1 /* $NetBSD: verify_mic.c,v 1.2 2014/05/12 15:25:49 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2003 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
verify_mic_des(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,krb5_keyblock * key,const char * type)41 verify_mic_des
42 (OM_uint32 * minor_status,
43 const gsskrb5_ctx context_handle,
44 krb5_context context,
45 const gss_buffer_t message_buffer,
46 const gss_buffer_t token_buffer,
47 gss_qop_t * qop_state,
48 krb5_keyblock *key,
49 const char *type
50 )
51 {
52 u_char *p;
53 EVP_MD_CTX *md5;
54 u_char hash[16], *seq;
55 DES_key_schedule schedule;
56 EVP_CIPHER_CTX des_ctx;
57 DES_cblock zero;
58 DES_cblock deskey;
59 uint32_t seq_number;
60 OM_uint32 ret;
61 int cmp;
62
63 p = token_buffer->value;
64 ret = _gsskrb5_verify_header (&p,
65 token_buffer->length,
66 type,
67 GSS_KRB5_MECHANISM);
68 if (ret)
69 return ret;
70
71 if (memcmp(p, "\x00\x00", 2) != 0)
72 return GSS_S_BAD_SIG;
73 p += 2;
74 if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
75 return GSS_S_BAD_MIC;
76 p += 4;
77 p += 16;
78
79 /* verify checksum */
80 md5 = EVP_MD_CTX_create();
81 EVP_DigestInit_ex(md5, EVP_md5(), NULL);
82 EVP_DigestUpdate(md5, p - 24, 8);
83 EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
84 EVP_DigestFinal_ex(md5, hash, NULL);
85 EVP_MD_CTX_destroy(md5);
86
87 memset (&zero, 0, sizeof(zero));
88 memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
89
90 DES_set_key_unchecked (&deskey, &schedule);
91 DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
92 &schedule, &zero);
93 if (ct_memcmp (p - 8, hash, 8) != 0) {
94 memset (deskey, 0, sizeof(deskey));
95 memset (&schedule, 0, sizeof(schedule));
96 return GSS_S_BAD_MIC;
97 }
98
99 /* verify sequence number */
100
101 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
102
103 p -= 16;
104
105 EVP_CIPHER_CTX_init(&des_ctx);
106 EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0);
107 EVP_Cipher(&des_ctx, p, p, 8);
108 EVP_CIPHER_CTX_cleanup(&des_ctx);
109
110 memset (deskey, 0, sizeof(deskey));
111 memset (&schedule, 0, sizeof(schedule));
112
113 seq = p;
114 _gsskrb5_decode_om_uint32(seq, &seq_number);
115
116 if (context_handle->more_flags & LOCAL)
117 cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
118 else
119 cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
120
121 if (cmp != 0) {
122 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
123 return GSS_S_BAD_MIC;
124 }
125
126 ret = _gssapi_msg_order_check(context_handle->order, seq_number);
127 if (ret) {
128 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
129 return ret;
130 }
131
132 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
133
134 return GSS_S_COMPLETE;
135 }
136 #endif
137
138 static OM_uint32
verify_mic_des3(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,krb5_keyblock * key,const char * type)139 verify_mic_des3
140 (OM_uint32 * minor_status,
141 const gsskrb5_ctx context_handle,
142 krb5_context context,
143 const gss_buffer_t message_buffer,
144 const gss_buffer_t token_buffer,
145 gss_qop_t * qop_state,
146 krb5_keyblock *key,
147 const char *type
148 )
149 {
150 u_char *p;
151 u_char *seq;
152 uint32_t seq_number;
153 OM_uint32 ret;
154 krb5_crypto crypto;
155 krb5_data seq_data;
156 int cmp, docompat;
157 Checksum csum;
158 char *tmp;
159 char ivec[8];
160
161 p = token_buffer->value;
162 ret = _gsskrb5_verify_header (&p,
163 token_buffer->length,
164 type,
165 GSS_KRB5_MECHANISM);
166 if (ret)
167 return ret;
168
169 if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
170 return GSS_S_BAD_SIG;
171 p += 2;
172 if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
173 return GSS_S_BAD_MIC;
174 p += 4;
175
176 ret = krb5_crypto_init(context, key,
177 ETYPE_DES3_CBC_NONE, &crypto);
178 if (ret){
179 *minor_status = ret;
180 return GSS_S_FAILURE;
181 }
182
183 /* verify sequence number */
184 docompat = 0;
185 retry:
186 if (docompat)
187 memset(ivec, 0, 8);
188 else
189 memcpy(ivec, p + 8, 8);
190
191 ret = krb5_decrypt_ivec (context,
192 crypto,
193 KRB5_KU_USAGE_SEQ,
194 p, 8, &seq_data, ivec);
195 if (ret) {
196 if (docompat++) {
197 krb5_crypto_destroy (context, crypto);
198 *minor_status = ret;
199 return GSS_S_FAILURE;
200 } else
201 goto retry;
202 }
203
204 if (seq_data.length != 8) {
205 krb5_data_free (&seq_data);
206 if (docompat++) {
207 krb5_crypto_destroy (context, crypto);
208 return GSS_S_BAD_MIC;
209 } else
210 goto retry;
211 }
212
213 HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
214
215 seq = seq_data.data;
216 _gsskrb5_decode_om_uint32(seq, &seq_number);
217
218 if (context_handle->more_flags & LOCAL)
219 cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
220 else
221 cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
222
223 krb5_data_free (&seq_data);
224 if (cmp != 0) {
225 krb5_crypto_destroy (context, crypto);
226 *minor_status = 0;
227 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
228 return GSS_S_BAD_MIC;
229 }
230
231 ret = _gssapi_msg_order_check(context_handle->order, seq_number);
232 if (ret) {
233 krb5_crypto_destroy (context, crypto);
234 *minor_status = 0;
235 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
236 return ret;
237 }
238
239 /* verify checksum */
240
241 tmp = malloc (message_buffer->length + 8);
242 if (tmp == NULL) {
243 krb5_crypto_destroy (context, crypto);
244 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
245 *minor_status = ENOMEM;
246 return GSS_S_FAILURE;
247 }
248
249 memcpy (tmp, p - 8, 8);
250 memcpy (tmp + 8, message_buffer->value, message_buffer->length);
251
252 csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
253 csum.checksum.length = 20;
254 csum.checksum.data = p + 8;
255
256 krb5_crypto_destroy (context, crypto);
257 ret = krb5_crypto_init(context, key,
258 ETYPE_DES3_CBC_SHA1, &crypto);
259 if (ret) {
260 free (tmp);
261 *minor_status = ret;
262 return GSS_S_FAILURE;
263 }
264
265 ret = krb5_verify_checksum (context, crypto,
266 KRB5_KU_USAGE_SIGN,
267 tmp, message_buffer->length + 8,
268 &csum);
269 free (tmp);
270 if (ret) {
271 krb5_crypto_destroy (context, crypto);
272 *minor_status = ret;
273 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
274 return GSS_S_BAD_MIC;
275 }
276 HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
277
278 krb5_crypto_destroy (context, crypto);
279 return GSS_S_COMPLETE;
280 }
281
282 OM_uint32
_gsskrb5_verify_mic_internal(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state,const char * type)283 _gsskrb5_verify_mic_internal
284 (OM_uint32 * minor_status,
285 const gsskrb5_ctx ctx,
286 krb5_context context,
287 const gss_buffer_t message_buffer,
288 const gss_buffer_t token_buffer,
289 gss_qop_t * qop_state,
290 const char * type
291 )
292 {
293 krb5_keyblock *key;
294 OM_uint32 ret;
295 krb5_keytype keytype;
296
297 if (ctx->more_flags & IS_CFX)
298 return _gssapi_verify_mic_cfx (minor_status, ctx,
299 context, message_buffer, token_buffer,
300 qop_state);
301
302 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
303 ret = _gsskrb5i_get_token_key(ctx, context, &key);
304 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
305 if (ret) {
306 *minor_status = ret;
307 return GSS_S_FAILURE;
308 }
309 *minor_status = 0;
310 krb5_enctype_to_keytype (context, key->keytype, &keytype);
311 switch (keytype) {
312 case KEYTYPE_DES :
313 #ifdef HEIM_WEAK_CRYPTO
314 ret = verify_mic_des (minor_status, ctx, context,
315 message_buffer, token_buffer, qop_state, key,
316 type);
317 #else
318 ret = GSS_S_FAILURE;
319 #endif
320 break;
321 case KEYTYPE_DES3 :
322 ret = verify_mic_des3 (minor_status, ctx, context,
323 message_buffer, token_buffer, qop_state, key,
324 type);
325 break;
326 case KEYTYPE_ARCFOUR :
327 case KEYTYPE_ARCFOUR_56 :
328 ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
329 context,
330 message_buffer, token_buffer,
331 qop_state, key, type);
332 break;
333 default :
334 abort();
335 }
336 krb5_free_keyblock (context, key);
337
338 return ret;
339 }
340
341 OM_uint32 GSSAPI_CALLCONV
_gsskrb5_verify_mic(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)342 _gsskrb5_verify_mic
343 (OM_uint32 * minor_status,
344 const gss_ctx_id_t context_handle,
345 const gss_buffer_t message_buffer,
346 const gss_buffer_t token_buffer,
347 gss_qop_t * qop_state
348 )
349 {
350 krb5_context context;
351 OM_uint32 ret;
352
353 GSSAPI_KRB5_INIT (&context);
354
355 if (qop_state != NULL)
356 *qop_state = GSS_C_QOP_DEFAULT;
357
358 ret = _gsskrb5_verify_mic_internal(minor_status,
359 (gsskrb5_ctx)context_handle,
360 context,
361 message_buffer, token_buffer,
362 qop_state, (void *)(intptr_t)"\x01\x01");
363
364 return ret;
365 }
366