Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / heimdal / lib / gssapi / get_mic.c
1 /*
2  * Copyright (c) 1997 - 2001 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 "gssapi_locl.h"
35
36 RCSID("$Id: get_mic.c,v 1.19 2001/10/31 13:37:39 nectar Exp $");
37
38 static OM_uint32
39 mic_des
40            (OM_uint32 * minor_status,
41             const gss_ctx_id_t context_handle,
42             gss_qop_t qop_req,
43             const gss_buffer_t message_buffer,
44             gss_buffer_t message_token,
45             krb5_keyblock *key
46            )
47 {
48   u_char *p;
49   MD5_CTX md5;
50   u_char hash[16];
51   des_key_schedule schedule;
52   des_cblock deskey;
53   des_cblock zero;
54   int32_t seq_number;
55   size_t len, total_len;
56
57   gssapi_krb5_encap_length (22, &len, &total_len);
58
59   message_token->length = total_len;
60   message_token->value  = malloc (total_len);
61   if (message_token->value == NULL) {
62     *minor_status = ENOMEM;
63     return GSS_S_FAILURE;
64   }
65
66   p = gssapi_krb5_make_header(message_token->value,
67                               len,
68                               "\x01\x01"); /* TOK_ID */
69
70   memcpy (p, "\x00\x00", 2);    /* SGN_ALG = DES MAC MD5 */
71   p += 2;
72
73   memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
74   p += 4;
75
76   /* Fill in later (SND-SEQ) */
77   memset (p, 0, 16);
78   p += 16;
79
80   /* checksum */
81   MD5_Init (&md5);
82   MD5_Update (&md5, p - 24, 8);
83   MD5_Update (&md5, message_buffer->value, message_buffer->length);
84   MD5_Final (hash, &md5);
85
86   memset (&zero, 0, sizeof(zero));
87   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
88   des_set_key (&deskey, schedule);
89   des_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
90                  schedule, &zero);
91   memcpy (p - 8, hash, 8);      /* SGN_CKSUM */
92
93   /* sequence number */
94   krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
95                                context_handle->auth_context,
96                                &seq_number);
97
98   p -= 16;                      /* SND_SEQ */
99   p[0] = (seq_number >> 0)  & 0xFF;
100   p[1] = (seq_number >> 8)  & 0xFF;
101   p[2] = (seq_number >> 16) & 0xFF;
102   p[3] = (seq_number >> 24) & 0xFF;
103   memset (p + 4,
104           (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
105           4);
106
107   des_set_key (&deskey, schedule);
108   des_cbc_encrypt ((void *)p, (void *)p, 8,
109                    schedule, (des_cblock *)(p + 8), DES_ENCRYPT);
110
111   krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
112                                context_handle->auth_context,
113                                ++seq_number);
114   
115   memset (deskey, 0, sizeof(deskey));
116   memset (schedule, 0, sizeof(schedule));
117   
118   return GSS_S_COMPLETE;
119 }
120
121 static OM_uint32
122 mic_des3
123            (OM_uint32 * minor_status,
124             const gss_ctx_id_t context_handle,
125             gss_qop_t qop_req,
126             const gss_buffer_t message_buffer,
127             gss_buffer_t message_token,
128             krb5_keyblock *key
129            )
130 {
131   u_char *p;
132   Checksum cksum;
133   u_char seq[8];
134
135   int32_t seq_number;
136   size_t len, total_len;
137
138   krb5_crypto crypto;
139   krb5_error_code kret;
140   krb5_data encdata;
141   char *tmp;
142
143   gssapi_krb5_encap_length (36, &len, &total_len);
144
145   message_token->length = total_len;
146   message_token->value  = malloc (total_len);
147   if (message_token->value == NULL) {
148       *minor_status = ENOMEM;
149       return GSS_S_FAILURE;
150   }
151
152   p = gssapi_krb5_make_header(message_token->value,
153                               len,
154                               "\x01\x01"); /* TOK-ID */
155
156   memcpy (p, "\x04\x00", 2);    /* SGN_ALG = HMAC SHA1 DES3-KD */
157   p += 2;
158
159   memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
160   p += 4;
161
162   /* this should be done in parts */
163
164   tmp = malloc (message_buffer->length + 8);
165   if (tmp == NULL) {
166       free (message_token->value);
167       *minor_status = ENOMEM;
168       return GSS_S_FAILURE;
169   }
170   memcpy (tmp, p - 8, 8);
171   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
172
173   kret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
174   if (kret) {
175       free (message_token->value);
176       free (tmp);
177       gssapi_krb5_set_error_string ();
178       *minor_status = kret;
179       return GSS_S_FAILURE;
180   }
181
182   kret = krb5_create_checksum (gssapi_krb5_context,
183                                crypto,
184                                KRB5_KU_USAGE_SIGN,
185                                0,
186                                tmp,
187                                message_buffer->length + 8,
188                                &cksum);
189   free (tmp);
190   krb5_crypto_destroy (gssapi_krb5_context, crypto);
191   if (kret) {
192       free (message_token->value);
193       gssapi_krb5_set_error_string ();
194       *minor_status = kret;
195       return GSS_S_FAILURE;
196   }
197
198   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
199
200   /* sequence number */
201   krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
202                                context_handle->auth_context,
203                                &seq_number);
204
205   seq[0] = (seq_number >> 0)  & 0xFF;
206   seq[1] = (seq_number >> 8)  & 0xFF;
207   seq[2] = (seq_number >> 16) & 0xFF;
208   seq[3] = (seq_number >> 24) & 0xFF;
209   memset (seq + 4,
210           (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
211           4);
212
213   kret = krb5_crypto_init(gssapi_krb5_context, key,
214                           ETYPE_DES3_CBC_NONE, &crypto);
215   if (kret) {
216       free (message_token->value);
217       gssapi_krb5_set_error_string ();
218       *minor_status = kret;
219       return GSS_S_FAILURE;
220   }
221
222   kret = krb5_encrypt (gssapi_krb5_context,
223                        crypto,
224                        KRB5_KU_USAGE_SEQ,
225                        seq, 8, &encdata);
226   krb5_crypto_destroy (gssapi_krb5_context, crypto);
227   if (kret) {
228       free (message_token->value);
229       gssapi_krb5_set_error_string ();
230       *minor_status = kret;
231       return GSS_S_FAILURE;
232   }
233   
234   assert (encdata.length == 8);
235
236   memcpy (p, encdata.data, encdata.length);
237   krb5_data_free (&encdata);
238
239   krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
240                                context_handle->auth_context,
241                                ++seq_number);
242   
243   free_Checksum (&cksum);
244   return GSS_S_COMPLETE;
245 }
246
247 OM_uint32 gss_get_mic
248            (OM_uint32 * minor_status,
249             const gss_ctx_id_t context_handle,
250             gss_qop_t qop_req,
251             const gss_buffer_t message_buffer,
252             gss_buffer_t message_token
253            )
254 {
255   krb5_keyblock *key;
256   OM_uint32 ret;
257   krb5_keytype keytype;
258
259   ret = gss_krb5_get_localkey(context_handle, &key);
260   if (ret) {
261       gssapi_krb5_set_error_string ();
262       *minor_status = ret;
263       return GSS_S_FAILURE;
264   }
265   krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
266
267   switch (keytype) {
268   case KEYTYPE_DES :
269       ret = mic_des (minor_status, context_handle, qop_req,
270                      message_buffer, message_token, key);
271       break;
272   case KEYTYPE_DES3 :
273       ret = mic_des3 (minor_status, context_handle, qop_req,
274                       message_buffer, message_token, key);
275       break;
276   default :
277       *minor_status = KRB5_PROG_ETYPE_NOSUPP;
278       ret = GSS_S_FAILURE;
279       break;
280   }
281   krb5_free_keyblock (gssapi_krb5_context, key);
282   return ret;
283 }