1/*	$NetBSD$	*/
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
40static OM_uint32
41verify_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	    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
138static OM_uint32
139verify_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	    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;
185retry:
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  ret = krb5_verify_checksum (context, crypto,
257			      KRB5_KU_USAGE_SIGN,
258			      tmp, message_buffer->length + 8,
259			      &csum);
260  free (tmp);
261  if (ret) {
262      krb5_crypto_destroy (context, crypto);
263      *minor_status = ret;
264      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
265      return GSS_S_BAD_MIC;
266  }
267  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
268
269  krb5_crypto_destroy (context, crypto);
270  return GSS_S_COMPLETE;
271}
272
273OM_uint32
274_gsskrb5_verify_mic_internal
275           (OM_uint32 * minor_status,
276            const gsskrb5_ctx ctx,
277	    krb5_context context,
278            const gss_buffer_t message_buffer,
279            const gss_buffer_t token_buffer,
280            gss_qop_t * qop_state,
281	    char * type
282	    )
283{
284    krb5_keyblock *key;
285    OM_uint32 ret;
286    krb5_keytype keytype;
287
288    if (ctx->more_flags & IS_CFX)
289        return _gssapi_verify_mic_cfx (minor_status, ctx,
290				       context, message_buffer, token_buffer,
291				       qop_state);
292
293    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
294    ret = _gsskrb5i_get_token_key(ctx, context, &key);
295    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
296    if (ret) {
297	*minor_status = ret;
298	return GSS_S_FAILURE;
299    }
300    *minor_status = 0;
301    krb5_enctype_to_keytype (context, key->keytype, &keytype);
302    switch (keytype) {
303    case KEYTYPE_DES :
304#ifdef HEIM_WEAK_CRYPTO
305	ret = verify_mic_des (minor_status, ctx, context,
306			      message_buffer, token_buffer, qop_state, key,
307			      type);
308#else
309      ret = GSS_S_FAILURE;
310#endif
311	break;
312    case KEYTYPE_DES3 :
313	ret = verify_mic_des3 (minor_status, ctx, context,
314			       message_buffer, token_buffer, qop_state, key,
315			       type);
316	break;
317    case KEYTYPE_ARCFOUR :
318    case KEYTYPE_ARCFOUR_56 :
319	ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
320					  context,
321					  message_buffer, token_buffer,
322					  qop_state, key, type);
323	break;
324    default :
325        abort();
326    }
327    krb5_free_keyblock (context, key);
328
329    return ret;
330}
331
332OM_uint32 GSSAPI_CALLCONV
333_gsskrb5_verify_mic
334           (OM_uint32 * minor_status,
335            const gss_ctx_id_t context_handle,
336            const gss_buffer_t message_buffer,
337            const gss_buffer_t token_buffer,
338            gss_qop_t * qop_state
339	    )
340{
341    krb5_context context;
342    OM_uint32 ret;
343
344    GSSAPI_KRB5_INIT (&context);
345
346    if (qop_state != NULL)
347	*qop_state = GSS_C_QOP_DEFAULT;
348
349    ret = _gsskrb5_verify_mic_internal(minor_status,
350				       (gsskrb5_ctx)context_handle,
351				       context,
352				       message_buffer, token_buffer,
353				       qop_state, "\x01\x01");
354
355    return ret;
356}
357