Use gssalloc memory management where appropriate
[krb5.git] / src / lib / gssapi / krb5 / k5unseal.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 2001, 2007 by the Massachusetts Institute of Technology.
4  * Copyright 1993 by OpenVision Technologies, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software
7  * and its documentation for any purpose is hereby granted without fee,
8  * provided that the above copyright notice appears in all copies and
9  * that both that copyright notice and this permission notice appear in
10  * supporting documentation, and that the name of OpenVision not be used
11  * in advertising or publicity pertaining to distribution of the software
12  * without specific, written prior permission. OpenVision makes no
13  * representations about the suitability of this software for any
14  * purpose.  It is provided "as is" without express or implied warranty.
15  *
16  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 /*
26  * Copyright (C) 1998 by the FundsXpress, INC.
27  *
28  * All rights reserved.
29  *
30  * Export of this software from the United States of America may require
31  * a specific license from the United States Government.  It is the
32  * responsibility of any person or organization contemplating export to
33  * obtain such a license before exporting.
34  *
35  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
36  * distribute this software and its documentation for any purpose and
37  * without fee is hereby granted, provided that the above copyright
38  * notice appear in all copies and that both that copyright notice and
39  * this permission notice appear in supporting documentation, and that
40  * the name of FundsXpress. not be used in advertising or publicity pertaining
41  * to distribution of the software without specific, written prior
42  * permission.  FundsXpress makes no representations about the suitability of
43  * this software for any purpose.  It is provided "as is" without express
44  * or implied warranty.
45  *
46  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
47  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
48  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
49  */
50
51 #include "gssapiP_krb5.h"
52 #ifdef HAVE_MEMORY_H
53 #include <memory.h>
54 #endif
55 #include <assert.h>
56
57 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
58    conf_state is only valid if SEAL. */
59
60 static OM_uint32
61 kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
62              conf_state, qop_state, toktype)
63     krb5_context context;
64     OM_uint32 *minor_status;
65     krb5_gss_ctx_id_rec *ctx;
66     unsigned char *ptr;
67     int bodysize;
68     gss_buffer_t message_buffer;
69     int *conf_state;
70     int *qop_state;
71     int toktype;
72 {
73     krb5_error_code code;
74     int conflen = 0;
75     int signalg;
76     int sealalg;
77     gss_buffer_desc token;
78     krb5_checksum cksum;
79     krb5_checksum md5cksum;
80     krb5_data plaind;
81     char *data_ptr;
82     unsigned char *plain;
83     unsigned int cksum_len = 0;
84     size_t plainlen;
85     int direction;
86     krb5_ui_4 seqnum;
87     OM_uint32 retval;
88     size_t sumlen;
89     krb5_keyusage sign_usage = KG_USAGE_SIGN;
90
91     if (toktype == KG_TOK_SEAL_MSG) {
92         message_buffer->length = 0;
93         message_buffer->value = NULL;
94     }
95
96     /* get the sign and seal algorithms */
97
98     signalg = ptr[0] + (ptr[1]<<8);
99     sealalg = ptr[2] + (ptr[3]<<8);
100
101     /* Sanity checks */
102
103     if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
104         *minor_status = 0;
105         return GSS_S_DEFECTIVE_TOKEN;
106     }
107
108     if ((toktype != KG_TOK_SEAL_MSG) &&
109         (sealalg != 0xffff)) {
110         *minor_status = 0;
111         return GSS_S_DEFECTIVE_TOKEN;
112     }
113
114     /* in the current spec, there is only one valid seal algorithm per
115        key type, so a simple comparison is ok */
116
117     if ((toktype == KG_TOK_SEAL_MSG) &&
118         !((sealalg == 0xffff) ||
119           (sealalg == ctx->sealalg))) {
120         *minor_status = 0;
121         return GSS_S_DEFECTIVE_TOKEN;
122     }
123
124     /* there are several mappings of seal algorithms to sign algorithms,
125        but few enough that we can try them all. */
126
127     if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
128         (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
129         (ctx->sealalg == SEAL_ALG_DES3KD &&
130          signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
131         (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
132          signalg != SGN_ALG_HMAC_MD5)) {
133         *minor_status = 0;
134         return GSS_S_DEFECTIVE_TOKEN;
135     }
136
137     switch (signalg) {
138     case SGN_ALG_DES_MAC_MD5:
139     case SGN_ALG_MD2_5:
140     case SGN_ALG_HMAC_MD5:
141         cksum_len = 8;
142         if (toktype != KG_TOK_SEAL_MSG)
143             sign_usage = 15;
144         break;
145     case SGN_ALG_3:
146         cksum_len = 16;
147         break;
148     case SGN_ALG_HMAC_SHA1_DES3_KD:
149         cksum_len = 20;
150         break;
151     default:
152         *minor_status = 0;
153         return GSS_S_DEFECTIVE_TOKEN;
154     }
155
156     /* get the token parameters */
157
158     if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
159                                &seqnum))) {
160         *minor_status = code;
161         return(GSS_S_BAD_SIG);
162     }
163
164     /* decode the message, if SEAL */
165
166     if (toktype == KG_TOK_SEAL_MSG) {
167         size_t tmsglen = bodysize-(14+cksum_len);
168         if (sealalg != 0xffff) {
169             if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
170                 *minor_status = ENOMEM;
171                 return(GSS_S_FAILURE);
172             }
173             if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
174                 unsigned char bigend_seqnum[4];
175                 krb5_keyblock *enc_key;
176                 int i;
177                 store_32_be(seqnum, bigend_seqnum);
178                 code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
179                 if (code)
180                 {
181                     xfree(plain);
182                     *minor_status = code;
183                     return(GSS_S_FAILURE);
184                 }
185
186                 assert (enc_key->length == 16);
187                 for (i = 0; i <= 15; i++)
188                     ((char *) enc_key->contents)[i] ^=0xf0;
189                 code = kg_arcfour_docrypt (enc_key, 0,
190                                            &bigend_seqnum[0], 4,
191                                            ptr+14+cksum_len, tmsglen,
192                                            plain);
193                 krb5_free_keyblock (context, enc_key);
194             } else {
195                 code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
196                                   ptr+14+cksum_len, plain, tmsglen);
197             }
198             if (code) {
199                 xfree(plain);
200                 *minor_status = code;
201                 return(GSS_S_FAILURE);
202             }
203         } else {
204             plain = ptr+14+cksum_len;
205         }
206
207         plainlen = tmsglen;
208
209         if ((sealalg == 0xffff) && ctx->big_endian) {
210             token.length = tmsglen;
211         } else {
212             conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
213             token.length = tmsglen - conflen - plain[tmsglen-1];
214         }
215
216         if (token.length) {
217             if ((token.value = (void *) gssalloc_malloc(token.length)) == NULL) {
218                 if (sealalg != 0xffff)
219                     xfree(plain);
220                 *minor_status = ENOMEM;
221                 return(GSS_S_FAILURE);
222             }
223             memcpy(token.value, plain+conflen, token.length);
224         } else {
225             token.value = NULL;
226         }
227     } else if (toktype == KG_TOK_SIGN_MSG) {
228         token = *message_buffer;
229         plain = token.value;
230         plainlen = token.length;
231     } else {
232         token.length = 0;
233         token.value = NULL;
234         plain = token.value;
235         plainlen = token.length;
236     }
237
238     /* compute the checksum of the message */
239
240     /* initialize the the cksum */
241     switch (signalg) {
242     case SGN_ALG_DES_MAC_MD5:
243     case SGN_ALG_MD2_5:
244     case SGN_ALG_DES_MAC:
245     case SGN_ALG_3:
246         md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
247         break;
248     case SGN_ALG_HMAC_MD5:
249         md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
250         break;
251     case SGN_ALG_HMAC_SHA1_DES3_KD:
252         md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
253         break;
254     default:
255         abort ();
256     }
257
258     code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
259     if (code)
260         return(code);
261     md5cksum.length = sumlen;
262
263     switch (signalg) {
264     case SGN_ALG_DES_MAC_MD5:
265     case SGN_ALG_3:
266         /* compute the checksum of the message */
267
268         /* 8 = bytes of token body to be checksummed according to spec */
269
270         if (! (data_ptr = (void *)
271                xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
272             if (sealalg != 0xffff)
273                 xfree(plain);
274             if (toktype == KG_TOK_SEAL_MSG)
275                 gssalloc_free(token.value);
276             *minor_status = ENOMEM;
277             return(GSS_S_FAILURE);
278         }
279
280         (void) memcpy(data_ptr, ptr-2, 8);
281
282         if (ctx->big_endian)
283             (void) memcpy(data_ptr+8, token.value, token.length);
284         else
285             (void) memcpy(data_ptr+8, plain, plainlen);
286
287         plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
288         plaind.data = data_ptr;
289         code = krb5_k_make_checksum(context, md5cksum.checksum_type,
290                                     ctx->seq, sign_usage,
291                                     &plaind, &md5cksum);
292         xfree(data_ptr);
293
294         if (code) {
295             if (toktype == KG_TOK_SEAL_MSG)
296                 gssalloc_free(token.value);
297             *minor_status = code;
298             return(GSS_S_FAILURE);
299         }
300
301         code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
302                                   (g_OID_equal(ctx->mech_used,
303                                                gss_mech_krb5_old) ?
304                                    ctx->seq->keyblock.contents : NULL),
305                                   md5cksum.contents, 16);
306         if (code) {
307             krb5_free_checksum_contents(context, &md5cksum);
308             if (toktype == KG_TOK_SEAL_MSG)
309                 gssalloc_free(token.value);
310             *minor_status = code;
311             return GSS_S_FAILURE;
312         }
313
314         if (signalg == 0)
315             cksum.length = 8;
316         else
317             cksum.length = 16;
318         cksum.contents = md5cksum.contents + 16 - cksum.length;
319
320         code = memcmp(cksum.contents, ptr+14, cksum.length);
321         break;
322
323     case SGN_ALG_MD2_5:
324         if (!ctx->seed_init &&
325             (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
326             krb5_free_checksum_contents(context, &md5cksum);
327             if (sealalg != 0xffff)
328                 xfree(plain);
329             if (toktype == KG_TOK_SEAL_MSG)
330                 gssalloc_free(token.value);
331             *minor_status = code;
332             return GSS_S_FAILURE;
333         }
334
335         if (! (data_ptr = (void *)
336                xmalloc(sizeof(ctx->seed) + 8 +
337                        (ctx->big_endian ? token.length : plainlen)))) {
338             krb5_free_checksum_contents(context, &md5cksum);
339             if (sealalg == 0)
340                 xfree(plain);
341             if (toktype == KG_TOK_SEAL_MSG)
342                 gssalloc_free(token.value);
343             *minor_status = ENOMEM;
344             return(GSS_S_FAILURE);
345         }
346         (void) memcpy(data_ptr, ptr-2, 8);
347         (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
348         if (ctx->big_endian)
349             (void) memcpy(data_ptr+8+sizeof(ctx->seed),
350                           token.value, token.length);
351         else
352             (void) memcpy(data_ptr+8+sizeof(ctx->seed),
353                           plain, plainlen);
354         plaind.length = 8 + sizeof(ctx->seed) +
355             (ctx->big_endian ? token.length : plainlen);
356         plaind.data = data_ptr;
357         krb5_free_checksum_contents(context, &md5cksum);
358         code = krb5_k_make_checksum(context, md5cksum.checksum_type,
359                                     ctx->seq, sign_usage,
360                                     &plaind, &md5cksum);
361         xfree(data_ptr);
362
363         if (code) {
364             if (sealalg == 0)
365                 xfree(plain);
366             if (toktype == KG_TOK_SEAL_MSG)
367                 gssalloc_free(token.value);
368             *minor_status = code;
369             return(GSS_S_FAILURE);
370         }
371
372         code = memcmp(md5cksum.contents, ptr+14, 8);
373         /* Falls through to defective-token??  */
374
375     default:
376         *minor_status = 0;
377         return(GSS_S_DEFECTIVE_TOKEN);
378
379     case SGN_ALG_HMAC_SHA1_DES3_KD:
380     case SGN_ALG_HMAC_MD5:
381         /* compute the checksum of the message */
382
383         /* 8 = bytes of token body to be checksummed according to spec */
384
385         if (! (data_ptr = (void *)
386                xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
387             if (sealalg != 0xffff)
388                 xfree(plain);
389             if (toktype == KG_TOK_SEAL_MSG)
390                 gssalloc_free(token.value);
391             *minor_status = ENOMEM;
392             return(GSS_S_FAILURE);
393         }
394
395         (void) memcpy(data_ptr, ptr-2, 8);
396
397         if (ctx->big_endian)
398             (void) memcpy(data_ptr+8, token.value, token.length);
399         else
400             (void) memcpy(data_ptr+8, plain, plainlen);
401
402         plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
403         plaind.data = data_ptr;
404         code = krb5_k_make_checksum(context, md5cksum.checksum_type,
405                                     ctx->seq, sign_usage,
406                                     &plaind, &md5cksum);
407         xfree(data_ptr);
408
409         if (code) {
410             if (toktype == KG_TOK_SEAL_MSG)
411                 gssalloc_free(token.value);
412             *minor_status = code;
413             return(GSS_S_FAILURE);
414         }
415
416         code = memcmp(md5cksum.contents, ptr+14, cksum_len);
417         break;
418     }
419
420     krb5_free_checksum_contents(context, &md5cksum);
421     if (sealalg != 0xffff)
422         xfree(plain);
423
424     /* compare the computed checksum against the transmitted checksum */
425
426     if (code) {
427         if (toktype == KG_TOK_SEAL_MSG)
428             gssalloc_free(token.value);
429         *minor_status = 0;
430         return(GSS_S_BAD_SIG);
431     }
432
433
434     /* it got through unscathed.  Make sure the context is unexpired */
435
436     if (toktype == KG_TOK_SEAL_MSG)
437         *message_buffer = token;
438
439     if (conf_state)
440         *conf_state = (sealalg != 0xffff);
441
442     if (qop_state)
443         *qop_state = GSS_C_QOP_DEFAULT;
444
445     /* do sequencing checks */
446
447     if ((ctx->initiate && direction != 0xff) ||
448         (!ctx->initiate && direction != 0)) {
449         if (toktype == KG_TOK_SEAL_MSG) {
450             gssalloc_free(token.value);
451             message_buffer->value = NULL;
452             message_buffer->length = 0;
453         }
454         *minor_status = (OM_uint32)G_BAD_DIRECTION;
455         return(GSS_S_BAD_SIG);
456     }
457
458     retval = g_order_check(&(ctx->seqstate), (gssint_uint64)seqnum);
459
460     /* success or ordering violation */
461
462     *minor_status = 0;
463     return(retval);
464 }
465
466 /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
467    conf_state is only valid if SEAL. */
468
469 OM_uint32
470 kg_unseal(minor_status, context_handle, input_token_buffer,
471           message_buffer, conf_state, qop_state, toktype)
472     OM_uint32 *minor_status;
473     gss_ctx_id_t context_handle;
474     gss_buffer_t input_token_buffer;
475     gss_buffer_t message_buffer;
476     int *conf_state;
477     gss_qop_t *qop_state;
478     int toktype;
479 {
480     krb5_gss_ctx_id_rec *ctx;
481     unsigned char *ptr;
482     unsigned int bodysize;
483     int err;
484     int toktype2;
485     int vfyflags = 0;
486     OM_uint32 ret;
487
488     ctx = (krb5_gss_ctx_id_rec *) context_handle;
489
490     if (! ctx->established) {
491         *minor_status = KG_CTX_INCOMPLETE;
492         return(GSS_S_NO_CONTEXT);
493     }
494
495     /* parse the token, leave the data in message_buffer, setting conf_state */
496
497     /* verify the header */
498
499     ptr = (unsigned char *) input_token_buffer->value;
500
501
502     err = g_verify_token_header(ctx->mech_used,
503                                 &bodysize, &ptr, -1,
504                                 input_token_buffer->length,
505                                 vfyflags);
506     if (err) {
507         *minor_status = err;
508         return GSS_S_DEFECTIVE_TOKEN;
509     }
510
511     if (bodysize < 2) {
512         *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
513         return GSS_S_DEFECTIVE_TOKEN;
514     }
515
516     toktype2 = load_16_be(ptr);
517
518     ptr += 2;
519     bodysize -= 2;
520
521     switch (toktype2) {
522     case KG2_TOK_MIC_MSG:
523     case KG2_TOK_WRAP_MSG:
524     case KG2_TOK_DEL_CTX:
525         ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
526                                           ptr, bodysize, message_buffer,
527                                           conf_state, qop_state, toktype);
528         break;
529     case KG_TOK_MIC_MSG:
530     case KG_TOK_WRAP_MSG:
531     case KG_TOK_DEL_CTX:
532         ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
533                            message_buffer, conf_state, qop_state,
534                            toktype);
535         break;
536     default:
537         *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
538         ret = GSS_S_DEFECTIVE_TOKEN;
539         break;
540     }
541
542     if (ret != 0)
543         save_error_info (*minor_status, ctx->k5_context);
544
545     return ret;
546 }
547
548 OM_uint32 KRB5_CALLCONV
549 krb5_gss_unwrap(minor_status, context_handle,
550                 input_message_buffer, output_message_buffer,
551                 conf_state, qop_state)
552     OM_uint32           *minor_status;
553     gss_ctx_id_t        context_handle;
554     gss_buffer_t        input_message_buffer;
555     gss_buffer_t        output_message_buffer;
556     int                 *conf_state;
557     gss_qop_t           *qop_state;
558 {
559     OM_uint32           rstat;
560
561     rstat = kg_unseal(minor_status, context_handle,
562                       input_message_buffer, output_message_buffer,
563                       conf_state, qop_state, KG_TOK_WRAP_MSG);
564     return(rstat);
565 }
566
567 OM_uint32 KRB5_CALLCONV
568 krb5_gss_verify_mic(minor_status, context_handle,
569                     message_buffer, token_buffer,
570                     qop_state)
571     OM_uint32           *minor_status;
572     gss_ctx_id_t        context_handle;
573     gss_buffer_t        message_buffer;
574     gss_buffer_t        token_buffer;
575     gss_qop_t           *qop_state;
576 {
577     OM_uint32           rstat;
578
579     rstat = kg_unseal(minor_status, context_handle,
580                       token_buffer, message_buffer,
581                       NULL, qop_state, KG_TOK_MIC_MSG);
582     return(rstat);
583 }