xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/get_mic.c (revision 02e9120893770924227138ba49df1edb3896112a)
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   des_ctx = EVP_CIPHER_CTX_new();
100   if (des_ctx == NULL) {
101       memset (deskey, 0, sizeof(deskey));
102       memset (&schedule, 0, sizeof(schedule));
103       free (message_token->value);
104       message_token->value = NULL;
105       message_token->length = 0;
106       *minor_status = ENOMEM;
107       return GSS_S_FAILURE;
108   }
109 
110   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
111   /* sequence number */
112   krb5_auth_con_getlocalseqnumber (context,
113 				   ctx->auth_context,
114 				   &seq_number);
115 
116   p -= 16;			/* SND_SEQ */
117   p[0] = (seq_number >> 0)  & 0xFF;
118   p[1] = (seq_number >> 8)  & 0xFF;
119   p[2] = (seq_number >> 16) & 0xFF;
120   p[3] = (seq_number >> 24) & 0xFF;
121   memset (p + 4,
122 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
123 	  4);
124 
125   EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
126   EVP_Cipher(des_ctx, p, p, 8);
127   EVP_CIPHER_CTX_free(des_ctx);
128 
129   krb5_auth_con_setlocalseqnumber (context,
130 			       ctx->auth_context,
131 			       ++seq_number);
132   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
133 
134   memset (deskey, 0, sizeof(deskey));
135   memset (&schedule, 0, sizeof(schedule));
136 
137   *minor_status = 0;
138   return GSS_S_COMPLETE;
139 }
140 #endif
141 
142 static OM_uint32
143 mic_des3
144            (OM_uint32 * minor_status,
145             const gsskrb5_ctx ctx,
146 	    krb5_context context,
147             gss_qop_t qop_req,
148             const gss_buffer_t message_buffer,
149             gss_buffer_t message_token,
150 	    krb5_keyblock *key
151            )
152 {
153   u_char *p;
154   Checksum cksum;
155   u_char seq[8];
156 
157   int32_t seq_number;
158   size_t len, total_len;
159 
160   krb5_crypto crypto;
161   krb5_error_code kret;
162   krb5_data encdata;
163   char *tmp;
164   char ivec[8];
165 
166   _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
167 
168   message_token->length = total_len;
169   message_token->value  = malloc (total_len);
170   if (message_token->value == NULL) {
171       message_token->length = 0;
172       *minor_status = ENOMEM;
173       return GSS_S_FAILURE;
174   }
175 
176   p = _gsskrb5_make_header(message_token->value,
177 			      len,
178 			      "\x01\x01", /* TOK-ID */
179 			      GSS_KRB5_MECHANISM);
180 
181   memcpy (p, "\x04\x00", 2);	/* SGN_ALG = HMAC SHA1 DES3-KD */
182   p += 2;
183 
184   memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
185   p += 4;
186 
187   /* this should be done in parts */
188 
189   tmp = malloc (message_buffer->length + 8);
190   if (tmp == NULL) {
191       free (message_token->value);
192       message_token->value = NULL;
193       message_token->length = 0;
194       *minor_status = ENOMEM;
195       return GSS_S_FAILURE;
196   }
197   memcpy (tmp, p - 8, 8);
198   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
199 
200   kret = krb5_crypto_init(context, key, 0, &crypto);
201   if (kret) {
202       free (message_token->value);
203       message_token->value = NULL;
204       message_token->length = 0;
205       free (tmp);
206       *minor_status = kret;
207       return GSS_S_FAILURE;
208   }
209 
210   kret = krb5_create_checksum (context,
211 			       crypto,
212 			       KRB5_KU_USAGE_SIGN,
213 			       0,
214 			       tmp,
215 			       message_buffer->length + 8,
216 			       &cksum);
217   free (tmp);
218   krb5_crypto_destroy (context, crypto);
219   if (kret) {
220       free (message_token->value);
221       message_token->value = NULL;
222       message_token->length = 0;
223       *minor_status = kret;
224       return GSS_S_FAILURE;
225   }
226 
227   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
228 
229   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
230   /* sequence number */
231   krb5_auth_con_getlocalseqnumber (context,
232 			       ctx->auth_context,
233 			       &seq_number);
234 
235   seq[0] = (seq_number >> 0)  & 0xFF;
236   seq[1] = (seq_number >> 8)  & 0xFF;
237   seq[2] = (seq_number >> 16) & 0xFF;
238   seq[3] = (seq_number >> 24) & 0xFF;
239   memset (seq + 4,
240 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
241 	  4);
242 
243   kret = krb5_crypto_init(context, key,
244 			  ETYPE_DES3_CBC_NONE, &crypto);
245   if (kret) {
246       free (message_token->value);
247       message_token->value = NULL;
248       message_token->length = 0;
249       *minor_status = kret;
250       return GSS_S_FAILURE;
251   }
252 
253   if (ctx->more_flags & COMPAT_OLD_DES3)
254       memset(ivec, 0, 8);
255   else
256       memcpy(ivec, p + 8, 8);
257 
258   kret = krb5_encrypt_ivec (context,
259 			    crypto,
260 			    KRB5_KU_USAGE_SEQ,
261 			    seq, 8, &encdata, ivec);
262   krb5_crypto_destroy (context, crypto);
263   if (kret) {
264       free (message_token->value);
265       message_token->value = NULL;
266       message_token->length = 0;
267       *minor_status = kret;
268       return GSS_S_FAILURE;
269   }
270 
271   assert (encdata.length == 8);
272 
273   memcpy (p, encdata.data, encdata.length);
274   krb5_data_free (&encdata);
275 
276   krb5_auth_con_setlocalseqnumber (context,
277 			       ctx->auth_context,
278 			       ++seq_number);
279   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
280 
281   free_Checksum (&cksum);
282   *minor_status = 0;
283   return GSS_S_COMPLETE;
284 }
285 
286 OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic
287            (OM_uint32 * minor_status,
288             const gss_ctx_id_t context_handle,
289             gss_qop_t qop_req,
290             const gss_buffer_t message_buffer,
291             gss_buffer_t message_token
292            )
293 {
294   krb5_context context;
295   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
296   krb5_keyblock *key;
297   OM_uint32 ret;
298   krb5_keytype keytype;
299 
300   GSSAPI_KRB5_INIT (&context);
301 
302   if (ctx->more_flags & IS_CFX)
303       return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
304 			      message_buffer, message_token);
305 
306   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
307   ret = _gsskrb5i_get_token_key(ctx, context, &key);
308   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
309   if (ret) {
310       *minor_status = ret;
311       return GSS_S_FAILURE;
312   }
313   krb5_enctype_to_keytype (context, key->keytype, &keytype);
314 
315   switch (keytype) {
316   case KEYTYPE_DES :
317 #ifdef HEIM_WEAK_CRYPTO
318       ret = mic_des (minor_status, ctx, context, qop_req,
319 		     message_buffer, message_token, key);
320 #else
321       ret = GSS_S_FAILURE;
322 #endif
323       break;
324   case KEYTYPE_DES3 :
325       ret = mic_des3 (minor_status, ctx, context, qop_req,
326 		      message_buffer, message_token, key);
327       break;
328   case KEYTYPE_ARCFOUR:
329   case KEYTYPE_ARCFOUR_56:
330       ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
331 				     message_buffer, message_token, key);
332       break;
333   default :
334       abort();
335       break;
336   }
337   krb5_free_keyblock (context, key);
338   return ret;
339 }
340