Restructure Makefiles to accomodate multiple archs
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / gssapi / wrap.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 "gssapi_locl.h"
35
36 RCSID("$Id: wrap.c,v 1.21.2.1 2003/09/18 22:05:45 lha Exp $");
37
38 OM_uint32
39 gss_krb5_get_localkey(const gss_ctx_id_t context_handle,
40                        krb5_keyblock **key)
41 {
42     krb5_keyblock *skey;
43
44     krb5_auth_con_getlocalsubkey(gssapi_krb5_context,
45                                  context_handle->auth_context, 
46                                  &skey);
47     if(skey == NULL)
48         krb5_auth_con_getremotesubkey(gssapi_krb5_context,
49                                       context_handle->auth_context, 
50                                       &skey);
51     if(skey == NULL)
52         krb5_auth_con_getkey(gssapi_krb5_context,
53                              context_handle->auth_context, 
54                              &skey);
55     if(skey == NULL)
56         return GSS_S_FAILURE;
57     *key = skey;
58     return 0;
59 }
60
61 static OM_uint32
62 sub_wrap_size (
63             OM_uint32 req_output_size,
64             OM_uint32 * max_input_size,
65             int blocksize,
66             int extrasize
67            )
68 {
69   size_t len, total_len, padlength;
70   padlength = blocksize - (req_output_size % blocksize);
71   len = req_output_size + 8 + padlength + extrasize;
72   gssapi_krb5_encap_length(len, &len, &total_len);
73   *max_input_size = (OM_uint32)total_len;
74   return GSS_S_COMPLETE;
75 }
76
77 OM_uint32
78 gss_wrap_size_limit (
79             OM_uint32 * minor_status,
80             const gss_ctx_id_t context_handle,
81             int conf_req_flag,
82             gss_qop_t qop_req,
83             OM_uint32 req_output_size,
84             OM_uint32 * max_input_size
85            )
86 {
87   krb5_keyblock *key;
88   OM_uint32 ret;
89   krb5_keytype keytype;
90
91   ret = gss_krb5_get_localkey(context_handle, &key);
92   if (ret) {
93       gssapi_krb5_set_error_string ();
94       *minor_status = ret;
95       return GSS_S_FAILURE;
96   }
97   krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
98
99   switch (keytype) {
100   case KEYTYPE_DES :
101   case KEYTYPE_ARCFOUR:
102       ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
103       break;
104   case KEYTYPE_DES3 :
105       ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
106       break;
107   default :
108       *minor_status = KRB5_PROG_ETYPE_NOSUPP;
109       ret = GSS_S_FAILURE;
110       break;
111   }
112   krb5_free_keyblock (gssapi_krb5_context, key);
113   *minor_status = 0;
114   return ret;
115 }
116
117 static OM_uint32
118 wrap_des
119            (OM_uint32 * minor_status,
120             const gss_ctx_id_t context_handle,
121             int conf_req_flag,
122             gss_qop_t qop_req,
123             const gss_buffer_t input_message_buffer,
124             int * conf_state,
125             gss_buffer_t output_message_buffer,
126             krb5_keyblock *key
127            )
128 {
129   u_char *p;
130   MD5_CTX md5;
131   u_char hash[16];
132   des_key_schedule schedule;
133   des_cblock deskey;
134   des_cblock zero;
135   int i;
136   int32_t seq_number;
137   size_t len, total_len, padlength, datalen;
138
139   padlength = 8 - (input_message_buffer->length % 8);
140   datalen = input_message_buffer->length + padlength + 8;
141   len = datalen + 22;
142   gssapi_krb5_encap_length (len, &len, &total_len);
143
144   output_message_buffer->length = total_len;
145   output_message_buffer->value  = malloc (total_len);
146   if (output_message_buffer->value == NULL) {
147     *minor_status = ENOMEM;
148     return GSS_S_FAILURE;
149   }
150
151   p = gssapi_krb5_make_header(output_message_buffer->value,
152                               len,
153                               "\x02\x01"); /* TOK_ID */
154
155   /* SGN_ALG */
156   memcpy (p, "\x00\x00", 2);
157   p += 2;
158   /* SEAL_ALG */
159   if(conf_req_flag)
160       memcpy (p, "\x00\x00", 2);
161   else
162       memcpy (p, "\xff\xff", 2);
163   p += 2;
164   /* Filler */
165   memcpy (p, "\xff\xff", 2);
166   p += 2;
167
168   /* fill in later */
169   memset (p, 0, 16);
170   p += 16;
171
172   /* confounder + data + pad */
173   krb5_generate_random_block(p, 8);
174   memcpy (p + 8, input_message_buffer->value,
175           input_message_buffer->length);
176   memset (p + 8 + input_message_buffer->length, padlength, padlength);
177
178   /* checksum */
179   MD5_Init (&md5);
180   MD5_Update (&md5, p - 24, 8);
181   MD5_Update (&md5, p, datalen);
182   MD5_Final (hash, &md5);
183
184   memset (&zero, 0, sizeof(zero));
185   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
186   des_set_key (&deskey, schedule);
187   des_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
188                  schedule, &zero);
189   memcpy (p - 8, hash, 8);
190
191   /* sequence number */
192   krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
193                                context_handle->auth_context,
194                                &seq_number);
195
196   p -= 16;
197   p[0] = (seq_number >> 0)  & 0xFF;
198   p[1] = (seq_number >> 8)  & 0xFF;
199   p[2] = (seq_number >> 16) & 0xFF;
200   p[3] = (seq_number >> 24) & 0xFF;
201   memset (p + 4,
202           (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
203           4);
204
205   des_set_key (&deskey, schedule);
206   des_cbc_encrypt ((void *)p, (void *)p, 8,
207                    schedule, (des_cblock *)(p + 8), DES_ENCRYPT);
208
209   krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
210                                context_handle->auth_context,
211                                ++seq_number);
212
213   /* encrypt the data */
214   p += 16;
215
216   if(conf_req_flag) {
217       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
218
219       for (i = 0; i < sizeof(deskey); ++i)
220           deskey[i] ^= 0xf0;
221       des_set_key (&deskey, schedule);
222       memset (&zero, 0, sizeof(zero));
223       des_cbc_encrypt ((void *)p,
224                        (void *)p,
225                        datalen,
226                        schedule,
227                        &zero,
228                        DES_ENCRYPT);
229       
230       memset (deskey, 0, sizeof(deskey));
231       memset (schedule, 0, sizeof(schedule));
232   }
233   if(conf_state != NULL)
234       *conf_state = conf_req_flag;
235   *minor_status = 0;
236   return GSS_S_COMPLETE;
237 }
238
239 static OM_uint32
240 wrap_des3
241            (OM_uint32 * minor_status,
242             const gss_ctx_id_t context_handle,
243             int conf_req_flag,
244             gss_qop_t qop_req,
245             const gss_buffer_t input_message_buffer,
246             int * conf_state,
247             gss_buffer_t output_message_buffer,
248             krb5_keyblock *key
249            )
250 {
251   u_char *p;
252   u_char seq[8];
253   int32_t seq_number;
254   size_t len, total_len, padlength, datalen;
255   u_int32_t ret;
256   krb5_crypto crypto;
257   Checksum cksum;
258   krb5_data encdata;
259
260   padlength = 8 - (input_message_buffer->length % 8);
261   datalen = input_message_buffer->length + padlength + 8;
262   len = datalen + 34;
263   gssapi_krb5_encap_length (len, &len, &total_len);
264
265   output_message_buffer->length = total_len;
266   output_message_buffer->value  = malloc (total_len);
267   if (output_message_buffer->value == NULL) {
268     *minor_status = ENOMEM;
269     return GSS_S_FAILURE;
270   }
271
272   p = gssapi_krb5_make_header(output_message_buffer->value,
273                               len,
274                               "\x02\x01"); /* TOK_ID */
275
276   /* SGN_ALG */
277   memcpy (p, "\x04\x00", 2);    /* HMAC SHA1 DES3-KD */
278   p += 2;
279   /* SEAL_ALG */
280   if(conf_req_flag)
281       memcpy (p, "\x02\x00", 2); /* DES3-KD */
282   else
283       memcpy (p, "\xff\xff", 2);
284   p += 2;
285   /* Filler */
286   memcpy (p, "\xff\xff", 2);
287   p += 2;
288
289   /* calculate checksum (the above + confounder + data + pad) */
290
291   memcpy (p + 20, p - 8, 8);
292   krb5_generate_random_block(p + 28, 8);
293   memcpy (p + 28 + 8, input_message_buffer->value,
294           input_message_buffer->length);
295   memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
296
297   ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
298   if (ret) {
299       gssapi_krb5_set_error_string ();
300       free (output_message_buffer->value);
301       *minor_status = ret;
302       return GSS_S_FAILURE;
303   }
304
305   ret = krb5_create_checksum (gssapi_krb5_context,
306                               crypto,
307                               KRB5_KU_USAGE_SIGN,
308                               0,
309                               p + 20,
310                               datalen + 8,
311                               &cksum);
312   krb5_crypto_destroy (gssapi_krb5_context, crypto);
313   if (ret) {
314       gssapi_krb5_set_error_string ();
315       free (output_message_buffer->value);
316       *minor_status = ret;
317       return GSS_S_FAILURE;
318   }
319
320   /* zero out SND_SEQ + SGN_CKSUM in case */
321   memset (p, 0, 28);
322
323   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
324   free_Checksum (&cksum);
325
326   /* sequence number */
327   krb5_auth_con_getlocalseqnumber (gssapi_krb5_context,
328                                context_handle->auth_context,
329                                &seq_number);
330
331   seq[0] = (seq_number >> 0)  & 0xFF;
332   seq[1] = (seq_number >> 8)  & 0xFF;
333   seq[2] = (seq_number >> 16) & 0xFF;
334   seq[3] = (seq_number >> 24) & 0xFF;
335   memset (seq + 4,
336           (context_handle->more_flags & LOCAL) ? 0 : 0xFF,
337           4);
338
339
340   ret = krb5_crypto_init(gssapi_krb5_context, key, ETYPE_DES3_CBC_NONE,
341                          &crypto);
342   if (ret) {
343       free (output_message_buffer->value);
344       *minor_status = ret;
345       return GSS_S_FAILURE;
346   }
347
348   {
349       des_cblock ivec;
350
351       memcpy (&ivec, p + 8, 8);
352       ret = krb5_encrypt_ivec (gssapi_krb5_context,
353                                crypto,
354                                KRB5_KU_USAGE_SEQ,
355                                seq, 8, &encdata,
356                                &ivec);
357   }
358   krb5_crypto_destroy (gssapi_krb5_context, crypto);
359   if (ret) {
360       gssapi_krb5_set_error_string ();
361       free (output_message_buffer->value);
362       *minor_status = ret;
363       return GSS_S_FAILURE;
364   }
365   
366   assert (encdata.length == 8);
367
368   memcpy (p, encdata.data, encdata.length);
369   krb5_data_free (&encdata);
370
371   krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
372                                context_handle->auth_context,
373                                ++seq_number);
374
375   /* encrypt the data */
376   p += 28;
377
378   if(conf_req_flag) {
379       krb5_data tmp;
380
381       ret = krb5_crypto_init(gssapi_krb5_context, key,
382                              ETYPE_DES3_CBC_NONE, &crypto);
383       if (ret) {
384           gssapi_krb5_set_error_string ();
385           free (output_message_buffer->value);
386           *minor_status = ret;
387           return GSS_S_FAILURE;
388       }
389       ret = krb5_encrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL,
390                          p, datalen, &tmp);
391       krb5_crypto_destroy(gssapi_krb5_context, crypto);
392       if (ret) {
393           gssapi_krb5_set_error_string ();
394           free (output_message_buffer->value);
395           *minor_status = ret;
396           return GSS_S_FAILURE;
397       }
398       assert (tmp.length == datalen);
399
400       memcpy (p, tmp.data, datalen);
401       krb5_data_free(&tmp);
402   }
403   if(conf_state != NULL)
404       *conf_state = conf_req_flag;
405   *minor_status = 0;
406   return GSS_S_COMPLETE;
407 }
408
409 OM_uint32 gss_wrap
410            (OM_uint32 * minor_status,
411             const gss_ctx_id_t context_handle,
412             int conf_req_flag,
413             gss_qop_t qop_req,
414             const gss_buffer_t input_message_buffer,
415             int * conf_state,
416             gss_buffer_t output_message_buffer
417            )
418 {
419   krb5_keyblock *key;
420   OM_uint32 ret;
421   krb5_keytype keytype;
422
423   ret = gss_krb5_get_localkey(context_handle, &key);
424   if (ret) {
425       gssapi_krb5_set_error_string ();
426       *minor_status = ret;
427       return GSS_S_FAILURE;
428   }
429   krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
430
431   switch (keytype) {
432   case KEYTYPE_DES :
433       ret = wrap_des (minor_status, context_handle, conf_req_flag,
434                       qop_req, input_message_buffer, conf_state,
435                       output_message_buffer, key);
436       break;
437   case KEYTYPE_DES3 :
438       ret = wrap_des3 (minor_status, context_handle, conf_req_flag,
439                        qop_req, input_message_buffer, conf_state,
440                        output_message_buffer, key);
441       break;
442   case KEYTYPE_ARCFOUR:
443       ret = _gssapi_wrap_arcfour (minor_status, context_handle, conf_req_flag,
444                                   qop_req, input_message_buffer, conf_state,
445                                   output_message_buffer, key);
446       break;
447   default :
448       *minor_status = KRB5_PROG_ETYPE_NOSUPP;
449       ret = GSS_S_FAILURE;
450       break;
451   }
452   krb5_free_keyblock (gssapi_krb5_context, key);
453   return ret;
454 }