1178825Sdfr/*
2178825Sdfr * Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "krb5/gsskrb5_locl.h"
35178825Sdfr
36178825SdfrRCSID("$Id: verify_mic.c 19031 2006-11-13 18:02:57Z lha $");
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,
47178825Sdfr	    char *type
48178825Sdfr	    )
49178825Sdfr{
50178825Sdfr  u_char *p;
51178825Sdfr  MD5_CTX md5;
52178825Sdfr  u_char hash[16], *seq;
53178825Sdfr  DES_key_schedule schedule;
54178825Sdfr  DES_cblock zero;
55178825Sdfr  DES_cblock deskey;
56178825Sdfr  uint32_t seq_number;
57178825Sdfr  OM_uint32 ret;
58178825Sdfr  int cmp;
59178825Sdfr
60178825Sdfr  p = token_buffer->value;
61178825Sdfr  ret = _gsskrb5_verify_header (&p,
62178825Sdfr				   token_buffer->length,
63178825Sdfr				   type,
64178825Sdfr				   GSS_KRB5_MECHANISM);
65178825Sdfr  if (ret)
66178825Sdfr      return ret;
67178825Sdfr
68178825Sdfr  if (memcmp(p, "\x00\x00", 2) != 0)
69178825Sdfr      return GSS_S_BAD_SIG;
70178825Sdfr  p += 2;
71178825Sdfr  if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
72178825Sdfr    return GSS_S_BAD_MIC;
73178825Sdfr  p += 4;
74178825Sdfr  p += 16;
75178825Sdfr
76178825Sdfr  /* verify checksum */
77178825Sdfr  MD5_Init (&md5);
78178825Sdfr  MD5_Update (&md5, p - 24, 8);
79178825Sdfr  MD5_Update (&md5, message_buffer->value,
80178825Sdfr	     message_buffer->length);
81178825Sdfr  MD5_Final (hash, &md5);
82178825Sdfr
83178825Sdfr  memset (&zero, 0, sizeof(zero));
84178825Sdfr  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
85178825Sdfr
86178825Sdfr  DES_set_key (&deskey, &schedule);
87178825Sdfr  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
88178825Sdfr		 &schedule, &zero);
89178825Sdfr  if (memcmp (p - 8, hash, 8) != 0) {
90178825Sdfr    memset (deskey, 0, sizeof(deskey));
91178825Sdfr    memset (&schedule, 0, sizeof(schedule));
92178825Sdfr    return GSS_S_BAD_MIC;
93178825Sdfr  }
94178825Sdfr
95178825Sdfr  /* verify sequence number */
96178825Sdfr
97178825Sdfr  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
98178825Sdfr
99178825Sdfr  p -= 16;
100178825Sdfr  DES_set_key (&deskey, &schedule);
101178825Sdfr  DES_cbc_encrypt ((void *)p, (void *)p, 8,
102178825Sdfr		   &schedule, (DES_cblock *)hash, DES_DECRYPT);
103178825Sdfr
104178825Sdfr  memset (deskey, 0, sizeof(deskey));
105178825Sdfr  memset (&schedule, 0, sizeof(schedule));
106178825Sdfr
107178825Sdfr  seq = p;
108178825Sdfr  _gsskrb5_decode_om_uint32(seq, &seq_number);
109178825Sdfr
110178825Sdfr  if (context_handle->more_flags & LOCAL)
111178825Sdfr      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
112178825Sdfr  else
113178825Sdfr      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
114178825Sdfr
115178825Sdfr  if (cmp != 0) {
116178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
117178825Sdfr    return GSS_S_BAD_MIC;
118178825Sdfr  }
119178825Sdfr
120178825Sdfr  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
121178825Sdfr  if (ret) {
122178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
123178825Sdfr      return ret;
124178825Sdfr  }
125178825Sdfr
126178825Sdfr  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
127178825Sdfr
128178825Sdfr  return GSS_S_COMPLETE;
129178825Sdfr}
130178825Sdfr
131178825Sdfrstatic OM_uint32
132178825Sdfrverify_mic_des3
133178825Sdfr           (OM_uint32 * minor_status,
134178825Sdfr            const gsskrb5_ctx context_handle,
135178825Sdfr	    krb5_context context,
136178825Sdfr            const gss_buffer_t message_buffer,
137178825Sdfr            const gss_buffer_t token_buffer,
138178825Sdfr            gss_qop_t * qop_state,
139178825Sdfr	    krb5_keyblock *key,
140178825Sdfr	    char *type
141178825Sdfr	    )
142178825Sdfr{
143178825Sdfr  u_char *p;
144178825Sdfr  u_char *seq;
145178825Sdfr  uint32_t seq_number;
146178825Sdfr  OM_uint32 ret;
147178825Sdfr  krb5_crypto crypto;
148178825Sdfr  krb5_data seq_data;
149178825Sdfr  int cmp, docompat;
150178825Sdfr  Checksum csum;
151178825Sdfr  char *tmp;
152178825Sdfr  char ivec[8];
153178825Sdfr
154178825Sdfr  p = token_buffer->value;
155178825Sdfr  ret = _gsskrb5_verify_header (&p,
156178825Sdfr				   token_buffer->length,
157178825Sdfr				   type,
158178825Sdfr				   GSS_KRB5_MECHANISM);
159178825Sdfr  if (ret)
160178825Sdfr      return ret;
161178825Sdfr
162178825Sdfr  if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
163178825Sdfr      return GSS_S_BAD_SIG;
164178825Sdfr  p += 2;
165178825Sdfr  if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
166178825Sdfr    return GSS_S_BAD_MIC;
167178825Sdfr  p += 4;
168178825Sdfr
169178825Sdfr  ret = krb5_crypto_init(context, key,
170178825Sdfr			 ETYPE_DES3_CBC_NONE, &crypto);
171178825Sdfr  if (ret){
172178825Sdfr      *minor_status = ret;
173178825Sdfr      return GSS_S_FAILURE;
174178825Sdfr  }
175178825Sdfr
176178825Sdfr  /* verify sequence number */
177178825Sdfr  docompat = 0;
178178825Sdfrretry:
179178825Sdfr  if (docompat)
180178825Sdfr      memset(ivec, 0, 8);
181178825Sdfr  else
182178825Sdfr      memcpy(ivec, p + 8, 8);
183178825Sdfr
184178825Sdfr  ret = krb5_decrypt_ivec (context,
185178825Sdfr			   crypto,
186178825Sdfr			   KRB5_KU_USAGE_SEQ,
187178825Sdfr			   p, 8, &seq_data, ivec);
188178825Sdfr  if (ret) {
189178825Sdfr      if (docompat++) {
190178825Sdfr	  krb5_crypto_destroy (context, crypto);
191178825Sdfr	  *minor_status = ret;
192178825Sdfr	  return GSS_S_FAILURE;
193178825Sdfr      } else
194178825Sdfr	  goto retry;
195178825Sdfr  }
196178825Sdfr
197178825Sdfr  if (seq_data.length != 8) {
198178825Sdfr      krb5_data_free (&seq_data);
199178825Sdfr      if (docompat++) {
200178825Sdfr	  krb5_crypto_destroy (context, crypto);
201178825Sdfr	  return GSS_S_BAD_MIC;
202178825Sdfr      } else
203178825Sdfr	  goto retry;
204178825Sdfr  }
205178825Sdfr
206178825Sdfr  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
207178825Sdfr
208178825Sdfr  seq = seq_data.data;
209178825Sdfr  _gsskrb5_decode_om_uint32(seq, &seq_number);
210178825Sdfr
211178825Sdfr  if (context_handle->more_flags & LOCAL)
212178825Sdfr      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
213178825Sdfr  else
214178825Sdfr      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
215178825Sdfr
216178825Sdfr  krb5_data_free (&seq_data);
217178825Sdfr  if (cmp != 0) {
218178825Sdfr      krb5_crypto_destroy (context, crypto);
219178825Sdfr      *minor_status = 0;
220178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
221178825Sdfr      return GSS_S_BAD_MIC;
222178825Sdfr  }
223178825Sdfr
224178825Sdfr  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
225178825Sdfr  if (ret) {
226178825Sdfr      krb5_crypto_destroy (context, crypto);
227178825Sdfr      *minor_status = 0;
228178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
229178825Sdfr      return ret;
230178825Sdfr  }
231178825Sdfr
232178825Sdfr  /* verify checksum */
233178825Sdfr
234178825Sdfr  tmp = malloc (message_buffer->length + 8);
235178825Sdfr  if (tmp == NULL) {
236178825Sdfr      krb5_crypto_destroy (context, crypto);
237178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
238178825Sdfr      *minor_status = ENOMEM;
239178825Sdfr      return GSS_S_FAILURE;
240178825Sdfr  }
241178825Sdfr
242178825Sdfr  memcpy (tmp, p - 8, 8);
243178825Sdfr  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
244178825Sdfr
245178825Sdfr  csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
246178825Sdfr  csum.checksum.length = 20;
247178825Sdfr  csum.checksum.data   = p + 8;
248178825Sdfr
249178825Sdfr  ret = krb5_verify_checksum (context, crypto,
250178825Sdfr			      KRB5_KU_USAGE_SIGN,
251178825Sdfr			      tmp, message_buffer->length + 8,
252178825Sdfr			      &csum);
253178825Sdfr  free (tmp);
254178825Sdfr  if (ret) {
255178825Sdfr      krb5_crypto_destroy (context, crypto);
256178825Sdfr      *minor_status = ret;
257178825Sdfr      HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
258178825Sdfr      return GSS_S_BAD_MIC;
259178825Sdfr  }
260178825Sdfr  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
261178825Sdfr
262178825Sdfr  krb5_crypto_destroy (context, crypto);
263178825Sdfr  return GSS_S_COMPLETE;
264178825Sdfr}
265178825Sdfr
266178825SdfrOM_uint32
267178825Sdfr_gsskrb5_verify_mic_internal
268178825Sdfr           (OM_uint32 * minor_status,
269178825Sdfr            const gsskrb5_ctx context_handle,
270178825Sdfr	    krb5_context context,
271178825Sdfr            const gss_buffer_t message_buffer,
272178825Sdfr            const gss_buffer_t token_buffer,
273178825Sdfr            gss_qop_t * qop_state,
274178825Sdfr	    char * type
275178825Sdfr	    )
276178825Sdfr{
277178825Sdfr    krb5_keyblock *key;
278178825Sdfr    OM_uint32 ret;
279178825Sdfr    krb5_keytype keytype;
280178825Sdfr
281178825Sdfr    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
282178825Sdfr    ret = _gsskrb5i_get_token_key(context_handle, context, &key);
283178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
284178825Sdfr    if (ret) {
285178825Sdfr	*minor_status = ret;
286178825Sdfr	return GSS_S_FAILURE;
287178825Sdfr    }
288178825Sdfr    *minor_status = 0;
289178825Sdfr    krb5_enctype_to_keytype (context, key->keytype, &keytype);
290178825Sdfr    switch (keytype) {
291178825Sdfr    case KEYTYPE_DES :
292178825Sdfr	ret = verify_mic_des (minor_status, context_handle, context,
293178825Sdfr			      message_buffer, token_buffer, qop_state, key,
294178825Sdfr			      type);
295178825Sdfr	break;
296178825Sdfr    case KEYTYPE_DES3 :
297178825Sdfr	ret = verify_mic_des3 (minor_status, context_handle, context,
298178825Sdfr			       message_buffer, token_buffer, qop_state, key,
299178825Sdfr			       type);
300178825Sdfr	break;
301178825Sdfr    case KEYTYPE_ARCFOUR :
302178825Sdfr    case KEYTYPE_ARCFOUR_56 :
303178825Sdfr	ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
304178825Sdfr					  context,
305178825Sdfr					  message_buffer, token_buffer,
306178825Sdfr					  qop_state, key, type);
307178825Sdfr	break;
308178825Sdfr    default :
309178825Sdfr	ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
310178825Sdfr				      context,
311178825Sdfr				      message_buffer, token_buffer, qop_state,
312178825Sdfr				      key);
313178825Sdfr	break;
314178825Sdfr    }
315178825Sdfr    krb5_free_keyblock (context, key);
316178825Sdfr
317178825Sdfr    return ret;
318178825Sdfr}
319178825Sdfr
320178825SdfrOM_uint32
321178825Sdfr_gsskrb5_verify_mic
322178825Sdfr           (OM_uint32 * minor_status,
323178825Sdfr            const gss_ctx_id_t context_handle,
324178825Sdfr            const gss_buffer_t message_buffer,
325178825Sdfr            const gss_buffer_t token_buffer,
326178825Sdfr            gss_qop_t * qop_state
327178825Sdfr	    )
328178825Sdfr{
329178825Sdfr    krb5_context context;
330178825Sdfr    OM_uint32 ret;
331178825Sdfr
332178825Sdfr    GSSAPI_KRB5_INIT (&context);
333178825Sdfr
334178825Sdfr    if (qop_state != NULL)
335178825Sdfr	*qop_state = GSS_C_QOP_DEFAULT;
336178825Sdfr
337178825Sdfr    ret = _gsskrb5_verify_mic_internal(minor_status,
338178825Sdfr				       (gsskrb5_ctx)context_handle,
339178825Sdfr				       context,
340178825Sdfr				       message_buffer, token_buffer,
341178825Sdfr				       qop_state, "\x01\x01");
342178825Sdfr
343178825Sdfr    return ret;
344178825Sdfr}
345