gsskrb5: add [un]wrap_ex for arcfour-hmac-md5
authorStefan Metzmacher <metze@samba.org>
Fri, 8 Aug 2008 14:25:56 +0000 (16:25 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Aug 2008 06:49:04 +0000 (08:49 +0200)
metze

source/heimdal/lib/gssapi/krb5/arcfour.c
source/heimdal/lib/gssapi/krb5/gsskrb5-private.h
source/heimdal/lib/gssapi/krb5/unwrap.c
source/heimdal/lib/gssapi/krb5/wrap.c

index 032da36ebc86a4dfd33d08cdd3ab4f0c24dfe122..4ec289531b2f8e151bc7c6d78782a34e7e71e76f 100644 (file)
@@ -495,6 +495,148 @@ _gssapi_wrap_arcfour(OM_uint32 * minor_status,
     return GSS_S_COMPLETE;
 }
 
+OM_uint32
+_gssapi_wrap_ex_arcfour(OM_uint32 *minor_status,
+                       const gsskrb5_ctx context_handle,
+                       krb5_context context,
+                       int conf_req_flag,
+                       gss_qop_t qop_req,
+                       int *conf_state,
+                       krb5_keyblock *key,
+                       const gss_buffer_t associated_data_buffer,
+                       gss_buffer_t message_buffer,
+                       gss_buffer_t output_token_buffer)
+{
+    u_char Klocaldata[16], k6_data[16], *p, *p0;
+    size_t token_len, wtoken_len;
+    krb5_keyblock Klocal;
+    krb5_error_code ret;
+    int32_t seq_number;
+
+    if (conf_state)
+       *conf_state = 0;
+
+    token_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+    _gssapi_encap_length(token_len, &token_len, &wtoken_len, GSS_KRB5_MECHANISM);
+
+    output_token_buffer->length = wtoken_len;
+    output_token_buffer->value  = malloc (wtoken_len);
+    if (output_token_buffer->value == NULL) {
+       *minor_status = ENOMEM;
+       return GSS_S_FAILURE;
+    }
+
+    p0 = _gssapi_make_mech_header(output_token_buffer->value,
+                                 token_len,
+                                 GSS_KRB5_MECHANISM);
+    p = p0;
+
+    *p++ = 0x02; /* TOK_ID */
+    *p++ = 0x01;
+    *p++ = 0x11; /* SGN_ALG */
+    *p++ = 0x00;
+    if (conf_req_flag) {
+       *p++ = 0x10; /* SEAL_ALG */
+       *p++ = 0x00;
+    } else {
+       *p++ = 0xff; /* SEAL_ALG */
+       *p++ = 0xff;
+    }
+    *p++ = 0xff; /* Filler */
+    *p++ = 0xff;
+
+    p = NULL;
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber (context,
+                                    context_handle->auth_context,
+                                    &seq_number);
+
+    _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
+
+    krb5_auth_con_setlocalseqnumber (context,
+                                    context_handle->auth_context,
+                                    ++seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    memset (p0 + 8 + 4,
+           (context_handle->more_flags & LOCAL) ? 0 : 0xff,
+           4);
+
+    krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
+
+    ret = arcfour_mic_cksum(context,
+                           key, KRB5_KU_USAGE_SEAL,
+                           p0 + 16, 8, /* SGN_CKSUM */
+                           p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
+                           p0 + 24, 8, /* Confounder */
+                           associated_data_buffer->value,
+                           associated_data_buffer->length);
+    if (ret) {
+       _gsskrb5_release_buffer(minor_status, output_token_buffer);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    {
+       int i;
+
+       Klocal.keytype = key->keytype;
+       Klocal.keyvalue.data = Klocaldata;
+       Klocal.keyvalue.length = sizeof(Klocaldata);
+
+       for (i = 0; i < 16; i++)
+           Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+    }
+    ret = arcfour_mic_key(context, &Klocal,
+                         p0 + 8, 4, /* SND_SEQ */
+                         k6_data, sizeof(k6_data));
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (ret) {
+       _gsskrb5_release_buffer(minor_status, output_token_buffer);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+
+    if(conf_req_flag) {
+       RC4_KEY rc4_key;
+
+       RC4_set_key (&rc4_key, sizeof(k6_data), (void *)k6_data);
+       /* XXX ? */
+       RC4 (&rc4_key, 8, p0 + 24, p0 + 24); /* Confounder */
+       RC4 (&rc4_key, message_buffer->length,
+            message_buffer->value,
+            message_buffer->value); /* data */
+       memset(&rc4_key, 0, sizeof(rc4_key));
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    ret = arcfour_mic_key(context, key,
+                         p0 + 16, 8, /* SGN_CKSUM */
+                         k6_data, sizeof(k6_data));
+    if (ret) {
+       _gsskrb5_release_buffer(minor_status, output_token_buffer);
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    {
+       RC4_KEY rc4_key;
+
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p0 + 8, p0 + 8); /* SND_SEQ */
+       memset(&rc4_key, 0, sizeof(rc4_key));
+       memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    if (conf_state)
+       *conf_state = conf_req_flag;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
 OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
                                 const gsskrb5_ctx context_handle,
                                 krb5_context context,
@@ -684,6 +826,155 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status,
     return GSS_S_COMPLETE;
 }
 
+OM_uint32
+_gssapi_unwrap_ex_arcfour(OM_uint32 *minor_status,
+                         const gsskrb5_ctx context_handle,
+                         krb5_context context,
+                         int *conf_state,
+                         gss_qop_t *qop_state,
+                         krb5_keyblock *key,
+                         const gss_buffer_t token_header_buffer,
+                         const gss_buffer_t associated_data_buffer,
+                         gss_buffer_t message_buffer)
+{
+    u_char Klocaldata[16];
+    krb5_keyblock Klocal;
+    krb5_error_code ret;
+    uint32_t seq_number;
+    OM_uint32 omret;
+    u_char k6_data[16], SND_SEQ[8], Confounder[8];
+    u_char cksum_data[8];
+    u_char *p, *p0;
+    int cmp;
+    int conf_flag;
+
+    if (conf_state)
+       *conf_state = 0;
+    if (qop_state)
+       *qop_state = 0;
+
+    p0 = token_header_buffer->value;
+
+    omret = _gssapi_verify_mech_header(&p0,
+                                      token_header_buffer->length,
+                                      GSS_KRB5_MECHANISM);
+    if (omret)
+       return omret;
+
+    p = p0;
+
+    if (memcmp(p, "\x02\x01", 2) != 0)
+       return GSS_S_BAD_SIG;
+    p += 2;
+    if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+       return GSS_S_BAD_SIG;
+    p += 2;
+
+    if (memcmp (p, "\x10\x00", 2) == 0)
+       conf_flag = 1;
+    else if (memcmp (p, "\xff\xff", 2) == 0)
+       conf_flag = 0;
+    else
+       return GSS_S_BAD_SIG;
+
+    p += 2;
+    if (memcmp (p, "\xff\xff", 2) != 0)
+       return GSS_S_BAD_MIC;
+    p = NULL;
+
+    ret = arcfour_mic_key(context, key,
+                         p0 + 16, 8, /* SGN_CKSUM */
+                         k6_data, sizeof(k6_data));
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    {
+       RC4_KEY rc4_key;
+
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p0 + 8, SND_SEQ); /* SND_SEQ */
+       memset(&rc4_key, 0, sizeof(rc4_key));
+       memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number);
+
+    if (context_handle->more_flags & LOCAL)
+       cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4);
+    else
+       cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4);
+
+    if (cmp != 0) {
+       *minor_status = 0;
+       return GSS_S_BAD_MIC;
+    }
+
+    {
+       int i;
+
+       Klocal.keytype = key->keytype;
+       Klocal.keyvalue.data = Klocaldata;
+       Klocal.keyvalue.length = sizeof(Klocaldata);
+
+       for (i = 0; i < 16; i++)
+           Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+    }
+    ret = arcfour_mic_key(context, &Klocal,
+                         SND_SEQ, 4,
+                         k6_data, sizeof(k6_data));
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    if(conf_flag) {
+       RC4_KEY rc4_key;
+
+       RC4_set_key (&rc4_key, sizeof(k6_data), k6_data);
+       RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */
+       RC4 (&rc4_key, message_buffer->length,
+            message_buffer->value,
+            message_buffer->value);
+       memset(&rc4_key, 0, sizeof(rc4_key));
+    } else {
+       memcpy(Confounder, p0 + 24, 8); /* Confounder */
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    ret = arcfour_mic_cksum(context,
+                           key, KRB5_KU_USAGE_SEAL,
+                           cksum_data, sizeof(cksum_data),
+                           p0, 8,
+                           Confounder, sizeof(Confounder),
+                           associated_data_buffer->value,
+                           associated_data_buffer->length);
+    if (ret) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
+    if (cmp) {
+       *minor_status = 0;
+       return GSS_S_BAD_MIC;
+    }
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    omret = _gssapi_msg_order_check(context_handle->order, seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    if (omret)
+       return omret;
+
+    if (conf_state)
+       *conf_state = conf_flag;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
 static OM_uint32
 max_wrap_length_arcfour(const gsskrb5_ctx ctx,
                        krb5_crypto crypto,
index a73893f11cea59527714a85d1571a2cbcb08dba4..08a65b10df077eb04ff212c25bcfebcb3d0e05aa 100644 (file)
@@ -110,6 +110,17 @@ _gssapi_unwrap_arcfour (
        gss_qop_t */*qop_state*/,
        krb5_keyblock */*key*/);
 
+OM_uint32
+_gssapi_unwrap_ex_arcfour(OM_uint32 *minor_status,
+                               const gsskrb5_ctx context_handle,
+                               krb5_context context,
+                               int *conf_state,
+                               gss_qop_t *qop_state,
+                               krb5_keyblock *key,
+                               const gss_buffer_t token_header_buffer,
+                               const gss_buffer_t associated_data_buffer,
+                               gss_buffer_t message_buffer);
+
 OM_uint32
 _gssapi_unwrap_cfx (
        OM_uint32 */*minor_status*/,
@@ -166,6 +177,18 @@ _gssapi_wrap_arcfour (
        gss_buffer_t /*output_message_buffer*/,
        krb5_keyblock */*key*/);
 
+OM_uint32
+_gssapi_wrap_ex_arcfour(OM_uint32 *minor_status,
+                             const gsskrb5_ctx context_handle,
+                             krb5_context context,
+                             int conf_req_flag,
+                             gss_qop_t qop_req,
+                             int *conf_state,
+                             krb5_keyblock *key,
+                             const gss_buffer_t associated_data_buffer,
+                             gss_buffer_t message_buffer,
+                             gss_buffer_t output_token_buffer);
+
 OM_uint32
 _gssapi_wrap_cfx (
        OM_uint32 */*minor_status*/,
index d108186a97bc48c17daa72309bfd8feb84cc6eaa..0a55e93edd1bbec827b551c0ca24a6ea6b0033a7 100644 (file)
@@ -446,7 +446,37 @@ OM_uint32 _gsskrb5_unwrap_ex
             gss_qop_t * qop_state
            )
 {
-  int no_ex = 1;
+  int no_ex = 0;
+  OM_uint32 minor;
+  krb5_keyblock *key;
+  krb5_context context;
+  OM_uint32 ret;
+  krb5_keytype keytype;
+  gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
+
+  GSSAPI_KRB5_INIT (&context);
+
+  if (qop_state != NULL)
+      *qop_state = GSS_C_QOP_DEFAULT;
+
+  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+  ret = _gsskrb5i_get_token_key(ctx, context, &key);
+  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+  if (ret) {
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (context, key->keytype, &keytype);
+
+  *minor_status = 0;
+
+  switch (keytype) {
+  case KEYTYPE_DES:
+  case KEYTYPE_DES3:
+  default:
+      no_ex = 1;
+      break;
+  }
 
   if (no_ex) {
     OM_uint32 major_status, minor;
@@ -494,6 +524,21 @@ OM_uint32 _gsskrb5_unwrap_ex
     return major_status;
   }
 
-  *minor_status = EINVAL;
-  return GSS_S_FAILURE;
+  switch (keytype) {
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = _gssapi_unwrap_ex_arcfour(minor_status, ctx, context,
+                                     conf_state, qop_state, key,
+                                     token_header_buffer,
+                                     associated_data_buffer,
+                                     message_buffer);
+      break;
+  default:
+      *minor_status = EINVAL;
+      ret = GSS_S_FAILURE;
+      break;
+  }
+
+  krb5_free_keyblock(context, key);
+  return ret;
 }
index 4042cd906ba4700182be84dffbc1e97a92852fca..df58cde6ada97533c87febc8a68e2d994d30a84c 100644 (file)
@@ -579,7 +579,33 @@ OM_uint32 _gsskrb5_wrap_ex
             int * conf_state
            )
 {
-  int no_ex = 1;
+  int no_ex = 0;
+  OM_uint32 minor;
+  krb5_context context;
+  krb5_keyblock *key;
+  OM_uint32 ret;
+  krb5_keytype keytype;
+  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
+
+  GSSAPI_KRB5_INIT (&context);
+
+  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+  ret = _gsskrb5i_get_token_key(ctx, context, &key);
+  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+  if (ret) {
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (context, key->keytype, &keytype);
+
+  switch (keytype) {
+  case KEYTYPE_DES:
+  case KEYTYPE_DES3:
+  default:
+      krb5_free_keyblock (context, key);
+      no_ex = 1;
+      break;
+  }
 
   if (no_ex) {
     OM_uint32 major_status, minor;
@@ -614,6 +640,22 @@ OM_uint32 _gsskrb5_wrap_ex
     return major_status;
   }
 
-  *minor_status = EINVAL;
-  return GSS_S_FAILURE;
+  switch (keytype) {
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = _gssapi_wrap_ex_arcfour(minor_status,
+                                   ctx, context, conf_req_flag,
+                                   qop_req, conf_state, key,
+                                   associated_data_buffer,
+                                   message_buffer,
+                                   output_token_buffer);
+      break;
+  default:
+      *minor_status = EINVAL;
+      ret = GSS_S_FAILURE;
+      break;
+  }
+
+  krb5_free_keyblock(context, key);
+  return ret;
 }