Restore compatibility with KDCs using key usage 8 to encrypt TGS
authorGreg Hudson <ghudson@mit.edu>
Wed, 20 May 2009 02:05:53 +0000 (02:05 +0000)
committerGreg Hudson <ghudson@mit.edu>
Wed, 20 May 2009 02:05:53 +0000 (02:05 +0000)
replies in a subkey, by implementing a fallback in
krb5_arcfour_decrypt.

ticket: 6490

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22357 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/crypto/arcfour/arcfour.c
src/lib/crypto/t_encrypt.c

index 4999982c37dd98b57c869077487afb746cc89a8f..7e527cf89f7cf831069ad0c575a9e8a475d0b84c 100644 (file)
@@ -252,40 +252,57 @@ krb5_arcfour_decrypt(const struct krb5_enc_provider *enc,
   checksum.length=hashsize;
   checksum.data=input->data;
 
-  /* compute the salt */
   ms_usage=krb5int_arcfour_translate_usage(usage);
-  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
-    strncpy(salt.data, krb5int_arcfour_l40, salt.length);
-    store_32_le(ms_usage, salt.data+10);
-  } else {
-    salt.length=4;
-    store_32_le(ms_usage, salt.data);
-  }
-  ret=krb5_hmac(hash, key, 1, &salt, &d1);
-  if (ret)
-    goto cleanup;
 
-  memcpy(k2.contents, k1.contents, k2.length);
-
-  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
-    memset(k1.contents+7, 0xab, 9);
+  /* We may have to try two ms_usage values; see below. */
+  do {
+      /* compute the salt */
+      if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+         strncpy(salt.data, krb5int_arcfour_l40, salt.length);
+         store_32_le(ms_usage, salt.data + 10);
+      } else {
+         salt.length = 4;
+         store_32_le(ms_usage, salt.data);
+      }
+      ret = krb5_hmac(hash, key, 1, &salt, &d1);
+      if (ret)
+         goto cleanup;
+
+      memcpy(k2.contents, k1.contents, k2.length);
+
+      if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+         memset(k1.contents + 7, 0xab, 9);
   
-  ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
-  if (ret)
-    goto cleanup;
-
-  ret=(*(enc->decrypt))(&k3, ivec, &ciphertext, &plaintext);
-  if (ret)
-    goto cleanup;
-
-  ret=krb5_hmac(hash, &k2, 1, &plaintext, &d1);
-  if (ret)
-    goto cleanup;
-
-  if (memcmp(checksum.data, d1.data, hashsize) != 0) {
-    ret=KRB5KRB_AP_ERR_BAD_INTEGRITY;
-    goto cleanup;
-  }
+      ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
+      if (ret)
+         goto cleanup;
+
+      ret = (*(enc->decrypt))(&k3, ivec, &ciphertext, &plaintext);
+      if (ret)
+         goto cleanup;
+
+      ret = krb5_hmac(hash, &k2, 1, &plaintext, &d1);
+      if (ret)
+         goto cleanup;
+
+      if (memcmp(checksum.data, d1.data, hashsize) != 0) {
+         if (ms_usage == 9) {
+             /*
+              * RFC 4757 specifies usage 8 for TGS-REP encrypted
+              * parts encrypted in a subkey, but the value used by MS
+              * is actually 9.  We now use 9 to start with, but fall
+              * back to 8 on failure in case we are communicating
+              * with a KDC using the value from the RFC.
+              */
+             ms_usage = 8;
+             continue;
+         }
+         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+         goto cleanup;
+      }
+
+      break;
+  } while (1);
 
   memcpy(output->data, plaintext.data+CONFOUNDERLENGTH,
         (plaintext.length-CONFOUNDERLENGTH));
index c4ecbdecfb94238948cdaaed57fa9168cf81e45f..974dc585b7ac8e8cd1e1cb1165f59e80780b2860 100644 (file)
@@ -47,14 +47,17 @@ krb5_enctype interesting_enctypes[] = {
   0
 };
 
-#define test(msg, exp) \
-printf ("%s: . . . ", msg); \
-retval = (exp);\
-if( retval) { \
-  printf( "Failed: %s\n", error_message(retval)); \
-  abort(); \
-} else printf ("OK\n");
-  
+static void
+test(const char *msg, krb5_error_code retval)
+{
+    printf("%s: . . . ", msg);
+    if (retval) {
+       printf("Failed: %s\n", error_message(retval));
+       abort();
+    } else
+       printf("OK\n");
+}
+
 static int compare_results(krb5_data *d1, krb5_data *d2)
 {
     if (d1->length != d2->length) {
@@ -186,6 +189,21 @@ main ()
     krb5_free_keyblock (context, key);
   }
 
+  /* Test the RC4 decrypt fallback from key usage 9 to 8. */
+  test ("Initializing an RC4 keyblock",
+       krb5_init_keyblock (context, ENCTYPE_ARCFOUR_HMAC, 0, &key));
+  test ("Generating random RC4 key",
+       krb5_c_make_random_key (context, ENCTYPE_ARCFOUR_HMAC, key));
+  enc_out.ciphertext = out;
+  krb5_c_encrypt_length (context, key->enctype, in.length, &len);
+  enc_out.ciphertext.length = len;
+  check.length = 2048;
+  test ("Encrypting with RC4 key usage 8",
+       krb5_c_encrypt (context, key, 8, 0, &in, &enc_out));
+  test ("Decrypting with RC4 key usage 9",
+       krb5_c_decrypt (context, key, 9, 0, &enc_out, &check));
+  test ("Comparing", compare_results (&in, &check));
+
   free(out.data);
   free(out2.data);
   free(check.data);