gsskrb5: add [un]wrap_ex with des keys
authorStefan Metzmacher <metze@samba.org>
Fri, 8 Aug 2008 14:36:59 +0000 (16:36 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Aug 2008 06:49:05 +0000 (08:49 +0200)
metze

source/heimdal/lib/gssapi/krb5/unwrap.c
source/heimdal/lib/gssapi/krb5/wrap.c

index db7b3972f141fbc3dca1ca6ff63e5594b4fb7bf6..e564a2e0c90de15d1480db723dce0689a5a3ecf2 100644 (file)
@@ -183,6 +183,140 @@ unwrap_des
   return GSS_S_COMPLETE;
 }
 
+static OM_uint32
+unwrap_ex_des
+           (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 *p, *seq;
+  MD5_CTX md5;
+  u_char hash[16];
+  DES_key_schedule schedule;
+  DES_cblock deskey;
+  DES_cblock zero;
+  int i;
+  uint32_t seq_number;
+  OM_uint32 ret;
+  int cstate;
+  int cmp;
+
+  p = token_header_buffer->value;
+  ret = _gsskrb5_verify_header (&p,
+                               token_header_buffer->length,
+                               "\x02\x01",
+                               GSS_KRB5_MECHANISM);
+  if (ret)
+      return ret;
+
+  if (memcmp (p, "\x00\x00", 2) != 0)
+    return GSS_S_BAD_SIG;
+  p += 2;
+  if (memcmp (p, "\x00\x00", 2) == 0) {
+      cstate = 1;
+  } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
+      cstate = 0;
+  } else
+      return GSS_S_BAD_MIC;
+  p += 2;
+  if(conf_state != NULL)
+      *conf_state = cstate;
+  if (memcmp (p, "\xff\xff", 2) != 0)
+    return GSS_S_DEFECTIVE_TOKEN;
+  p += 2;
+  p += 16;
+
+  if(cstate) {
+      uint8_t *e;
+
+      /* decrypt data */
+      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+      for (i = 0; i < sizeof(deskey); ++i)
+         deskey[i] ^= 0xf0;
+      DES_set_key_unchecked (&deskey, &schedule);
+      memset (&zero, 0, sizeof(zero));
+
+      e = malloc(8 + message_buffer->length);
+      if (e == NULL) {
+          *minor_status = ENOMEM;
+          return GSS_S_FAILURE;
+      }
+      memcpy(e, p, 8);
+      memcpy(e + 8, message_buffer->value, message_buffer->length);
+
+      DES_cbc_encrypt ((void *)e,
+                      (void *)e,
+                      8 + message_buffer->length,
+                      &schedule,
+                      &zero,
+                      DES_DECRYPT);
+
+      memcpy(p, e, 8);
+      memcpy(message_buffer->value, e + 8, message_buffer->length);
+      free(e);
+
+      memset (deskey, 0, sizeof(deskey));
+      memset (&schedule, 0, sizeof(schedule));
+  }
+
+  MD5_Init (&md5);
+  MD5_Update (&md5, p - 24, 8);
+  MD5_Update (&md5, p, 8);
+  MD5_Update (&md5, associated_data_buffer->value, associated_data_buffer->length);
+  MD5_Final (hash, &md5);
+
+  memset (&zero, 0, sizeof(zero));
+  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+  DES_set_key_unchecked (&deskey, &schedule);
+  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+                &schedule, &zero);
+  if (memcmp (p - 8, hash, 8) != 0)
+    return GSS_S_BAD_MIC;
+
+  /* verify sequence number */
+
+  HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+
+  p -= 16;
+  DES_set_key_unchecked (&deskey, &schedule);
+  DES_cbc_encrypt ((void *)p, (void *)p, 8,
+                  &schedule, (DES_cblock *)hash, DES_DECRYPT);
+
+  memset (deskey, 0, sizeof(deskey));
+  memset (&schedule, 0, sizeof(schedule));
+
+  seq = p;
+  _gsskrb5_decode_om_uint32(seq, &seq_number);
+
+  if (context_handle->more_flags & LOCAL)
+      cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
+  else
+      cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
+
+  if (cmp != 0) {
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    return GSS_S_BAD_MIC;
+  }
+
+  ret = _gssapi_msg_order_check(context_handle->order, seq_number);
+  if (ret) {
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+    return ret;
+  }
+
+  HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+  return GSS_S_COMPLETE;
+}
+
 static OM_uint32
 unwrap_des3
            (OM_uint32 * minor_status,
@@ -447,7 +581,6 @@ OM_uint32 _gsskrb5_unwrap_ex
            )
 {
   int no_ex = 0;
-  OM_uint32 minor;
   krb5_keyblock *key;
   krb5_context context;
   OM_uint32 ret;
@@ -471,7 +604,6 @@ OM_uint32 _gsskrb5_unwrap_ex
   *minor_status = 0;
 
   switch (keytype) {
-  case KEYTYPE_DES:
   case KEYTYPE_DES3:
       no_ex = 1;
       break;
@@ -526,6 +658,13 @@ OM_uint32 _gsskrb5_unwrap_ex
   }
 
   switch (keytype) {
+  case KEYTYPE_DES:
+      ret = unwrap_ex_des(minor_status, ctx, context,
+                         conf_state, qop_state, key,
+                         token_header_buffer,
+                         associated_data_buffer,
+                         message_buffer);
+      break;
   case KEYTYPE_ARCFOUR:
   case KEYTYPE_ARCFOUR_56:
       ret = _gssapi_unwrap_ex_arcfour(minor_status, ctx, context,
index 539a071c0fe55af741d64047f3aa6d8003533825..6817c75a676b91d5b68cbb615511a880b61bce0b 100644 (file)
@@ -323,6 +323,146 @@ wrap_des
   return GSS_S_COMPLETE;
 }
 
+static OM_uint32
+wrap_ex_des
+           (OM_uint32 *minor_status,
+            const gsskrb5_ctx ctx,
+            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 *p;
+  MD5_CTX md5;
+  u_char hash[16];
+  DES_key_schedule schedule;
+  DES_cblock deskey;
+  DES_cblock zero;
+  int i;
+  int32_t seq_number;
+  size_t len, total_len;
+
+  len = 22 + 8;
+  _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+  output_token_buffer->length = total_len;
+  output_token_buffer->value  = malloc(total_len);
+  if (output_token_buffer->value == NULL) {
+    output_token_buffer->length = 0;
+    *minor_status = ENOMEM;
+    return GSS_S_FAILURE;
+  }
+
+  p = _gsskrb5_make_header(output_token_buffer->value,
+                          len,
+                          "\x02\x01", /* TOK_ID */
+                          GSS_KRB5_MECHANISM);
+
+  /* SGN_ALG */
+  memcpy (p, "\x00\x00", 2);
+  p += 2;
+  /* SEAL_ALG */
+  if(conf_req_flag)
+      memcpy (p, "\x00\x00", 2);
+  else
+      memcpy (p, "\xff\xff", 2);
+  p += 2;
+  /* Filler */
+  memcpy (p, "\xff\xff", 2);
+  p += 2;
+
+  /* fill in later */
+  memset (p, 0, 16);
+  p += 16;
+
+  /* confounder + data + pad */
+  krb5_generate_random_block(p, 8);
+
+  /* checksum */
+  MD5_Init (&md5);
+  MD5_Update (&md5, p - 24, 8);
+  MD5_Update (&md5, p, 8);
+  MD5_Update (&md5, associated_data_buffer->value, associated_data_buffer->length);
+  MD5_Final (hash, &md5);
+
+  memset (&zero, 0, sizeof(zero));
+  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+  DES_set_key_unchecked (&deskey, &schedule);
+  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
+                &schedule, &zero);
+  memcpy (p - 8, hash, 8);
+
+  /* sequence number */
+  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+  krb5_auth_con_getlocalseqnumber (context,
+                                  ctx->auth_context,
+                                  &seq_number);
+
+  p -= 16;
+  p[0] = (seq_number >> 0)  & 0xFF;
+  p[1] = (seq_number >> 8)  & 0xFF;
+  p[2] = (seq_number >> 16) & 0xFF;
+  p[3] = (seq_number >> 24) & 0xFF;
+  memset (p + 4,
+         (ctx->more_flags & LOCAL) ? 0 : 0xFF,
+         4);
+
+  DES_set_key_unchecked (&deskey, &schedule);
+  DES_cbc_encrypt ((void *)p, (void *)p, 8,
+                  &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
+
+  krb5_auth_con_setlocalseqnumber (context,
+                              ctx->auth_context,
+                              ++seq_number);
+  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+
+  /* encrypt the data */
+  p += 16;
+
+  if(conf_req_flag) {
+      uint8_t *e;
+
+      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
+
+      for (i = 0; i < sizeof(deskey); ++i)
+         deskey[i] ^= 0xf0;
+      DES_set_key_unchecked (&deskey, &schedule);
+      memset (&zero, 0, sizeof(zero));
+
+      e = malloc(8 + message_buffer->length);
+      if (e == NULL) {
+          gss_release_buffer(minor_status, output_token_buffer);
+          *minor_status = ENOMEM;
+          return GSS_S_FAILURE;
+      }
+      memcpy(e, p, 8);
+      memcpy(e + 8, message_buffer->value, message_buffer->length);
+
+      DES_cbc_encrypt ((void *)e,
+                      (void *)e,
+                      8 + message_buffer->length,
+                      &schedule,
+                      &zero,
+                      DES_ENCRYPT);
+
+      memcpy(p, e, 8);
+      memcpy(message_buffer->value, e + 8, message_buffer->length);
+      free(e);
+  }
+  memset (deskey, 0, sizeof(deskey));
+  memset (&schedule, 0, sizeof(schedule));
+
+  if(conf_state != NULL)
+      *conf_state = conf_req_flag;
+  *minor_status = 0;
+  return GSS_S_COMPLETE;
+}
+
 static OM_uint32
 wrap_des3
            (OM_uint32 * minor_status,
@@ -580,7 +720,6 @@ OM_uint32 _gsskrb5_wrap_ex
            )
 {
   int no_ex = 0;
-  OM_uint32 minor;
   krb5_context context;
   krb5_keyblock *key;
   OM_uint32 ret;
@@ -599,7 +738,6 @@ OM_uint32 _gsskrb5_wrap_ex
   krb5_enctype_to_keytype (context, key->keytype, &keytype);
 
   switch (keytype) {
-  case KEYTYPE_DES:
   case KEYTYPE_DES3:
       krb5_free_keyblock (context, key);
       no_ex = 1;
@@ -642,6 +780,14 @@ OM_uint32 _gsskrb5_wrap_ex
   }
 
   switch (keytype) {
+  case KEYTYPE_DES:
+      ret = wrap_ex_des(minor_status,
+                       ctx, context, conf_req_flag,
+                       qop_req, conf_state, key,
+                       associated_data_buffer,
+                       message_buffer,
+                       output_token_buffer);
+      break;
   case KEYTYPE_ARCFOUR:
   case KEYTYPE_ARCFOUR_56:
       ret = _gssapi_wrap_ex_arcfour(minor_status,