1 /* $NetBSD: unwrap.c,v 1.5 2023/06/19 21:41:43 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "gsskrb5_locl.h"
37
38 #ifdef HEIM_WEAK_CRYPTO
39
40 static OM_uint32
unwrap_des(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state,krb5_keyblock * key)41 unwrap_des
42 (OM_uint32 * minor_status,
43 const gsskrb5_ctx context_handle,
44 const gss_buffer_t input_message_buffer,
45 gss_buffer_t output_message_buffer,
46 int * conf_state,
47 gss_qop_t * qop_state,
48 krb5_keyblock *key
49 )
50 {
51 u_char *p, *seq;
52 size_t len;
53 EVP_MD_CTX *md5;
54 u_char hash[16];
55 EVP_CIPHER_CTX *des_ctx;
56 DES_key_schedule schedule;
57 DES_cblock deskey;
58 DES_cblock zero;
59 size_t i;
60 uint32_t seq_number;
61 size_t padlength;
62 OM_uint32 ret;
63 int cstate;
64 int cmp;
65 int token_len;
66
67 if (IS_DCE_STYLE(context_handle)) {
68 token_len = 22 + 8 + 15; /* 45 */
69 if (input_message_buffer->length < token_len)
70 return GSS_S_BAD_MECH;
71 } else {
72 token_len = input_message_buffer->length;
73 }
74
75 p = input_message_buffer->value;
76 ret = _gsskrb5_verify_header (&p,
77 token_len,
78 "\x02\x01",
79 GSS_KRB5_MECHANISM);
80 if (ret)
81 return ret;
82
83 len = (p - (u_char *)input_message_buffer->value)
84 + 22 + 8;
85 if (input_message_buffer->length < len)
86 return GSS_S_BAD_MECH;
87
88 if (memcmp (p, "\x00\x00", 2) != 0)
89 return GSS_S_BAD_SIG;
90 p += 2;
91 if (memcmp (p, "\x00\x00", 2) == 0) {
92 cstate = 1;
93 } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
94 cstate = 0;
95 } else
96 return GSS_S_BAD_MIC;
97 p += 2;
98 if(conf_state != NULL)
99 *conf_state = cstate;
100 if (memcmp (p, "\xff\xff", 2) != 0)
101 return GSS_S_DEFECTIVE_TOKEN;
102 p += 2;
103 p += 16;
104
105 len = p - (u_char *)input_message_buffer->value;
106
107 if(cstate) {
108 /* decrypt data */
109 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
110 memset (&zero, 0, sizeof(zero));
111
112 for (i = 0; i < sizeof(deskey); ++i)
113 deskey[i] ^= 0xf0;
114
115
116 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
117 EVP_CIPHER_CTX des_ctxs;
118 des_ctx = &des_ctxs;
119 EVP_CIPHER_CTX_init(des_ctx);
120 #else
121 des_ctx = EVP_CIPHER_CTX_new();
122 #endif
123 if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0)) {
124 *minor_status = EINVAL;
125 return GSS_S_FAILURE;
126 }
127 EVP_Cipher(des_ctx, p, p, input_message_buffer->length - len);
128 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
129 EVP_CIPHER_CTX_cleanup(des_ctx);
130 #else
131 EVP_CIPHER_CTX_free(des_ctx);
132 #endif
133
134 memset (&schedule, 0, sizeof(schedule));
135 }
136
137 if (IS_DCE_STYLE(context_handle)) {
138 padlength = 0;
139 } else {
140 /* check pad */
141 ret = _gssapi_verify_pad(input_message_buffer,
142 input_message_buffer->length - len - 8,
143 &padlength);
144 if (ret)
145 return ret;
146 }
147
148 md5 = EVP_MD_CTX_create();
149 EVP_DigestInit_ex(md5, EVP_md5(), NULL);
150 EVP_DigestUpdate(md5, p - 24, 8);
151 EVP_DigestUpdate(md5, p, input_message_buffer->length - len);
152 EVP_DigestFinal_ex(md5, hash, NULL);
153 EVP_MD_CTX_destroy(md5);
154
155 memset (&zero, 0, sizeof(zero));
156 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
157 DES_set_key_unchecked (&deskey, &schedule);
158 DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
159 &schedule, &zero);
160 if (ct_memcmp (p - 8, hash, 8) != 0)
161 return GSS_S_BAD_MIC;
162
163 /* verify sequence number */
164
165 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
166
167 p -= 16;
168
169 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
170 EVP_CIPHER_CTX des_ctxs;
171 des_ctx = &des_ctxs;
172 EVP_CIPHER_CTX_init(des_ctx);
173 #else
174 des_ctx = EVP_CIPHER_CTX_new();
175 #endif
176 if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash,
177 0)) {
178 *minor_status = EINVAL;
179 return GSS_S_FAILURE;
180 }
181 EVP_Cipher(des_ctx, p, p, 8);
182 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
183 EVP_CIPHER_CTX_cleanup(des_ctx);
184 #else
185 EVP_CIPHER_CTX_free(des_ctx);
186 #endif
187
188 memset (deskey, 0, sizeof(deskey));
189 memset (&schedule, 0, sizeof(schedule));
190
191 seq = p;
192 _gsskrb5_decode_om_uint32(seq, &seq_number);
193
194 if (context_handle->more_flags & LOCAL)
195 cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
196 else
197 cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
198
199 if (cmp != 0) {
200 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
201 return GSS_S_BAD_MIC;
202 }
203
204 ret = _gssapi_msg_order_check(context_handle->order, seq_number);
205 if (ret) {
206 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
207 return ret;
208 }
209
210 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
211
212 /* copy out data */
213
214 output_message_buffer->length = input_message_buffer->length
215 - len - padlength - 8;
216 output_message_buffer->value = malloc(output_message_buffer->length);
217 if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
218 return GSS_S_FAILURE;
219 if (output_message_buffer->value != NULL)
220 memcpy (output_message_buffer->value,
221 p + 24,
222 output_message_buffer->length);
223 return GSS_S_COMPLETE;
224 }
225 #endif
226
227 static OM_uint32
unwrap_des3(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state,krb5_keyblock * key)228 unwrap_des3
229 (OM_uint32 * minor_status,
230 const gsskrb5_ctx context_handle,
231 krb5_context context,
232 const gss_buffer_t input_message_buffer,
233 gss_buffer_t output_message_buffer,
234 int * conf_state,
235 gss_qop_t * qop_state,
236 krb5_keyblock *key
237 )
238 {
239 u_char *p;
240 size_t len;
241 u_char *seq;
242 krb5_data seq_data;
243 u_char cksum[20];
244 uint32_t seq_number;
245 size_t padlength;
246 OM_uint32 ret;
247 int cstate;
248 krb5_crypto crypto;
249 Checksum csum;
250 int cmp;
251 int token_len;
252
253 if (IS_DCE_STYLE(context_handle)) {
254 token_len = 34 + 8 + 15; /* 57 */
255 if (input_message_buffer->length < token_len)
256 return GSS_S_BAD_MECH;
257 } else {
258 token_len = input_message_buffer->length;
259 }
260
261 p = input_message_buffer->value;
262 ret = _gsskrb5_verify_header (&p,
263 token_len,
264 "\x02\x01",
265 GSS_KRB5_MECHANISM);
266 if (ret)
267 return ret;
268
269 len = (p - (u_char *)input_message_buffer->value)
270 + 34 + 8;
271 if (input_message_buffer->length < len)
272 return GSS_S_BAD_MECH;
273
274 if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
275 return GSS_S_BAD_SIG;
276 p += 2;
277 if (ct_memcmp (p, "\x02\x00", 2) == 0) {
278 cstate = 1;
279 } else if (ct_memcmp (p, "\xff\xff", 2) == 0) {
280 cstate = 0;
281 } else
282 return GSS_S_BAD_MIC;
283 p += 2;
284 if(conf_state != NULL)
285 *conf_state = cstate;
286 if (ct_memcmp (p, "\xff\xff", 2) != 0)
287 return GSS_S_DEFECTIVE_TOKEN;
288 p += 2;
289 p += 28;
290
291 len = p - (u_char *)input_message_buffer->value;
292
293 if(cstate) {
294 /* decrypt data */
295 krb5_data tmp;
296
297 ret = krb5_crypto_init(context, key,
298 ETYPE_DES3_CBC_NONE, &crypto);
299 if (ret) {
300 *minor_status = ret;
301 return GSS_S_FAILURE;
302 }
303 ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL,
304 p, input_message_buffer->length - len, &tmp);
305 krb5_crypto_destroy(context, crypto);
306 if (ret) {
307 *minor_status = ret;
308 return GSS_S_FAILURE;
309 }
310 assert (tmp.length == input_message_buffer->length - len);
311
312 memcpy (p, tmp.data, tmp.length);
313 krb5_data_free(&tmp);
314 }
315
316 if (IS_DCE_STYLE(context_handle)) {
317 padlength = 0;
318 } else {
319 /* check pad */
320 ret = _gssapi_verify_pad(input_message_buffer,
321 input_message_buffer->length - len - 8,
322 &padlength);
323 if (ret)
324 return ret;
325 }
326
327 /* verify sequence number */
328
329 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
330
331 p -= 28;
332
333 ret = krb5_crypto_init(context, key,
334 ETYPE_DES3_CBC_NONE, &crypto);
335 if (ret) {
336 *minor_status = ret;
337 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
338 return GSS_S_FAILURE;
339 }
340 {
341 DES_cblock ivec;
342
343 memcpy(&ivec, p + 8, 8);
344 ret = krb5_decrypt_ivec (context,
345 crypto,
346 KRB5_KU_USAGE_SEQ,
347 p, 8, &seq_data,
348 &ivec);
349 }
350 krb5_crypto_destroy (context, crypto);
351 if (ret) {
352 *minor_status = ret;
353 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
354 return GSS_S_FAILURE;
355 }
356 if (seq_data.length != 8) {
357 krb5_data_free (&seq_data);
358 *minor_status = 0;
359 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
360 return GSS_S_BAD_MIC;
361 }
362
363 seq = seq_data.data;
364 _gsskrb5_decode_om_uint32(seq, &seq_number);
365
366 if (context_handle->more_flags & LOCAL)
367 cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
368 else
369 cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
370
371 krb5_data_free (&seq_data);
372 if (cmp != 0) {
373 *minor_status = 0;
374 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
375 return GSS_S_BAD_MIC;
376 }
377
378 ret = _gssapi_msg_order_check(context_handle->order, seq_number);
379 if (ret) {
380 *minor_status = 0;
381 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
382 return ret;
383 }
384
385 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
386
387 /* verify checksum */
388
389 memcpy (cksum, p + 8, 20);
390
391 memcpy (p + 20, p - 8, 8);
392
393 csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
394 csum.checksum.length = 20;
395 csum.checksum.data = cksum;
396
397 ret = krb5_crypto_init(context, key, 0, &crypto);
398 if (ret) {
399 *minor_status = ret;
400 return GSS_S_FAILURE;
401 }
402
403 ret = krb5_verify_checksum (context, crypto,
404 KRB5_KU_USAGE_SIGN,
405 p + 20,
406 input_message_buffer->length - len + 8,
407 &csum);
408 krb5_crypto_destroy (context, crypto);
409 if (ret) {
410 *minor_status = ret;
411 return GSS_S_FAILURE;
412 }
413
414 /* copy out data */
415
416 output_message_buffer->length = input_message_buffer->length
417 - len - padlength - 8;
418 output_message_buffer->value = malloc(output_message_buffer->length);
419 if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
420 return GSS_S_FAILURE;
421 if (output_message_buffer->value != NULL)
422 memcpy (output_message_buffer->value,
423 p + 36,
424 output_message_buffer->length);
425 return GSS_S_COMPLETE;
426 }
427
_gsskrb5_unwrap(OM_uint32 * minor_status,gss_const_ctx_id_t context_handle,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)428 OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap
429 (OM_uint32 * minor_status,
430 gss_const_ctx_id_t context_handle,
431 const gss_buffer_t input_message_buffer,
432 gss_buffer_t output_message_buffer,
433 int * conf_state,
434 gss_qop_t * qop_state
435 )
436 {
437 krb5_keyblock *key;
438 krb5_context context;
439 OM_uint32 ret;
440 gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
441
442 output_message_buffer->value = NULL;
443 output_message_buffer->length = 0;
444 if (qop_state != NULL)
445 *qop_state = GSS_C_QOP_DEFAULT;
446
447 GSSAPI_KRB5_INIT (&context);
448
449 if (ctx->more_flags & IS_CFX)
450 return _gssapi_unwrap_cfx (minor_status, ctx, context,
451 input_message_buffer, output_message_buffer,
452 conf_state, qop_state);
453
454 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
455 ret = _gsskrb5i_get_token_key(ctx, context, &key);
456 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
457 if (ret) {
458 *minor_status = ret;
459 return GSS_S_FAILURE;
460 }
461
462 *minor_status = 0;
463
464 switch (key->keytype) {
465 case KRB5_ENCTYPE_DES_CBC_CRC :
466 case KRB5_ENCTYPE_DES_CBC_MD4 :
467 case KRB5_ENCTYPE_DES_CBC_MD5 :
468 #ifdef HEIM_WEAK_CRYPTO
469 ret = unwrap_des (minor_status, ctx,
470 input_message_buffer, output_message_buffer,
471 conf_state, qop_state, key);
472 #else
473 ret = GSS_S_FAILURE;
474 #endif
475 break;
476 case KRB5_ENCTYPE_DES3_CBC_MD5 :
477 case KRB5_ENCTYPE_DES3_CBC_SHA1 :
478 ret = unwrap_des3 (minor_status, ctx, context,
479 input_message_buffer, output_message_buffer,
480 conf_state, qop_state, key);
481 break;
482 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
483 case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
484 ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
485 input_message_buffer, output_message_buffer,
486 conf_state, qop_state, key);
487 break;
488 default :
489 abort();
490 break;
491 }
492 krb5_free_keyblock (context, key);
493 return ret;
494 }
495