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