get_mic.c revision 178825
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: get_mic.c 19031 2006-11-13 18:02:57Z lha $");
37178825Sdfr
38178825Sdfrstatic OM_uint32
39178825Sdfrmic_des
40178825Sdfr           (OM_uint32 * minor_status,
41178825Sdfr            const gsskrb5_ctx ctx,
42178825Sdfr	    krb5_context context,
43178825Sdfr            gss_qop_t qop_req,
44178825Sdfr            const gss_buffer_t message_buffer,
45178825Sdfr            gss_buffer_t message_token,
46178825Sdfr	    krb5_keyblock *key
47178825Sdfr           )
48178825Sdfr{
49178825Sdfr  u_char *p;
50178825Sdfr  MD5_CTX md5;
51178825Sdfr  u_char hash[16];
52178825Sdfr  DES_key_schedule schedule;
53178825Sdfr  DES_cblock deskey;
54178825Sdfr  DES_cblock zero;
55178825Sdfr  int32_t seq_number;
56178825Sdfr  size_t len, total_len;
57178825Sdfr
58178825Sdfr  _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM);
59178825Sdfr
60178825Sdfr  message_token->length = total_len;
61178825Sdfr  message_token->value  = malloc (total_len);
62178825Sdfr  if (message_token->value == NULL) {
63178825Sdfr    message_token->length = 0;
64178825Sdfr    *minor_status = ENOMEM;
65178825Sdfr    return GSS_S_FAILURE;
66178825Sdfr  }
67178825Sdfr
68178825Sdfr  p = _gsskrb5_make_header(message_token->value,
69178825Sdfr			      len,
70178825Sdfr			      "\x01\x01", /* TOK_ID */
71178825Sdfr			      GSS_KRB5_MECHANISM);
72178825Sdfr
73178825Sdfr  memcpy (p, "\x00\x00", 2);	/* SGN_ALG = DES MAC MD5 */
74178825Sdfr  p += 2;
75178825Sdfr
76178825Sdfr  memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */
77178825Sdfr  p += 4;
78178825Sdfr
79178825Sdfr  /* Fill in later (SND-SEQ) */
80178825Sdfr  memset (p, 0, 16);
81178825Sdfr  p += 16;
82178825Sdfr
83178825Sdfr  /* checksum */
84178825Sdfr  MD5_Init (&md5);
85178825Sdfr  MD5_Update (&md5, p - 24, 8);
86178825Sdfr  MD5_Update (&md5, message_buffer->value, message_buffer->length);
87178825Sdfr  MD5_Final (hash, &md5);
88178825Sdfr
89178825Sdfr  memset (&zero, 0, sizeof(zero));
90178825Sdfr  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
91178825Sdfr  DES_set_key (&deskey, &schedule);
92178825Sdfr  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
93178825Sdfr		 &schedule, &zero);
94178825Sdfr  memcpy (p - 8, hash, 8);	/* SGN_CKSUM */
95178825Sdfr
96178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
97178825Sdfr  /* sequence number */
98178825Sdfr  krb5_auth_con_getlocalseqnumber (context,
99178825Sdfr				   ctx->auth_context,
100178825Sdfr				   &seq_number);
101178825Sdfr
102178825Sdfr  p -= 16;			/* SND_SEQ */
103178825Sdfr  p[0] = (seq_number >> 0)  & 0xFF;
104178825Sdfr  p[1] = (seq_number >> 8)  & 0xFF;
105178825Sdfr  p[2] = (seq_number >> 16) & 0xFF;
106178825Sdfr  p[3] = (seq_number >> 24) & 0xFF;
107178825Sdfr  memset (p + 4,
108178825Sdfr	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
109178825Sdfr	  4);
110178825Sdfr
111178825Sdfr  DES_set_key (&deskey, &schedule);
112178825Sdfr  DES_cbc_encrypt ((void *)p, (void *)p, 8,
113178825Sdfr		   &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
114178825Sdfr
115178825Sdfr  krb5_auth_con_setlocalseqnumber (context,
116178825Sdfr			       ctx->auth_context,
117178825Sdfr			       ++seq_number);
118178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
119178825Sdfr
120178825Sdfr  memset (deskey, 0, sizeof(deskey));
121178825Sdfr  memset (&schedule, 0, sizeof(schedule));
122178825Sdfr
123178825Sdfr  *minor_status = 0;
124178825Sdfr  return GSS_S_COMPLETE;
125178825Sdfr}
126178825Sdfr
127178825Sdfrstatic OM_uint32
128178825Sdfrmic_des3
129178825Sdfr           (OM_uint32 * minor_status,
130178825Sdfr            const gsskrb5_ctx ctx,
131178825Sdfr	    krb5_context context,
132178825Sdfr            gss_qop_t qop_req,
133178825Sdfr            const gss_buffer_t message_buffer,
134178825Sdfr            gss_buffer_t message_token,
135178825Sdfr	    krb5_keyblock *key
136178825Sdfr           )
137178825Sdfr{
138178825Sdfr  u_char *p;
139178825Sdfr  Checksum cksum;
140178825Sdfr  u_char seq[8];
141178825Sdfr
142178825Sdfr  int32_t seq_number;
143178825Sdfr  size_t len, total_len;
144178825Sdfr
145178825Sdfr  krb5_crypto crypto;
146178825Sdfr  krb5_error_code kret;
147178825Sdfr  krb5_data encdata;
148178825Sdfr  char *tmp;
149178825Sdfr  char ivec[8];
150178825Sdfr
151178825Sdfr  _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM);
152178825Sdfr
153178825Sdfr  message_token->length = total_len;
154178825Sdfr  message_token->value  = malloc (total_len);
155178825Sdfr  if (message_token->value == NULL) {
156178825Sdfr      message_token->length = 0;
157178825Sdfr      *minor_status = ENOMEM;
158178825Sdfr      return GSS_S_FAILURE;
159178825Sdfr  }
160178825Sdfr
161178825Sdfr  p = _gsskrb5_make_header(message_token->value,
162178825Sdfr			      len,
163178825Sdfr			      "\x01\x01", /* TOK-ID */
164178825Sdfr			      GSS_KRB5_MECHANISM);
165178825Sdfr
166178825Sdfr  memcpy (p, "\x04\x00", 2);	/* SGN_ALG = HMAC SHA1 DES3-KD */
167178825Sdfr  p += 2;
168178825Sdfr
169178825Sdfr  memcpy (p, "\xff\xff\xff\xff", 4); /* filler */
170178825Sdfr  p += 4;
171178825Sdfr
172178825Sdfr  /* this should be done in parts */
173178825Sdfr
174178825Sdfr  tmp = malloc (message_buffer->length + 8);
175178825Sdfr  if (tmp == NULL) {
176178825Sdfr      free (message_token->value);
177178825Sdfr      message_token->value = NULL;
178178825Sdfr      message_token->length = 0;
179178825Sdfr      *minor_status = ENOMEM;
180178825Sdfr      return GSS_S_FAILURE;
181178825Sdfr  }
182178825Sdfr  memcpy (tmp, p - 8, 8);
183178825Sdfr  memcpy (tmp + 8, message_buffer->value, message_buffer->length);
184178825Sdfr
185178825Sdfr  kret = krb5_crypto_init(context, key, 0, &crypto);
186178825Sdfr  if (kret) {
187178825Sdfr      free (message_token->value);
188178825Sdfr      message_token->value = NULL;
189178825Sdfr      message_token->length = 0;
190178825Sdfr      free (tmp);
191178825Sdfr      *minor_status = kret;
192178825Sdfr      return GSS_S_FAILURE;
193178825Sdfr  }
194178825Sdfr
195178825Sdfr  kret = krb5_create_checksum (context,
196178825Sdfr			       crypto,
197178825Sdfr			       KRB5_KU_USAGE_SIGN,
198178825Sdfr			       0,
199178825Sdfr			       tmp,
200178825Sdfr			       message_buffer->length + 8,
201178825Sdfr			       &cksum);
202178825Sdfr  free (tmp);
203178825Sdfr  krb5_crypto_destroy (context, crypto);
204178825Sdfr  if (kret) {
205178825Sdfr      free (message_token->value);
206178825Sdfr      message_token->value = NULL;
207178825Sdfr      message_token->length = 0;
208178825Sdfr      *minor_status = kret;
209178825Sdfr      return GSS_S_FAILURE;
210178825Sdfr  }
211178825Sdfr
212178825Sdfr  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
213178825Sdfr
214178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
215178825Sdfr  /* sequence number */
216178825Sdfr  krb5_auth_con_getlocalseqnumber (context,
217178825Sdfr			       ctx->auth_context,
218178825Sdfr			       &seq_number);
219178825Sdfr
220178825Sdfr  seq[0] = (seq_number >> 0)  & 0xFF;
221178825Sdfr  seq[1] = (seq_number >> 8)  & 0xFF;
222178825Sdfr  seq[2] = (seq_number >> 16) & 0xFF;
223178825Sdfr  seq[3] = (seq_number >> 24) & 0xFF;
224178825Sdfr  memset (seq + 4,
225178825Sdfr	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
226178825Sdfr	  4);
227178825Sdfr
228178825Sdfr  kret = krb5_crypto_init(context, key,
229178825Sdfr			  ETYPE_DES3_CBC_NONE, &crypto);
230178825Sdfr  if (kret) {
231178825Sdfr      free (message_token->value);
232178825Sdfr      message_token->value = NULL;
233178825Sdfr      message_token->length = 0;
234178825Sdfr      *minor_status = kret;
235178825Sdfr      return GSS_S_FAILURE;
236178825Sdfr  }
237178825Sdfr
238178825Sdfr  if (ctx->more_flags & COMPAT_OLD_DES3)
239178825Sdfr      memset(ivec, 0, 8);
240178825Sdfr  else
241178825Sdfr      memcpy(ivec, p + 8, 8);
242178825Sdfr
243178825Sdfr  kret = krb5_encrypt_ivec (context,
244178825Sdfr			    crypto,
245178825Sdfr			    KRB5_KU_USAGE_SEQ,
246178825Sdfr			    seq, 8, &encdata, ivec);
247178825Sdfr  krb5_crypto_destroy (context, crypto);
248178825Sdfr  if (kret) {
249178825Sdfr      free (message_token->value);
250178825Sdfr      message_token->value = NULL;
251178825Sdfr      message_token->length = 0;
252178825Sdfr      *minor_status = kret;
253178825Sdfr      return GSS_S_FAILURE;
254178825Sdfr  }
255178825Sdfr
256178825Sdfr  assert (encdata.length == 8);
257178825Sdfr
258178825Sdfr  memcpy (p, encdata.data, encdata.length);
259178825Sdfr  krb5_data_free (&encdata);
260178825Sdfr
261178825Sdfr  krb5_auth_con_setlocalseqnumber (context,
262178825Sdfr			       ctx->auth_context,
263178825Sdfr			       ++seq_number);
264178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
265178825Sdfr
266178825Sdfr  free_Checksum (&cksum);
267178825Sdfr  *minor_status = 0;
268178825Sdfr  return GSS_S_COMPLETE;
269178825Sdfr}
270178825Sdfr
271178825SdfrOM_uint32 _gsskrb5_get_mic
272178825Sdfr           (OM_uint32 * minor_status,
273178825Sdfr            const gss_ctx_id_t context_handle,
274178825Sdfr            gss_qop_t qop_req,
275178825Sdfr            const gss_buffer_t message_buffer,
276178825Sdfr            gss_buffer_t message_token
277178825Sdfr           )
278178825Sdfr{
279178825Sdfr  krb5_context context;
280178825Sdfr  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
281178825Sdfr  krb5_keyblock *key;
282178825Sdfr  OM_uint32 ret;
283178825Sdfr  krb5_keytype keytype;
284178825Sdfr
285178825Sdfr  GSSAPI_KRB5_INIT (&context);
286178825Sdfr
287178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
288178825Sdfr  ret = _gsskrb5i_get_token_key(ctx, context, &key);
289178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
290178825Sdfr  if (ret) {
291178825Sdfr      *minor_status = ret;
292178825Sdfr      return GSS_S_FAILURE;
293178825Sdfr  }
294178825Sdfr  krb5_enctype_to_keytype (context, key->keytype, &keytype);
295178825Sdfr
296178825Sdfr  switch (keytype) {
297178825Sdfr  case KEYTYPE_DES :
298178825Sdfr      ret = mic_des (minor_status, ctx, context, qop_req,
299178825Sdfr		     message_buffer, message_token, key);
300178825Sdfr      break;
301178825Sdfr  case KEYTYPE_DES3 :
302178825Sdfr      ret = mic_des3 (minor_status, ctx, context, qop_req,
303178825Sdfr		      message_buffer, message_token, key);
304178825Sdfr      break;
305178825Sdfr  case KEYTYPE_ARCFOUR:
306178825Sdfr  case KEYTYPE_ARCFOUR_56:
307178825Sdfr      ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req,
308178825Sdfr				     message_buffer, message_token, key);
309178825Sdfr      break;
310178825Sdfr  default :
311178825Sdfr      ret = _gssapi_mic_cfx (minor_status, ctx, context, qop_req,
312178825Sdfr			     message_buffer, message_token, key);
313178825Sdfr      break;
314178825Sdfr  }
315178825Sdfr  krb5_free_keyblock (context, key);
316178825Sdfr  return ret;
317178825Sdfr}
318