Pullup to 1.7-branch is only for the test case, as krb5-1.7 behaved
authorTom Yu <tlyu@mit.edu>
Thu, 26 Nov 2009 03:54:59 +0000 (03:54 +0000)
committerTom Yu <tlyu@mit.edu>
Thu, 26 Nov 2009 03:54:59 +0000 (03:54 +0000)
correctly for these checksums.

Fix regression in MD4-DES and MD5-DES keyed checksums.  The original
key was being used for the DES encryption, not the "xorkey".  (key
with each byte XORed with 0xf0)

Add a test case that will catch future regressions of this sort, by
including a verification of a "known-good" checksum (derived from a
known-to-be-interoperable version of the implementation).

ticket: 6584
target_version: 1.7.1
tags: pullup

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

src/lib/crypto/crypto_tests/Makefile.in
src/lib/crypto/crypto_tests/t_cksum.c
src/lib/crypto/krb/keyhash_provider/k5_md4des.c
src/lib/crypto/krb/keyhash_provider/k5_md5des.c

index 6e38506b56a582ea6f87be66bf635bf1b52c987f..ae0a5223bc7846247546774f68c52129feb5bd8f 100644 (file)
@@ -37,6 +37,9 @@ EXTRADEPSRCS=\
 
 ##DOS##LIBOBJS = $(OBJS)
 
+# NOTE: The t_cksum known checksum values are primarily for regression
+# testing.  They are not derived a priori, but are known to produce
+# checksums that interoperate.
 check-unix:: t_nfold t_encrypt t_prf t_prng t_hmac \
                t_cksum4 t_cksum5 \
                aes-test  \
@@ -49,8 +52,8 @@ check-unix:: t_nfold t_encrypt t_prf t_prng t_hmac \
        $(RUN_SETUP) $(VALGRIND) ./t_hmac
        $(RUN_SETUP) $(VALGRIND) ./t_prf <$(srcdir)/t_prf.in >t_prf.output
        diff t_prf.output $(srcdir)/t_prf.expected
-       $(RUN_SETUP) $(VALGRIND) ./t_cksum4 "this is a test"
-       $(RUN_SETUP) $(VALGRIND) ./t_cksum5 "this is a test"
+       $(RUN_SETUP) $(VALGRIND) ./t_cksum4 "this is a test" e3f76a07f3401e3536b43a3f54226c39422c35682c354835
+       $(RUN_SETUP) $(VALGRIND) ./t_cksum5 "this is a test" e3f76a07f3401e351143ee6f4c09be1edb4264d55015db53
        $(RUN_SETUP) $(VALGRIND) ./t_crc
        $(RUN_SETUP) $(VALGRIND) ./t_cts
        $(RUN_SETUP) $(VALGRIND) ./aes-test -k > vk.txt
index a544d9ee8758ece3c87e28b6eb5e9c603be07c02..5fab8695b5effffa4adfe0dcc9befdfd2b020cf4 100644 (file)
@@ -59,6 +59,27 @@ print_checksum(text, number, message, checksum)
   printf("\n");
 }
 
+static void
+parse_hexstring(const char *s, krb5_data *dat)
+{
+  size_t i, len;
+  unsigned int byte;
+  unsigned char *cp;
+
+  len = strlen(s);
+  cp = malloc(len / 2);
+  dat->data = (char *)cp;
+  if (cp == NULL) {
+    dat->length = 0;
+    return;
+  }
+  dat->length = len / 2;
+  for (i = 0; i + 1 < len; i += 2) {
+    sscanf(&s[i], "%2x", &byte);
+    *cp++ = byte;
+  }
+}
+
 /*
  * Test the checksum verification of Old Style (tm) and correct RSA-MD[4,5]-DES
  * checksums.
@@ -77,7 +98,7 @@ main(argc, argv)
   krb5_keyblock                keyblock;
   krb5_key             key;
   krb5_error_code      kret=0;
-  krb5_data            plaintext, newstyle_checksum;
+  krb5_data            plaintext, newstyle_checksum, knowncksum_dat;
 
   /* this is a terrible seed, but that's ok for the test. */
 
@@ -101,7 +122,7 @@ main(argc, argv)
     printf("cannot get memory for new style checksum\n");
     return(ENOMEM);
   }
-  for (msgindex = 1; msgindex < argc; msgindex++) {
+  for (msgindex = 1; msgindex + 1 < argc; msgindex += 2) {
     plaintext.length = strlen(argv[msgindex]);
     plaintext.data = argv[msgindex];
 
@@ -118,6 +139,7 @@ main(argc, argv)
     }
     if (!valid) {
       printf("verify on new checksum failed\n");
+      kret = 1;
       break;
     }
     printf("Verify succeeded for \"%s\"\n", argv[msgindex]);
@@ -130,14 +152,32 @@ main(argc, argv)
     }
     if (valid) {
       printf("verify on new checksum succeeded, but shouldn't have\n");
+      kret = 1;
       break;
     }
     printf("Verify of bad checksum OK for \"%s\"\n", argv[msgindex]);
+    parse_hexstring(argv[msgindex+1], &knowncksum_dat);
+    if (knowncksum_dat.data == NULL) {
+      printf("parse_hexstring failed\n");
+      kret = 1;
+      break;
+    }
+    if ((kret = (*(khp.verify))(key, 0, 0, &plaintext, &knowncksum_dat,
+                               &valid))) {
+      printf("verify on known checksum choked with %d\n", kret);
+      break;
+    }
+    if (!valid) {
+      printf("verify on known checksum failed\n");
+      kret = 1;
+      break;
+    }
+    printf("Verify on known checksum succeeded\n");
     kret = 0;
   }
   free(newstyle_checksum.data);
   if (!kret)
-    printf("%d tests passed successfully for MD%d checksum\n", argc-1, MD);
+    printf("%d tests passed successfully for MD%d checksum\n", (argc-1)/2, MD);
 
   krb5_k_free_key(NULL, key);
 
index ef10a68983df38cf2b5fef4ca545843350ef2a7e..89d97f7bfbf3a4c49cc1ac247e57993a89f66a32 100644 (file)
 
 extern struct krb5_enc_provider krb5int_enc_des;
 
+/* Derive a key by XOR with 0xF0 bytes. */
+static krb5_error_code
+mk_xorkey(krb5_key origkey, krb5_key *xorkey)
+{
+    krb5_error_code retval = 0;
+    unsigned char xorbytes[8];
+    krb5_keyblock xorkeyblock;
+    size_t i = 0;
+
+    if (origkey->keyblock.length != sizeof(xorbytes))
+       return KRB5_CRYPTO_INTERNAL;
+    memcpy(xorbytes, origkey->keyblock.contents, sizeof(xorbytes));
+    for (i = 0; i < sizeof(xorbytes); i++)
+       xorbytes[i] ^= 0xf0;
+
+    /* Do a shallow copy here. */
+    xorkeyblock = origkey->keyblock;
+    xorkeyblock.contents = xorbytes;
+
+    retval = krb5_k_create_key(0, &xorkeyblock, xorkey);
+    zap(xorbytes, sizeof(xorbytes));
+    return retval;
+}
+
 static krb5_error_code
 k5_md4des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
               const krb5_data *input, krb5_data *output)
@@ -46,6 +70,7 @@ k5_md4des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     krb5_data data;
     krb5_MD4_CTX ctx;
     unsigned char conf[CONFLENGTH];
+    krb5_key xorkey = NULL;
     struct krb5_enc_provider *enc = &krb5int_enc_des;
 
     if (output->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH))
@@ -58,6 +83,10 @@ k5_md4des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &data)))
        return(ret);
 
+    ret = mk_xorkey(key, &xorkey);
+    if (ret)
+       return ret;
+
     /* hash the confounder, then the input data */
 
     krb5int_MD4Init(&ctx);
@@ -71,7 +100,9 @@ k5_md4des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     memcpy(output->data, conf, CONFLENGTH);
     memcpy(output->data+CONFLENGTH, ctx.digest, RSA_MD4_CKSUM_LENGTH);
 
-    ret = enc->encrypt(key, NULL, output, output);
+    ret = enc->encrypt(xorkey, NULL, output, output);
+
+    krb5_k_free_key(NULL, xorkey);
 
     return (ret);
 }
@@ -85,10 +116,14 @@ k5_md4des_verify(krb5_key key, krb5_keyusage usage,
     krb5_error_code ret;
     krb5_MD4_CTX ctx;
     unsigned char plaintext[CONFLENGTH+RSA_MD4_CKSUM_LENGTH];
+    krb5_key xorkey = NULL;
     int compathash = 0;
     struct krb5_enc_provider *enc = &krb5int_enc_des;
     krb5_data output, iv;
 
+    iv.data = NULL;
+    iv.length = 0;
+
     if (key->keyblock.length != 8)
        return(KRB5_BAD_KEYSIZE);
     if (hash->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH)) {
@@ -109,20 +144,23 @@ k5_md4des_verify(krb5_key key, krb5_keyusage usage,
         iv.length = key->keyblock.length;
         if (key->keyblock.contents)
             memcpy(iv.data, key->keyblock.contents, key->keyblock.length);
+    } else {
+       ret = mk_xorkey(key, &xorkey);
+       if (ret)
+         return ret;
     }
 
     /* decrypt it */
-    output.data = plaintext;
+    output.data = (char *)plaintext;
     output.length = hash->length;
 
     if (!compathash) {
-        ret = enc->decrypt(key, NULL, hash, &output);
+        ret = enc->decrypt(xorkey, NULL, hash, &output);
+       krb5_k_free_key(NULL, xorkey);
     } else {
         ret = enc->decrypt(key, &iv, hash, &output);
-    }
-
-    if (compathash && iv.data) {
-        free (iv.data);
+       zap(iv.data, iv.length);
+        free(iv.data);
     }
 
     if (ret) return(ret);
index eb189c26af298e29594a949517f509fcdc910acd..4a3d623ac5b43699de31e90db4bc4b8d826e7144 100644 (file)
 
 extern struct krb5_enc_provider krb5int_enc_des;
 
+/* Derive a key by XOR with 0xF0 bytes. */
+static krb5_error_code
+mk_xorkey(krb5_key origkey, krb5_key *xorkey)
+{
+    krb5_error_code retval = 0;
+    unsigned char xorbytes[8];
+    krb5_keyblock xorkeyblock;
+    size_t i = 0;
+
+    if (origkey->keyblock.length != sizeof(xorbytes))
+       return KRB5_CRYPTO_INTERNAL;
+    memcpy(xorbytes, origkey->keyblock.contents, sizeof(xorbytes));
+    for (i = 0; i < sizeof(xorbytes); i++)
+       xorbytes[i] ^= 0xf0;
+
+    /* Do a shallow copy here. */
+    xorkeyblock = origkey->keyblock;
+    xorkeyblock.contents = xorbytes;
+
+    retval = krb5_k_create_key(0, &xorkeyblock, xorkey);
+    zap(xorbytes, sizeof(xorbytes));
+    return retval;
+}
+
 static krb5_error_code
 k5_md5des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
               const krb5_data *input, krb5_data *output)
@@ -46,6 +70,7 @@ k5_md5des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     krb5_data data;
     krb5_MD5_CTX ctx;
     unsigned char conf[CONFLENGTH];
+    krb5_key xorkey = NULL;
     struct krb5_enc_provider *enc = &krb5int_enc_des;
 
     if (output->length != (CONFLENGTH+RSA_MD5_CKSUM_LENGTH))
@@ -58,6 +83,10 @@ k5_md5des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &data)))
        return(ret);
 
+    ret = mk_xorkey(key, &xorkey);
+    if (ret)
+       return ret;
+
     /* hash the confounder, then the input data */
 
     krb5int_MD5Init(&ctx);
@@ -71,7 +100,9 @@ k5_md5des_hash(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     memcpy(output->data, conf, CONFLENGTH);
     memcpy(output->data+CONFLENGTH, ctx.digest, RSA_MD5_CKSUM_LENGTH);
 
-    ret = enc->encrypt(key, NULL, output, output);
+    ret = enc->encrypt(xorkey, NULL, output, output);
+
+    krb5_k_free_key(NULL, xorkey);
 
     return ret;
 
@@ -85,10 +116,14 @@ k5_md5des_verify(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
     krb5_error_code ret;
     krb5_MD5_CTX ctx;
     unsigned char plaintext[CONFLENGTH+RSA_MD5_CKSUM_LENGTH];
+    krb5_key xorkey = NULL;
     int compathash = 0;
     struct krb5_enc_provider *enc = &krb5int_enc_des;
     krb5_data output, iv;
 
+    iv.data = NULL;
+    iv.length = 0;
+
     if (key->keyblock.length != 8)
        return(KRB5_BAD_KEYSIZE);
 
@@ -109,20 +144,23 @@ k5_md5des_verify(krb5_key key, krb5_keyusage usage, const krb5_data *ivec,
         iv.length = key->keyblock.length;
         if (key->keyblock.contents)
             memcpy(iv.data, key->keyblock.contents, key->keyblock.length);
+    } else {
+       ret = mk_xorkey(key, &xorkey);
+       if (ret)
+         return ret;
     }
 
     /* decrypt it */
-    output.data = plaintext;
+    output.data = (char *)plaintext;
     output.length = hash->length;
 
     if (!compathash) {
-        ret = enc->decrypt(key, NULL, hash, &output);
+        ret = enc->decrypt(xorkey, NULL, hash, &output);
+       krb5_k_free_key(NULL, xorkey);
     } else {
         ret = enc->decrypt(key, &iv, hash, &output);
-    }
-
-    if (compathash && iv.data) {
-        free (iv.data);
+       zap(iv.data, iv.length);
+        free(iv.data);
     }
 
     if (ret) return(ret);