1178825Sdfr/*
2233294Sstas * Copyright (c) 1997 - 2003 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36233294Sstas#ifdef HEIM_WEAK_CRYPTO
37178825Sdfr
38178825Sdfrstatic OM_uint32
39178825Sdfrverify_mic_des
40178825Sdfr           (OM_uint32 * minor_status,
41178825Sdfr            const gsskrb5_ctx context_handle,
42178825Sdfr	    krb5_context context,
43178825Sdfr            const gss_buffer_t message_buffer,
44178825Sdfr            const gss_buffer_t token_buffer,
45178825Sdfr            gss_qop_t * qop_state,
46178825Sdfr	    krb5_keyblock *key,
47233294Sstas	    const char *type
48178825Sdfr	    )
49178825Sdfr{
50178825Sdfr  u_char *p;
51233294Sstas  EVP_MD_CTX *md5;
52178825Sdfr  u_char hash[16], *seq;
53178825Sdfr  DES_key_schedule schedule;
54233294Sstas  EVP_CIPHER_CTX des_ctx;
55178825Sdfr  DES_cblock zero;
56178825Sdfr  DES_cblock deskey;
57178825Sdfr  uint32_t seq_number;
58178825Sdfr  OM_uint32 ret;
59178825Sdfr  int cmp;
60178825Sdfr
61178825Sdfr  p = token_buffer->value;
62178825Sdfr  ret = _gsskrb5_verify_header (&p,
63178825Sdfr				   token_buffer->length,
64178825Sdfr				   type,
65178825Sdfr				   GSS_KRB5_MECHANISM);
66178825Sdfr  if (ret)
67178825Sdfr      return ret;
68178825Sdfr
69178825Sdfr  if (memcmp(p, "\x00\x00", 2) != 0)
70178825Sdfr      return GSS_S_BAD_SIG;
71178825Sdfr  p += 2;
72178825Sdfr  if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
73178825Sdfr    return GSS_S_BAD_MIC;
74178825Sdfr  p += 4;
75178825Sdfr  p += 16;
76178825Sdfr
77178825Sdfr  /* verify checksum */
78233294Sstas  md5 = EVP_MD_CTX_create();
79233294Sstas  EVP_DigestInit_ex(md5, EVP_md5(), NULL);
80233294Sstas  EVP_DigestUpdate(md5, p - 24, 8);
81233294Sstas  EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length);
82233294Sstas  EVP_DigestFinal_ex(md5, hash, NULL);
83233294Sstas  EVP_MD_CTX_destroy(md5);
84178825Sdfr
85178825Sdfr  memset (&zero, 0, sizeof(zero));
86178825Sdfr  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
87178825Sdfr
88233294Sstas  DES_set_key_unchecked (&deskey, &schedule);
89178825Sdfr  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
90178825Sdfr		 &schedule, &zero);
91233294Sstas  if (ct_memcmp (p - 8, hash, 8) != 0) {
92178825Sdfr    memset (deskey, 0, sizeof(deskey));
93178825Sdfr    memset (&schedule, 0, sizeof(schedule));
94178825Sdfr    return GSS_S_BAD_MIC;
95178825Sdfr  }
96178825Sdfr
97178825Sdfr  /* verify sequence number */
98233294Sstas
99178825Sdfr  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
100178825Sdfr
101178825Sdfr  p -= 16;
102178825Sdfr
103233294Sstas  EVP_CIPHER_CTX_init(&des_ctx);
104233294Sstas  EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0);
105233294Sstas  EVP_Cipher(&des_ctx, p, p, 8);
106233294Sstas  EVP_CIPHER_CTX_cleanup(&des_ctx);
107233294Sstas
108178825Sdfr  memset (deskey, 0, sizeof(deskey));
109178825Sdfr  memset (&schedule, 0, sizeof(schedule));
110178825Sdfr
111178825Sdfr  seq = p;
112178825Sdfr  _gsskrb5_decode_om_uint32(seq, &seq_number);
113178825Sdfr
114178825Sdfr  if (context_handle->more_flags & LOCAL)
115233294Sstas      cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
116178825Sdfr  else
117233294Sstas      cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
118178825Sdfr
119178825Sdfr  if (cmp != 0) {
120178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
121178825Sdfr    return GSS_S_BAD_MIC;
122178825Sdfr  }
123178825Sdfr
124178825Sdfr  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
125178825Sdfr  if (ret) {
126178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
127178825Sdfr      return ret;
128178825Sdfr  }
129178825Sdfr
130178825Sdfr  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
131178825Sdfr
132178825Sdfr  return GSS_S_COMPLETE;
133178825Sdfr}
134233294Sstas#endif
135178825Sdfr
136178825Sdfrstatic OM_uint32
137178825Sdfrverify_mic_des3
138178825Sdfr           (OM_uint32 * minor_status,
139178825Sdfr            const gsskrb5_ctx context_handle,
140178825Sdfr	    krb5_context context,
141178825Sdfr            const gss_buffer_t message_buffer,
142178825Sdfr            const gss_buffer_t token_buffer,
143178825Sdfr            gss_qop_t * qop_state,
144178825Sdfr	    krb5_keyblock *key,
145233294Sstas	    const char *type
146178825Sdfr	    )
147178825Sdfr{
148178825Sdfr  u_char *p;
149178825Sdfr  u_char *seq;
150178825Sdfr  uint32_t seq_number;
151178825Sdfr  OM_uint32 ret;
152178825Sdfr  krb5_crypto crypto;
153178825Sdfr  krb5_data seq_data;
154178825Sdfr  int cmp, docompat;
155178825Sdfr  Checksum csum;
156178825Sdfr  char *tmp;
157178825Sdfr  char ivec[8];
158233294Sstas
159178825Sdfr  p = token_buffer->value;
160178825Sdfr  ret = _gsskrb5_verify_header (&p,
161178825Sdfr				   token_buffer->length,
162178825Sdfr				   type,
163178825Sdfr				   GSS_KRB5_MECHANISM);
164178825Sdfr  if (ret)
165178825Sdfr      return ret;
166178825Sdfr
167178825Sdfr  if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
168178825Sdfr      return GSS_S_BAD_SIG;
169178825Sdfr  p += 2;
170178825Sdfr  if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
171178825Sdfr    return GSS_S_BAD_MIC;
172178825Sdfr  p += 4;
173178825Sdfr
174178825Sdfr  ret = krb5_crypto_init(context, key,
175178825Sdfr			 ETYPE_DES3_CBC_NONE, &crypto);
176178825Sdfr  if (ret){
177178825Sdfr      *minor_status = ret;
178178825Sdfr      return GSS_S_FAILURE;
179178825Sdfr  }
180178825Sdfr
181178825Sdfr  /* verify sequence number */
182178825Sdfr  docompat = 0;
183178825Sdfrretry:
184178825Sdfr  if (docompat)
185178825Sdfr      memset(ivec, 0, 8);
186178825Sdfr  else
187178825Sdfr      memcpy(ivec, p + 8, 8);
188178825Sdfr
189178825Sdfr  ret = krb5_decrypt_ivec (context,
190178825Sdfr			   crypto,
191178825Sdfr			   KRB5_KU_USAGE_SEQ,
192178825Sdfr			   p, 8, &seq_data, ivec);
193178825Sdfr  if (ret) {
194178825Sdfr      if (docompat++) {
195178825Sdfr	  krb5_crypto_destroy (context, crypto);
196178825Sdfr	  *minor_status = ret;
197178825Sdfr	  return GSS_S_FAILURE;
198178825Sdfr      } else
199178825Sdfr	  goto retry;
200178825Sdfr  }
201178825Sdfr
202178825Sdfr  if (seq_data.length != 8) {
203178825Sdfr      krb5_data_free (&seq_data);
204178825Sdfr      if (docompat++) {
205178825Sdfr	  krb5_crypto_destroy (context, crypto);
206178825Sdfr	  return GSS_S_BAD_MIC;
207178825Sdfr      } else
208178825Sdfr	  goto retry;
209178825Sdfr  }
210178825Sdfr
211178825Sdfr  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
212178825Sdfr
213178825Sdfr  seq = seq_data.data;
214178825Sdfr  _gsskrb5_decode_om_uint32(seq, &seq_number);
215178825Sdfr
216178825Sdfr  if (context_handle->more_flags & LOCAL)
217233294Sstas      cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
218178825Sdfr  else
219233294Sstas      cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
220178825Sdfr
221178825Sdfr  krb5_data_free (&seq_data);
222178825Sdfr  if (cmp != 0) {
223178825Sdfr      krb5_crypto_destroy (context, crypto);
224178825Sdfr      *minor_status = 0;
225178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
226178825Sdfr      return GSS_S_BAD_MIC;
227178825Sdfr  }
228178825Sdfr
229178825Sdfr  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
230178825Sdfr  if (ret) {
231178825Sdfr      krb5_crypto_destroy (context, crypto);
232178825Sdfr      *minor_status = 0;
233178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
234178825Sdfr      return ret;
235178825Sdfr  }
236178825Sdfr
237178825Sdfr  /* verify checksum */
238178825Sdfr
239178825Sdfr  tmp = malloc (message_buffer->length + 8);
240178825Sdfr  if (tmp == NULL) {
241178825Sdfr      krb5_crypto_destroy (context, crypto);
242178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
243178825Sdfr      *minor_status = ENOMEM;
244178825Sdfr      return GSS_S_FAILURE;
245178825Sdfr  }
246178825Sdfr
247178825Sdfr  memcpy (tmp, p - 8, 8);
248178825Sdfr  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
249178825Sdfr
250178825Sdfr  csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
251178825Sdfr  csum.checksum.length = 20;
252178825Sdfr  csum.checksum.data   = p + 8;
253178825Sdfr
254234027Sstas  krb5_crypto_destroy (context, crypto);
255234027Sstas  ret = krb5_crypto_init(context, key,
256234027Sstas			 ETYPE_DES3_CBC_SHA1, &crypto);
257234027Sstas  if (ret){
258234027Sstas      *minor_status = ret;
259234027Sstas      return GSS_S_FAILURE;
260234027Sstas  }
261234027Sstas
262178825Sdfr  ret = krb5_verify_checksum (context, crypto,
263178825Sdfr			      KRB5_KU_USAGE_SIGN,
264178825Sdfr			      tmp, message_buffer->length + 8,
265178825Sdfr			      &csum);
266178825Sdfr  free (tmp);
267178825Sdfr  if (ret) {
268178825Sdfr      krb5_crypto_destroy (context, crypto);
269178825Sdfr      *minor_status = ret;
270178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
271178825Sdfr      return GSS_S_BAD_MIC;
272178825Sdfr  }
273178825Sdfr  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
274178825Sdfr
275178825Sdfr  krb5_crypto_destroy (context, crypto);
276178825Sdfr  return GSS_S_COMPLETE;
277178825Sdfr}
278178825Sdfr
279178825SdfrOM_uint32
280178825Sdfr_gsskrb5_verify_mic_internal
281178825Sdfr           (OM_uint32 * minor_status,
282233294Sstas            const gsskrb5_ctx ctx,
283178825Sdfr	    krb5_context context,
284178825Sdfr            const gss_buffer_t message_buffer,
285178825Sdfr            const gss_buffer_t token_buffer,
286178825Sdfr            gss_qop_t * qop_state,
287233294Sstas	    const char * type
288178825Sdfr	    )
289178825Sdfr{
290178825Sdfr    krb5_keyblock *key;
291178825Sdfr    OM_uint32 ret;
292178825Sdfr    krb5_keytype keytype;
293178825Sdfr
294233294Sstas    if (ctx->more_flags & IS_CFX)
295233294Sstas        return _gssapi_verify_mic_cfx (minor_status, ctx,
296233294Sstas				       context, message_buffer, token_buffer,
297233294Sstas				       qop_state);
298233294Sstas
299233294Sstas    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
300233294Sstas    ret = _gsskrb5i_get_token_key(ctx, context, &key);
301233294Sstas    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
302178825Sdfr    if (ret) {
303178825Sdfr	*minor_status = ret;
304178825Sdfr	return GSS_S_FAILURE;
305178825Sdfr    }
306178825Sdfr    *minor_status = 0;
307178825Sdfr    krb5_enctype_to_keytype (context, key->keytype, &keytype);
308178825Sdfr    switch (keytype) {
309178825Sdfr    case KEYTYPE_DES :
310233294Sstas#ifdef HEIM_WEAK_CRYPTO
311233294Sstas	ret = verify_mic_des (minor_status, ctx, context,
312178825Sdfr			      message_buffer, token_buffer, qop_state, key,
313178825Sdfr			      type);
314233294Sstas#else
315233294Sstas      ret = GSS_S_FAILURE;
316233294Sstas#endif
317178825Sdfr	break;
318178825Sdfr    case KEYTYPE_DES3 :
319233294Sstas	ret = verify_mic_des3 (minor_status, ctx, context,
320178825Sdfr			       message_buffer, token_buffer, qop_state, key,
321178825Sdfr			       type);
322178825Sdfr	break;
323178825Sdfr    case KEYTYPE_ARCFOUR :
324178825Sdfr    case KEYTYPE_ARCFOUR_56 :
325233294Sstas	ret = _gssapi_verify_mic_arcfour (minor_status, ctx,
326178825Sdfr					  context,
327178825Sdfr					  message_buffer, token_buffer,
328178825Sdfr					  qop_state, key, type);
329178825Sdfr	break;
330178825Sdfr    default :
331233294Sstas        abort();
332178825Sdfr    }
333178825Sdfr    krb5_free_keyblock (context, key);
334233294Sstas
335178825Sdfr    return ret;
336178825Sdfr}
337178825Sdfr
338233294SstasOM_uint32 GSSAPI_CALLCONV
339178825Sdfr_gsskrb5_verify_mic
340178825Sdfr           (OM_uint32 * minor_status,
341178825Sdfr            const gss_ctx_id_t context_handle,
342178825Sdfr            const gss_buffer_t message_buffer,
343178825Sdfr            const gss_buffer_t token_buffer,
344178825Sdfr            gss_qop_t * qop_state
345178825Sdfr	    )
346178825Sdfr{
347178825Sdfr    krb5_context context;
348178825Sdfr    OM_uint32 ret;
349178825Sdfr
350178825Sdfr    GSSAPI_KRB5_INIT (&context);
351178825Sdfr
352178825Sdfr    if (qop_state != NULL)
353178825Sdfr	*qop_state = GSS_C_QOP_DEFAULT;
354178825Sdfr
355233294Sstas    ret = _gsskrb5_verify_mic_internal(minor_status,
356178825Sdfr				       (gsskrb5_ctx)context_handle,
357178825Sdfr				       context,
358178825Sdfr				       message_buffer, token_buffer,
359233294Sstas				       qop_state, (void *)(intptr_t)"\x01\x01");
360178825Sdfr
361178825Sdfr    return ret;
362178825Sdfr}
363