xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/get_mic.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
1 /*
2  * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "gsskrb5_locl.h"
35 
36 #ifdef HEIM_WEAK_CRYPTO
37 
38 static OM_uint32
39 mic_des
40            (OM_uint32 * minor_status,
41             const gsskrb5_ctx ctx,
42 	    krb5_context context,
43             gss_qop_t qop_req,
44             const gss_buffer_t message_buffer,
45             gss_buffer_t message_token,
46 	    krb5_keyblock *key
47            )
48 {
49   u_char *p;
50   EVP_MD_CTX *md5;
51   u_char hash[16];
52   DES_key_schedule schedule;
53   EVP_CIPHER_CTX des_ctx;
54   DES_cblock deskey;
55   DES_cblock zero;
56   int32_t seq_number;
57   size_t len, total_len;
58 
59   _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
60 
61   message_token->length = total_len;
62   message_token->value  = malloc (total_len);
63   if (message_token->value == NULL) {
64     message_token->length = 0;
65     *minor_status = ENOMEM;
66     return GSS_S_FAILURE;
67   }
68 
69   p = _gsskrb5_make_header(message_token->value,
70 			      len,
71 			      "\x01\x01", /* TOK_ID */
72 			      GSS_KRB5_MECHANISM);
73 
74   memcpy (p, "\x00\x00", 2);	/* SGN_ALG = DES MAC MD5 */
75   p += 2;
76 
77   memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
78   p += 4;
79 
80   /* Fill in later (SND-SEQ) */
81   memset (p, 0, 16);
82   p += 16;
83 
84   /* checksum */
85   md5 = EVP_MD_CTX_create();
86   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
87   EVP_DigestUpdate(md5, p - 24, 8);
88   EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
89   EVP_DigestFinal_ex(md5, hash, NULL);
90   EVP_MD_CTX_destroy(md5);
91 
92   memset (&zero, 0, sizeof(zero));
93   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
94   DES_set_key_unchecked (&deskey, &schedule);
95   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
96 		 &schedule, &zero);
97   memcpy (p - 8, hash, 8);	/* SGN_CKSUM */
98 
99   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
100   /* sequence number */
101   krb5_auth_con_getlocalseqnumber (context,
102 				   ctx->auth_context,
103 				   &seq_number);
104 
105   p -= 16;			/* SND_SEQ */
106   p[0] = (seq_number >> 0)  & 0xFF;
107   p[1] = (seq_number >> 8)  & 0xFF;
108   p[2] = (seq_number >> 16) & 0xFF;
109   p[3] = (seq_number >> 24) & 0xFF;
110   memset (p + 4,
111 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
112 	  4);
113 
114   EVP_CIPHER_CTX_init(&des_ctx);
115   EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
116   EVP_Cipher(&des_ctx, p, p, 8);
117   EVP_CIPHER_CTX_cleanup(&des_ctx);
118 
119   krb5_auth_con_setlocalseqnumber (context,
120 			       ctx->auth_context,
121 			       ++seq_number);
122   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
123 
124   memset (deskey, 0, sizeof(deskey));
125   memset (&schedule, 0, sizeof(schedule));
126 
127   *minor_status = 0;
128   return GSS_S_COMPLETE;
129 }
130 #endif
131 
132 static OM_uint32
133 mic_des3
134            (OM_uint32 * minor_status,
135             const gsskrb5_ctx ctx,
136 	    krb5_context context,
137             gss_qop_t qop_req,
138             const gss_buffer_t message_buffer,
139             gss_buffer_t message_token,
140 	    krb5_keyblock *key
141            )
142 {
143   u_char *p;
144   Checksum cksum;
145   u_char seq[8];
146 
147   int32_t seq_number;
148   size_t len, total_len;
149 
150   krb5_crypto crypto;
151   krb5_error_code kret;
152   krb5_data encdata;
153   char *tmp;
154   char ivec[8];
155 
156   _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
157 
158   message_token->length = total_len;
159   message_token->value  = malloc (total_len);
160   if (message_token->value == NULL) {
161       message_token->length = 0;
162       *minor_status = ENOMEM;
163       return GSS_S_FAILURE;
164   }
165 
166   p = _gsskrb5_make_header(message_token->value,
167 			      len,
168 			      "\x01\x01", /* TOK-ID */
169 			      GSS_KRB5_MECHANISM);
170 
171   memcpy (p, "\x04\x00", 2);	/* SGN_ALG = HMAC SHA1 DES3-KD */
172   p += 2;
173 
174   memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
175   p += 4;
176 
177   /* this should be done in parts */
178 
179   tmp = malloc (message_buffer->length + 8);
180   if (tmp == NULL) {
181       free (message_token->value);
182       message_token->value = NULL;
183       message_token->length = 0;
184       *minor_status = ENOMEM;
185       return GSS_S_FAILURE;
186   }
187   memcpy (tmp, p - 8, 8);
188   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
189 
190   kret = krb5_crypto_init(context, key, 0, &crypto);
191   if (kret) {
192       free (message_token->value);
193       message_token->value = NULL;
194       message_token->length = 0;
195       free (tmp);
196       *minor_status = kret;
197       return GSS_S_FAILURE;
198   }
199 
200   kret = krb5_create_checksum (context,
201 			       crypto,
202 			       KRB5_KU_USAGE_SIGN,
203 			       0,
204 			       tmp,
205 			       message_buffer->length + 8,
206 			       &cksum);
207   free (tmp);
208   krb5_crypto_destroy (context, crypto);
209   if (kret) {
210       free (message_token->value);
211       message_token->value = NULL;
212       message_token->length = 0;
213       *minor_status = kret;
214       return GSS_S_FAILURE;
215   }
216 
217   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
218 
219   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
220   /* sequence number */
221   krb5_auth_con_getlocalseqnumber (context,
222 			       ctx->auth_context,
223 			       &seq_number);
224 
225   seq[0] = (seq_number >> 0)  & 0xFF;
226   seq[1] = (seq_number >> 8)  & 0xFF;
227   seq[2] = (seq_number >> 16) & 0xFF;
228   seq[3] = (seq_number >> 24) & 0xFF;
229   memset (seq + 4,
230 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
231 	  4);
232 
233   kret = krb5_crypto_init(context, key,
234 			  ETYPE_DES3_CBC_NONE, &crypto);
235   if (kret) {
236       free (message_token->value);
237       message_token->value = NULL;
238       message_token->length = 0;
239       *minor_status = kret;
240       return GSS_S_FAILURE;
241   }
242 
243   if (ctx->more_flags & COMPAT_OLD_DES3)
244       memset(ivec, 0, 8);
245   else
246       memcpy(ivec, p + 8, 8);
247 
248   kret = krb5_encrypt_ivec (context,
249 			    crypto,
250 			    KRB5_KU_USAGE_SEQ,
251 			    seq, 8, &encdata, ivec);
252   krb5_crypto_destroy (context, crypto);
253   if (kret) {
254       free (message_token->value);
255       message_token->value = NULL;
256       message_token->length = 0;
257       *minor_status = kret;
258       return GSS_S_FAILURE;
259   }
260 
261   assert (encdata.length == 8);
262 
263   memcpy (p, encdata.data, encdata.length);
264   krb5_data_free (&encdata);
265 
266   krb5_auth_con_setlocalseqnumber (context,
267 			       ctx->auth_context,
268 			       ++seq_number);
269   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
270 
271   free_Checksum (&cksum);
272   *minor_status = 0;
273   return GSS_S_COMPLETE;
274 }
275 
276 OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic
277            (OM_uint32 * minor_status,
278             const gss_ctx_id_t context_handle,
279             gss_qop_t qop_req,
280             const gss_buffer_t message_buffer,
281             gss_buffer_t message_token
282            )
283 {
284   krb5_context context;
285   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
286   krb5_keyblock *key;
287   OM_uint32 ret;
288   krb5_keytype keytype;
289 
290   GSSAPI_KRB5_INIT (&context);
291 
292   if (ctx->more_flags & IS_CFX)
293       return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
294 			      message_buffer, message_token);
295 
296   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
297   ret = _gsskrb5i_get_token_key(ctx, context, &key);
298   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
299   if (ret) {
300       *minor_status = ret;
301       return GSS_S_FAILURE;
302   }
303   krb5_enctype_to_keytype (context, key->keytype, &keytype);
304 
305   switch (keytype) {
306   case KEYTYPE_DES :
307 #ifdef HEIM_WEAK_CRYPTO
308       ret = mic_des (minor_status, ctx, context, qop_req,
309 		     message_buffer, message_token, key);
310 #else
311       ret = GSS_S_FAILURE;
312 #endif
313       break;
314   case KEYTYPE_DES3 :
315       ret = mic_des3 (minor_status, ctx, context, qop_req,
316 		      message_buffer, message_token, key);
317       break;
318   case KEYTYPE_ARCFOUR:
319   case KEYTYPE_ARCFOUR_56:
320       ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
321 				     message_buffer, message_token, key);
322       break;
323   default :
324       abort();
325       break;
326   }
327   krb5_free_keyblock (context, key);
328   return ret;
329 }
330