s4:heimdal: import lorikeet-heimdal-200907152325 (commit 2bef9cd5378c01e9c2a74d622176...
[samba.git] / source4 / heimdal / lib / gssapi / krb5 / get_mic.c
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 static OM_uint32
37 mic_des
38            (OM_uint32 * minor_status,
39             const gsskrb5_ctx ctx,
40             krb5_context context,
41             gss_qop_t qop_req,
42             const gss_buffer_t message_buffer,
43             gss_buffer_t message_token,
44             krb5_keyblock *key
45            )
46 {
47   u_char *p;
48   MD5_CTX md5;
49   u_char hash[16];
50   DES_key_schedule schedule;
51   DES_cblock deskey;
52   DES_cblock zero;
53   int32_t seq_number;
54   size_t len, total_len;
55
56   _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
57
58   message_token->length = total_len;
59   message_token->value  = malloc (total_len);
60   if (message_token->value == NULL) {
61     message_token->length = 0;
62     *minor_status = ENOMEM;
63     return GSS_S_FAILURE;
64   }
65
66   p = _gsskrb5_make_header(message_token->value,
67                               len,
68                               "\x01\x01", /* TOK_ID */
69                               GSS_KRB5_MECHANISM);
70
71   memcpy (p, "\x00\x00", 2);    /* SGN_ALG = DES MAC MD5 */
72   p += 2;
73
74   memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
75   p += 4;
76
77   /* Fill in later (SND-SEQ) */
78   memset (p, 0, 16);
79   p += 16;
80
81   /* checksum */
82   MD5_Init (&md5);
83   MD5_Update (&md5, p - 24, 8);
84   MD5_Update (&md5, message_buffer->value, message_buffer->length);
85   MD5_Final (hash, &md5);
86
87   memset (&zero, 0, sizeof(zero));
88   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
89   DES_set_key_unchecked (&deskey, &schedule);
90   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
91                  &schedule, &zero);
92   memcpy (p - 8, hash, 8);      /* SGN_CKSUM */
93
94   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
95   /* sequence number */
96   krb5_auth_con_getlocalseqnumber (context,
97                                    ctx->auth_context,
98                                    &seq_number);
99
100   p -= 16;                      /* SND_SEQ */
101   p[0] = (seq_number >> 0)  & 0xFF;
102   p[1] = (seq_number >> 8)  & 0xFF;
103   p[2] = (seq_number >> 16) & 0xFF;
104   p[3] = (seq_number >> 24) & 0xFF;
105   memset (p + 4,
106           (ctx->more_flags & LOCAL) ? 0 : 0xFF,
107           4);
108
109   DES_set_key_unchecked (&deskey, &schedule);
110   DES_cbc_encrypt ((void *)p, (void *)p, 8,
111                    &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
112
113   krb5_auth_con_setlocalseqnumber (context,
114                                ctx->auth_context,
115                                ++seq_number);
116   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
117
118   memset (deskey, 0, sizeof(deskey));
119   memset (&schedule, 0, sizeof(schedule));
120
121   *minor_status = 0;
122   return GSS_S_COMPLETE;
123 }
124
125 static OM_uint32
126 mic_des3
127            (OM_uint32 * minor_status,
128             const gsskrb5_ctx ctx,
129             krb5_context context,
130             gss_qop_t qop_req,
131             const gss_buffer_t message_buffer,
132             gss_buffer_t message_token,
133             krb5_keyblock *key
134            )
135 {
136   u_char *p;
137   Checksum cksum;
138   u_char seq[8];
139
140   int32_t seq_number;
141   size_t len, total_len;
142
143   krb5_crypto crypto;
144   krb5_error_code kret;
145   krb5_data encdata;
146   char *tmp;
147   char ivec[8];
148
149   _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
150
151   message_token->length = total_len;
152   message_token->value  = malloc (total_len);
153   if (message_token->value == NULL) {
154       message_token->length = 0;
155       *minor_status = ENOMEM;
156       return GSS_S_FAILURE;
157   }
158
159   p = _gsskrb5_make_header(message_token->value,
160                               len,
161                               "\x01\x01", /* TOK-ID */
162                               GSS_KRB5_MECHANISM);
163
164   memcpy (p, "\x04\x00", 2);    /* SGN_ALG = HMAC SHA1 DES3-KD */
165   p += 2;
166
167   memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
168   p += 4;
169
170   /* this should be done in parts */
171
172   tmp = malloc (message_buffer->length + 8);
173   if (tmp == NULL) {
174       free (message_token->value);
175       message_token->value = NULL;
176       message_token->length = 0;
177       *minor_status = ENOMEM;
178       return GSS_S_FAILURE;
179   }
180   memcpy (tmp, p - 8, 8);
181   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
182
183   kret = krb5_crypto_init(context, key, 0, &crypto);
184   if (kret) {
185       free (message_token->value);
186       message_token->value = NULL;
187       message_token->length = 0;
188       free (tmp);
189       *minor_status = kret;
190       return GSS_S_FAILURE;
191   }
192
193   kret = krb5_create_checksum (context,
194                                crypto,
195                                KRB5_KU_USAGE_SIGN,
196                                0,
197                                tmp,
198                                message_buffer->length + 8,
199                                &cksum);
200   free (tmp);
201   krb5_crypto_destroy (context, crypto);
202   if (kret) {
203       free (message_token->value);
204       message_token->value = NULL;
205       message_token->length = 0;
206       *minor_status = kret;
207       return GSS_S_FAILURE;
208   }
209
210   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
211
212   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
213   /* sequence number */
214   krb5_auth_con_getlocalseqnumber (context,
215                                ctx->auth_context,
216                                &seq_number);
217
218   seq[0] = (seq_number >> 0)  & 0xFF;
219   seq[1] = (seq_number >> 8)  & 0xFF;
220   seq[2] = (seq_number >> 16) & 0xFF;
221   seq[3] = (seq_number >> 24) & 0xFF;
222   memset (seq + 4,
223           (ctx->more_flags & LOCAL) ? 0 : 0xFF,
224           4);
225
226   kret = krb5_crypto_init(context, key,
227                           ETYPE_DES3_CBC_NONE, &crypto);
228   if (kret) {
229       free (message_token->value);
230       message_token->value = NULL;
231       message_token->length = 0;
232       *minor_status = kret;
233       return GSS_S_FAILURE;
234   }
235
236   if (ctx->more_flags & COMPAT_OLD_DES3)
237       memset(ivec, 0, 8);
238   else
239       memcpy(ivec, p + 8, 8);
240
241   kret = krb5_encrypt_ivec (context,
242                             crypto,
243                             KRB5_KU_USAGE_SEQ,
244                             seq, 8, &encdata, ivec);
245   krb5_crypto_destroy (context, crypto);
246   if (kret) {
247       free (message_token->value);
248       message_token->value = NULL;
249       message_token->length = 0;
250       *minor_status = kret;
251       return GSS_S_FAILURE;
252   }
253
254   assert (encdata.length == 8);
255
256   memcpy (p, encdata.data, encdata.length);
257   krb5_data_free (&encdata);
258
259   krb5_auth_con_setlocalseqnumber (context,
260                                ctx->auth_context,
261                                ++seq_number);
262   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
263
264   free_Checksum (&cksum);
265   *minor_status = 0;
266   return GSS_S_COMPLETE;
267 }
268
269 OM_uint32 _gsskrb5_get_mic
270            (OM_uint32 * minor_status,
271             const gss_ctx_id_t context_handle,
272             gss_qop_t qop_req,
273             const gss_buffer_t message_buffer,
274             gss_buffer_t message_token
275            )
276 {
277   krb5_context context;
278   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
279   krb5_keyblock *key;
280   OM_uint32 ret;
281   krb5_keytype keytype;
282
283   GSSAPI_KRB5_INIT (&context);
284
285   if (ctx->more_flags & IS_CFX)
286       return _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
287                               message_buffer, message_token);
288
289   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
290   ret = _gsskrb5i_get_token_key(ctx, context, &key);
291   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
292   if (ret) {
293       *minor_status = ret;
294       return GSS_S_FAILURE;
295   }
296   krb5_enctype_to_keytype (context, key->keytype, &keytype);
297
298   switch (keytype) {
299   case KEYTYPE_DES :
300       ret = mic_des (minor_status, ctx, context, qop_req,
301                      message_buffer, message_token, key);
302       break;
303   case KEYTYPE_DES3 :
304       ret = mic_des3 (minor_status, ctx, context, qop_req,
305                       message_buffer, message_token, key);
306       break;
307   case KEYTYPE_ARCFOUR:
308   case KEYTYPE_ARCFOUR_56:
309       ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
310                                      message_buffer, message_token, key);
311       break;
312   default :
313       abort();
314       break;
315   }
316   krb5_free_keyblock (context, key);
317   return ret;
318 }