From: Tom Yu Date: Thu, 26 Nov 2009 03:54:59 +0000 (+0000) Subject: Pullup to 1.7-branch is only for the test case, as krb5-1.7 behaved X-Git-Tag: krb5-1.8-alpha1~143 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ad2adb977e00181627be7c9a4980b4015fd58fa6;p=krb5.git Pullup to 1.7-branch is only for the test case, as krb5-1.7 behaved 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 --- diff --git a/src/lib/crypto/crypto_tests/Makefile.in b/src/lib/crypto/crypto_tests/Makefile.in index 6e38506b5..ae0a5223b 100644 --- a/src/lib/crypto/crypto_tests/Makefile.in +++ b/src/lib/crypto/crypto_tests/Makefile.in @@ -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 diff --git a/src/lib/crypto/crypto_tests/t_cksum.c b/src/lib/crypto/crypto_tests/t_cksum.c index a544d9ee8..5fab8695b 100644 --- a/src/lib/crypto/crypto_tests/t_cksum.c +++ b/src/lib/crypto/crypto_tests/t_cksum.c @@ -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); diff --git a/src/lib/crypto/krb/keyhash_provider/k5_md4des.c b/src/lib/crypto/krb/keyhash_provider/k5_md4des.c index ef10a6898..89d97f7bf 100644 --- a/src/lib/crypto/krb/keyhash_provider/k5_md4des.c +++ b/src/lib/crypto/krb/keyhash_provider/k5_md4des.c @@ -38,6 +38,30 @@ 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); diff --git a/src/lib/crypto/krb/keyhash_provider/k5_md5des.c b/src/lib/crypto/krb/keyhash_provider/k5_md5des.c index eb189c26a..4a3d623ac 100644 --- a/src/lib/crypto/krb/keyhash_provider/k5_md5des.c +++ b/src/lib/crypto/krb/keyhash_provider/k5_md5des.c @@ -38,6 +38,30 @@ 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);