1*afab4e30Schristos /* $NetBSD: verify_mic.c,v 1.7 2023/06/19 21:41:43 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
5ca1c9b0cSelric * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric * All rights reserved.
7ca1c9b0cSelric *
8ca1c9b0cSelric * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric * modification, are permitted provided that the following conditions
10ca1c9b0cSelric * are met:
11ca1c9b0cSelric *
12ca1c9b0cSelric * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric * notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric *
15ca1c9b0cSelric * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric * notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric * documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric *
19ca1c9b0cSelric * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric * may be used to endorse or promote products derived from this software
21ca1c9b0cSelric * without specific prior written permission.
22ca1c9b0cSelric *
23ca1c9b0cSelric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric * SUCH DAMAGE.
34ca1c9b0cSelric */
35ca1c9b0cSelric
36ca1c9b0cSelric #include "gsskrb5_locl.h"
37ca1c9b0cSelric
38ca1c9b0cSelric #ifdef HEIM_WEAK_CRYPTO
39ca1c9b0cSelric
40ca1c9b0cSelric 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)41ca1c9b0cSelric verify_mic_des
42ca1c9b0cSelric (OM_uint32 * minor_status,
43ca1c9b0cSelric const gsskrb5_ctx context_handle,
44ca1c9b0cSelric krb5_context context,
45ca1c9b0cSelric const gss_buffer_t message_buffer,
46ca1c9b0cSelric const gss_buffer_t token_buffer,
47ca1c9b0cSelric gss_qop_t * qop_state,
48ca1c9b0cSelric krb5_keyblock *key,
494f77a458Spettai const char *type
50ca1c9b0cSelric )
51ca1c9b0cSelric {
52ca1c9b0cSelric u_char *p;
53ca1c9b0cSelric EVP_MD_CTX *md5;
54ca1c9b0cSelric u_char hash[16], *seq;
55ca1c9b0cSelric DES_key_schedule schedule;
566680b65dSchristos EVP_CIPHER_CTX *des_ctx;
57ca1c9b0cSelric DES_cblock zero;
58ca1c9b0cSelric DES_cblock deskey;
59ca1c9b0cSelric uint32_t seq_number;
60ca1c9b0cSelric OM_uint32 ret;
61ca1c9b0cSelric int cmp;
62ca1c9b0cSelric
63ca1c9b0cSelric p = token_buffer->value;
64ca1c9b0cSelric ret = _gsskrb5_verify_header (&p,
65ca1c9b0cSelric token_buffer->length,
66ca1c9b0cSelric type,
67ca1c9b0cSelric GSS_KRB5_MECHANISM);
68ca1c9b0cSelric if (ret)
69ca1c9b0cSelric return ret;
70ca1c9b0cSelric
71ca1c9b0cSelric if (memcmp(p, "\x00\x00", 2) != 0)
72ca1c9b0cSelric return GSS_S_BAD_SIG;
73ca1c9b0cSelric p += 2;
74ca1c9b0cSelric if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
75ca1c9b0cSelric return GSS_S_BAD_MIC;
76ca1c9b0cSelric p += 4;
77ca1c9b0cSelric p += 16;
78ca1c9b0cSelric
79ca1c9b0cSelric /* verify checksum */
80ca1c9b0cSelric md5 = EVP_MD_CTX_create();
81ca1c9b0cSelric EVP_DigestInit_ex(md5, EVP_md5(), NULL);
82ca1c9b0cSelric EVP_DigestUpdate(md5, p - 24, 8);
83ca1c9b0cSelric EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
84ca1c9b0cSelric EVP_DigestFinal_ex(md5, hash, NULL);
85ca1c9b0cSelric EVP_MD_CTX_destroy(md5);
86ca1c9b0cSelric
87ca1c9b0cSelric memset (&zero, 0, sizeof(zero));
88ca1c9b0cSelric memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
89ca1c9b0cSelric
90ca1c9b0cSelric DES_set_key_unchecked (&deskey, &schedule);
91ca1c9b0cSelric DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
92ca1c9b0cSelric &schedule, &zero);
93ca1c9b0cSelric if (ct_memcmp (p - 8, hash, 8) != 0) {
94241bea01Schristos memset_s(deskey, sizeof(deskey), 0, sizeof(deskey));
95241bea01Schristos memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule));
96ca1c9b0cSelric return GSS_S_BAD_MIC;
97ca1c9b0cSelric }
98ca1c9b0cSelric
99ca1c9b0cSelric /* verify sequence number */
100ca1c9b0cSelric
101ca1c9b0cSelric HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
102ca1c9b0cSelric
103ca1c9b0cSelric p -= 16;
104ca1c9b0cSelric
1056680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
1066680b65dSchristos EVP_CIPHER_CTX des_ctxs;
1076680b65dSchristos des_ctx = &des_ctxs;
1086680b65dSchristos EVP_CIPHER_CTX_init(des_ctx);
1096680b65dSchristos #else
1106680b65dSchristos des_ctx = EVP_CIPHER_CTX_new();
1116680b65dSchristos #endif
1127b2118deSchristos if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data,
1137b2118deSchristos hash, 0)) {
1147b2118deSchristos *minor_status = EINVAL;
1157b2118deSchristos return GSS_S_FAILURE;
1167b2118deSchristos }
1176680b65dSchristos EVP_Cipher(des_ctx, p, p, 8);
1186680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
1196680b65dSchristos EVP_CIPHER_CTX_cleanup(des_ctx);
1206680b65dSchristos #else
1216680b65dSchristos EVP_CIPHER_CTX_free(des_ctx);
1226680b65dSchristos #endif
123ca1c9b0cSelric
124241bea01Schristos memset_s(deskey, sizeof(deskey), 0, sizeof(deskey));
125241bea01Schristos memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule));
126ca1c9b0cSelric
127ca1c9b0cSelric seq = p;
128ca1c9b0cSelric _gsskrb5_decode_om_uint32(seq, &seq_number);
129ca1c9b0cSelric
130ca1c9b0cSelric if (context_handle->more_flags & LOCAL)
131ca1c9b0cSelric cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
132ca1c9b0cSelric else
133ca1c9b0cSelric cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
134ca1c9b0cSelric
135ca1c9b0cSelric if (cmp != 0) {
136ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
137ca1c9b0cSelric return GSS_S_BAD_MIC;
138ca1c9b0cSelric }
139ca1c9b0cSelric
140ca1c9b0cSelric ret = _gssapi_msg_order_check(context_handle->order, seq_number);
141ca1c9b0cSelric if (ret) {
142ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
143ca1c9b0cSelric return ret;
144ca1c9b0cSelric }
145ca1c9b0cSelric
146ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
147ca1c9b0cSelric
148ca1c9b0cSelric return GSS_S_COMPLETE;
149ca1c9b0cSelric }
150ca1c9b0cSelric #endif
151ca1c9b0cSelric
152ca1c9b0cSelric 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)153ca1c9b0cSelric verify_mic_des3
154ca1c9b0cSelric (OM_uint32 * minor_status,
155ca1c9b0cSelric const gsskrb5_ctx context_handle,
156ca1c9b0cSelric krb5_context context,
157ca1c9b0cSelric const gss_buffer_t message_buffer,
158ca1c9b0cSelric const gss_buffer_t token_buffer,
159ca1c9b0cSelric gss_qop_t * qop_state,
160ca1c9b0cSelric krb5_keyblock *key,
1614f77a458Spettai const char *type
162ca1c9b0cSelric )
163ca1c9b0cSelric {
164ca1c9b0cSelric u_char *p;
165ca1c9b0cSelric u_char *seq;
166ca1c9b0cSelric uint32_t seq_number;
167ca1c9b0cSelric OM_uint32 ret;
168ca1c9b0cSelric krb5_crypto crypto;
169ca1c9b0cSelric krb5_data seq_data;
170ca1c9b0cSelric int cmp, docompat;
171ca1c9b0cSelric Checksum csum;
172ca1c9b0cSelric char *tmp;
173ca1c9b0cSelric char ivec[8];
174ca1c9b0cSelric
175ca1c9b0cSelric p = token_buffer->value;
176ca1c9b0cSelric ret = _gsskrb5_verify_header (&p,
177ca1c9b0cSelric token_buffer->length,
178ca1c9b0cSelric type,
179ca1c9b0cSelric GSS_KRB5_MECHANISM);
180ca1c9b0cSelric if (ret)
181ca1c9b0cSelric return ret;
182ca1c9b0cSelric
183ca1c9b0cSelric if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
184ca1c9b0cSelric return GSS_S_BAD_SIG;
185ca1c9b0cSelric p += 2;
186ca1c9b0cSelric if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
187ca1c9b0cSelric return GSS_S_BAD_MIC;
188ca1c9b0cSelric p += 4;
189ca1c9b0cSelric
190ca1c9b0cSelric ret = krb5_crypto_init(context, key,
191ca1c9b0cSelric ETYPE_DES3_CBC_NONE, &crypto);
192ca1c9b0cSelric if (ret){
193ca1c9b0cSelric *minor_status = ret;
194ca1c9b0cSelric return GSS_S_FAILURE;
195ca1c9b0cSelric }
196ca1c9b0cSelric
197ca1c9b0cSelric /* verify sequence number */
198ca1c9b0cSelric docompat = 0;
199ca1c9b0cSelric retry:
200ca1c9b0cSelric if (docompat)
201ca1c9b0cSelric memset(ivec, 0, 8);
202ca1c9b0cSelric else
203ca1c9b0cSelric memcpy(ivec, p + 8, 8);
204ca1c9b0cSelric
205ca1c9b0cSelric ret = krb5_decrypt_ivec (context,
206ca1c9b0cSelric crypto,
207ca1c9b0cSelric KRB5_KU_USAGE_SEQ,
208ca1c9b0cSelric p, 8, &seq_data, ivec);
209ca1c9b0cSelric if (ret) {
210ca1c9b0cSelric if (docompat++) {
211ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
212ca1c9b0cSelric *minor_status = ret;
213ca1c9b0cSelric return GSS_S_FAILURE;
214ca1c9b0cSelric } else
215ca1c9b0cSelric goto retry;
216ca1c9b0cSelric }
217ca1c9b0cSelric
218ca1c9b0cSelric if (seq_data.length != 8) {
219ca1c9b0cSelric krb5_data_free (&seq_data);
220ca1c9b0cSelric if (docompat++) {
221ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
222ca1c9b0cSelric return GSS_S_BAD_MIC;
223ca1c9b0cSelric } else
224ca1c9b0cSelric goto retry;
225ca1c9b0cSelric }
226ca1c9b0cSelric
227ca1c9b0cSelric HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
228ca1c9b0cSelric
229ca1c9b0cSelric seq = seq_data.data;
230ca1c9b0cSelric _gsskrb5_decode_om_uint32(seq, &seq_number);
231ca1c9b0cSelric
232ca1c9b0cSelric if (context_handle->more_flags & LOCAL)
233ca1c9b0cSelric cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
234ca1c9b0cSelric else
235ca1c9b0cSelric cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
236ca1c9b0cSelric
237ca1c9b0cSelric krb5_data_free (&seq_data);
238ca1c9b0cSelric if (cmp != 0) {
239ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
240ca1c9b0cSelric *minor_status = 0;
241ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
242ca1c9b0cSelric return GSS_S_BAD_MIC;
243ca1c9b0cSelric }
244ca1c9b0cSelric
245ca1c9b0cSelric ret = _gssapi_msg_order_check(context_handle->order, seq_number);
246ca1c9b0cSelric if (ret) {
247ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
248ca1c9b0cSelric *minor_status = 0;
249ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
250ca1c9b0cSelric return ret;
251ca1c9b0cSelric }
252ca1c9b0cSelric
253ca1c9b0cSelric /* verify checksum */
254ca1c9b0cSelric
255ca1c9b0cSelric tmp = malloc (message_buffer->length + 8);
256ca1c9b0cSelric if (tmp == NULL) {
257ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
258ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
259ca1c9b0cSelric *minor_status = ENOMEM;
260ca1c9b0cSelric return GSS_S_FAILURE;
261ca1c9b0cSelric }
262ca1c9b0cSelric
263ca1c9b0cSelric memcpy (tmp, p - 8, 8);
264ca1c9b0cSelric memcpy (tmp + 8, message_buffer->value, message_buffer->length);
265ca1c9b0cSelric
266ca1c9b0cSelric csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
267ca1c9b0cSelric csum.checksum.length = 20;
268ca1c9b0cSelric csum.checksum.data = p + 8;
269ca1c9b0cSelric
2704f77a458Spettai krb5_crypto_destroy (context, crypto);
2714f77a458Spettai ret = krb5_crypto_init(context, key,
2724f77a458Spettai ETYPE_DES3_CBC_SHA1, &crypto);
2734f77a458Spettai if (ret) {
27453c5be25Schristos free (tmp);
2754f77a458Spettai *minor_status = ret;
2764f77a458Spettai return GSS_S_FAILURE;
2774f77a458Spettai }
2784f77a458Spettai
279ca1c9b0cSelric ret = krb5_verify_checksum (context, crypto,
280ca1c9b0cSelric KRB5_KU_USAGE_SIGN,
281ca1c9b0cSelric tmp, message_buffer->length + 8,
282ca1c9b0cSelric &csum);
283ca1c9b0cSelric free (tmp);
284ca1c9b0cSelric if (ret) {
285ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
286ca1c9b0cSelric *minor_status = ret;
287ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
288ca1c9b0cSelric return GSS_S_BAD_MIC;
289ca1c9b0cSelric }
290ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
291ca1c9b0cSelric
292ca1c9b0cSelric krb5_crypto_destroy (context, crypto);
293ca1c9b0cSelric return GSS_S_COMPLETE;
294ca1c9b0cSelric }
295ca1c9b0cSelric
296ca1c9b0cSelric 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)297ca1c9b0cSelric _gsskrb5_verify_mic_internal
298ca1c9b0cSelric (OM_uint32 * minor_status,
299ca1c9b0cSelric const gsskrb5_ctx ctx,
300ca1c9b0cSelric krb5_context context,
301ca1c9b0cSelric const gss_buffer_t message_buffer,
302ca1c9b0cSelric const gss_buffer_t token_buffer,
303ca1c9b0cSelric gss_qop_t * qop_state,
3044f77a458Spettai const char * type
305ca1c9b0cSelric )
306ca1c9b0cSelric {
307ca1c9b0cSelric krb5_keyblock *key;
308ca1c9b0cSelric OM_uint32 ret;
309ca1c9b0cSelric
310ca1c9b0cSelric if (ctx->more_flags & IS_CFX)
311ca1c9b0cSelric return _gssapi_verify_mic_cfx (minor_status, ctx,
312ca1c9b0cSelric context, message_buffer, token_buffer,
313ca1c9b0cSelric qop_state);
314ca1c9b0cSelric
315ca1c9b0cSelric HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
316ca1c9b0cSelric ret = _gsskrb5i_get_token_key(ctx, context, &key);
317ca1c9b0cSelric HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
318ca1c9b0cSelric if (ret) {
319ca1c9b0cSelric *minor_status = ret;
320ca1c9b0cSelric return GSS_S_FAILURE;
321ca1c9b0cSelric }
322ca1c9b0cSelric *minor_status = 0;
323d3273b5bSchristos
324d3273b5bSchristos switch (key->keytype) {
325d3273b5bSchristos case KRB5_ENCTYPE_DES_CBC_CRC :
326d3273b5bSchristos case KRB5_ENCTYPE_DES_CBC_MD4 :
327d3273b5bSchristos case KRB5_ENCTYPE_DES_CBC_MD5 :
328ca1c9b0cSelric #ifdef HEIM_WEAK_CRYPTO
329ca1c9b0cSelric ret = verify_mic_des (minor_status, ctx, context,
330ca1c9b0cSelric message_buffer, token_buffer, qop_state, key,
331ca1c9b0cSelric type);
332ca1c9b0cSelric #else
333ca1c9b0cSelric ret = GSS_S_FAILURE;
334ca1c9b0cSelric #endif
335ca1c9b0cSelric break;
336d3273b5bSchristos case KRB5_ENCTYPE_DES3_CBC_MD5 :
337d3273b5bSchristos case KRB5_ENCTYPE_DES3_CBC_SHA1 :
338ca1c9b0cSelric ret = verify_mic_des3 (minor_status, ctx, context,
339ca1c9b0cSelric message_buffer, token_buffer, qop_state, key,
340ca1c9b0cSelric type);
341ca1c9b0cSelric break;
342d3273b5bSchristos case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
343d3273b5bSchristos case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
344ca1c9b0cSelric ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
345ca1c9b0cSelric context,
346ca1c9b0cSelric message_buffer, token_buffer,
347ca1c9b0cSelric qop_state, key, type);
348ca1c9b0cSelric break;
349ca1c9b0cSelric default :
350ca1c9b0cSelric abort();
351ca1c9b0cSelric }
352ca1c9b0cSelric krb5_free_keyblock (context, key);
353ca1c9b0cSelric
354ca1c9b0cSelric return ret;
355ca1c9b0cSelric }
356ca1c9b0cSelric
357ca1c9b0cSelric OM_uint32 GSSAPI_CALLCONV
_gsskrb5_verify_mic(OM_uint32 * minor_status,gss_const_ctx_id_t context_handle,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)358ca1c9b0cSelric _gsskrb5_verify_mic
359ca1c9b0cSelric (OM_uint32 * minor_status,
360d3273b5bSchristos gss_const_ctx_id_t context_handle,
361ca1c9b0cSelric const gss_buffer_t message_buffer,
362ca1c9b0cSelric const gss_buffer_t token_buffer,
363ca1c9b0cSelric gss_qop_t * qop_state
364ca1c9b0cSelric )
365ca1c9b0cSelric {
366ca1c9b0cSelric krb5_context context;
367ca1c9b0cSelric OM_uint32 ret;
368ca1c9b0cSelric
369ca1c9b0cSelric GSSAPI_KRB5_INIT (&context);
370ca1c9b0cSelric
371ca1c9b0cSelric if (qop_state != NULL)
372ca1c9b0cSelric *qop_state = GSS_C_QOP_DEFAULT;
373ca1c9b0cSelric
374ca1c9b0cSelric ret = _gsskrb5_verify_mic_internal(minor_status,
375ca1c9b0cSelric (gsskrb5_ctx)context_handle,
376ca1c9b0cSelric context,
377ca1c9b0cSelric message_buffer, token_buffer,
3784f77a458Spettai qop_state, (void *)(intptr_t)"\x01\x01");
379ca1c9b0cSelric
380ca1c9b0cSelric return ret;
381ca1c9b0cSelric }
382