From d09cf275e3a8d1ccd992a1409d80c5a5b1f9ada2 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Mon, 14 May 2018 13:56:21 +0100 Subject: [PATCH] krb5: Use iovecs for internal checksum handling Modify the signature of the checksum operation in the krb5_checksum_type structure so that it processes iovecs rather than solid blocks of data. Update all of the implementations of these functions for all of the checksum types that we support so that they process iovecs, either by iterating through the iovec in each function, or by calling _krb5_evp_digest_iov or _krb5_evp_hmac_iov() Update callers of these functions so that they turn their single blocks of data into a single iovec of the correct type before calling checksum --- lib/krb5/crypto-aes-sha1.c | 5 +- lib/krb5/crypto-aes-sha2.c | 11 ++-- lib/krb5/crypto-arcfour.c | 10 ++-- lib/krb5/crypto-des-common.c | 17 ++++--- lib/krb5/crypto-des.c | 33 +++++++----- lib/krb5/crypto-des3.c | 11 ++-- lib/krb5/crypto-null.c | 4 +- lib/krb5/crypto.c | 99 +++++++++++++++++++++++++++--------- lib/krb5/crypto.h | 2 +- lib/krb5/pac.c | 7 ++- 10 files changed, 139 insertions(+), 60 deletions(-) diff --git a/lib/krb5/crypto-aes-sha1.c b/lib/krb5/crypto-aes-sha1.c index 30df0ee86b..d07ad0e8b1 100644 --- a/lib/krb5/crypto-aes-sha1.c +++ b/lib/krb5/crypto-aes-sha1.c @@ -92,6 +92,7 @@ AES_SHA1_PRF(krb5_context context, krb5_data *out) { struct _krb5_checksum_type *ct = crypto->et->checksum; + struct krb5_crypto_iov iov[1]; krb5_error_code ret; Checksum result; krb5_keyblock *derived; @@ -103,7 +104,9 @@ AES_SHA1_PRF(krb5_context context, return ret; } - ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result); + iov[0].data = *in; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + ret = (*ct->checksum)(context, NULL, 0, iov, 1, &result); if (ret) { krb5_data_free(&result.checksum); return ret; diff --git a/lib/krb5/crypto-aes-sha2.c b/lib/krb5/crypto-aes-sha2.c index 4630ce0715..c7d8dc10dc 100644 --- a/lib/krb5/crypto-aes-sha2.c +++ b/lib/krb5/crypto-aes-sha2.c @@ -59,9 +59,9 @@ _krb5_aes_sha2_md_for_enctype(krb5_context context, static krb5_error_code SP_HMAC_SHA2_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, - unsigned usage, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *result) { krb5_error_code ret; @@ -73,8 +73,9 @@ SP_HMAC_SHA2_checksum(krb5_context context, if (ret) return ret; - HMAC(md, key->key->keyvalue.data, key->key->keyvalue.length, - data, len, hmac, &hmaclen); + ret = _krb5_evp_hmac_iov(context, key, iov, niov, hmac, &hmaclen, md, NULL); + if (ret) + return ret; heim_assert(result->checksum.length <= hmaclen, "SHA2 internal error"); diff --git a/lib/krb5/crypto-arcfour.c b/lib/krb5/crypto-arcfour.c index c491561c69..dfc5d2f363 100644 --- a/lib/krb5/crypto-arcfour.c +++ b/lib/krb5/crypto-arcfour.c @@ -58,9 +58,9 @@ static struct _krb5_key_type keytype_arcfour = { krb5_error_code _krb5_HMAC_MD5_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *result) { EVP_MD_CTX *m; @@ -73,6 +73,7 @@ _krb5_HMAC_MD5_checksum(krb5_context context, unsigned char tmp[16]; unsigned char ksign_c_data[16]; krb5_error_code ret; + int i; m = EVP_MD_CTX_create(); if (m == NULL) @@ -93,7 +94,10 @@ _krb5_HMAC_MD5_checksum(krb5_context context, t[2] = (usage >> 16) & 0xFF; t[3] = (usage >> 24) & 0xFF; EVP_DigestUpdate(m, t, 4); - EVP_DigestUpdate(m, data, len); + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length); + } EVP_DigestFinal_ex (m, tmp, NULL); EVP_MD_CTX_destroy(m); diff --git a/lib/krb5/crypto-des-common.c b/lib/krb5/crypto-des-common.c index 95f6389d1e..c85bd24335 100644 --- a/lib/krb5/crypto-des-common.c +++ b/lib/krb5/crypto-des-common.c @@ -57,13 +57,14 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL _krb5_des_checksum(krb5_context context, const EVP_MD *evp_md, struct _krb5_key_data *key, - const void *data, - size_t len, + const struct krb5_crypto_iov *iov, + int niov, Checksum *cksum) { struct _krb5_evp_schedule *ctx = key->schedule->data; EVP_MD_CTX *m; DES_cblock ivec; + int i; unsigned char *p = cksum->checksum.data; krb5_generate_random_block(p, 8); @@ -74,7 +75,10 @@ _krb5_des_checksum(krb5_context context, EVP_DigestInit_ex(m, evp_md, NULL); EVP_DigestUpdate(m, p, 8); - EVP_DigestUpdate(m, data, len); + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length); + } EVP_DigestFinal_ex (m, p + 8, NULL); EVP_MD_CTX_destroy(m); memset_s(&ivec, sizeof(ivec), 0, sizeof(ivec)); @@ -126,13 +130,14 @@ _krb5_des_verify(krb5_context context, static krb5_error_code RSA_MD5_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { - if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_md5(), NULL) != 1) + if (_krb5_evp_digest_iov(iov, niov, C->checksum.data, NULL, EVP_md5(), NULL) != 1) krb5_abortx(context, "md5 checksum failed"); + return 0; } diff --git a/lib/krb5/crypto-des.c b/lib/krb5/crypto-des.c index 8ea145b56d..017ce106fc 100644 --- a/lib/krb5/crypto-des.c +++ b/lib/krb5/crypto-des.c @@ -99,15 +99,22 @@ static struct _krb5_key_type keytype_des = { static krb5_error_code CRC32_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { - uint32_t crc; + uint32_t crc = 0; unsigned char *r = C->checksum.data; + int i; + _krb5_crc_init_table (); - crc = _krb5_crc_update (data, len, 0); + + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i])) + crc = _krb5_crc_update(iov[i].data.data, iov[i].data.length, crc); + } + r[0] = crc & 0xff; r[1] = (crc >> 8) & 0xff; r[2] = (crc >> 16) & 0xff; @@ -118,12 +125,12 @@ CRC32_checksum(krb5_context context, static krb5_error_code RSA_MD4_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { - if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_md4(), NULL) != 1) + if (_krb5_evp_digest_iov(iov, niov, C->checksum.data, NULL, EVP_md4(), NULL) != 1) krb5_abortx(context, "md4 checksum failed"); return 0; } @@ -131,12 +138,12 @@ RSA_MD4_checksum(krb5_context context, static krb5_error_code RSA_MD4_DES_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *cksum) { - return _krb5_des_checksum(context, EVP_md4(), key, data, len, cksum); + return _krb5_des_checksum(context, EVP_md4(), key, iov, niov, cksum); } static krb5_error_code @@ -153,12 +160,12 @@ RSA_MD4_DES_verify(krb5_context context, static krb5_error_code RSA_MD5_DES_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { - return _krb5_des_checksum(context, EVP_md5(), key, data, len, C); + return _krb5_des_checksum(context, EVP_md5(), key, iov, niov, C); } static krb5_error_code diff --git a/lib/krb5/crypto-des3.c b/lib/krb5/crypto-des3.c index ed3e7c960e..36174ff7fb 100644 --- a/lib/krb5/crypto-des3.c +++ b/lib/krb5/crypto-des3.c @@ -59,6 +59,7 @@ DES3_prf(krb5_context context, krb5_data *out) { struct _krb5_checksum_type *ct = crypto->et->checksum; + struct krb5_crypto_iov iov[1]; krb5_error_code ret; Checksum result; krb5_keyblock *derived; @@ -70,7 +71,9 @@ DES3_prf(krb5_context context, return ret; } - ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result); + iov[0].data = *in; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + ret = (*ct->checksum)(context, NULL, 0, iov, 1, &result); if (ret) { krb5_data_free(&result.checksum); return ret; @@ -140,12 +143,12 @@ static struct _krb5_key_type keytype_des3_derived = { static krb5_error_code RSA_MD5_DES3_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { - return _krb5_des_checksum(context, EVP_md5(), key, data, len, C); + return _krb5_des_checksum(context, EVP_md5(), key, iov, niov, C); } static krb5_error_code diff --git a/lib/krb5/crypto-null.c b/lib/krb5/crypto-null.c index 96b7799470..8aca50239d 100644 --- a/lib/krb5/crypto-null.c +++ b/lib/krb5/crypto-null.c @@ -54,9 +54,9 @@ static struct _krb5_key_type keytype_null = { static krb5_error_code NONE_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { return 0; diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index 8afcc0eb2c..04ace41511 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -166,48 +166,62 @@ _key_schedule(krb5_context context, static krb5_error_code SHA1_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *C) { - if (EVP_Digest(data, len, C->checksum.data, NULL, EVP_sha1(), NULL) != 1) + if (_krb5_evp_digest_iov(iov, niov, C->checksum.data, + NULL, EVP_sha1(), NULL) != 1) krb5_abortx(context, "sha1 checksum failed"); + return 0; } /* HMAC according to RFC2104 */ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_internal_hmac(krb5_context context, - struct _krb5_checksum_type *cm, - const void *data, - size_t len, - unsigned usage, - struct _krb5_key_data *keyblock, - Checksum *result) +_krb5_internal_hmac_iov(krb5_context context, + struct _krb5_checksum_type *cm, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + struct _krb5_key_data *keyblock, + Checksum *result) { unsigned char *ipad, *opad; unsigned char *key; + struct krb5_crypto_iov *working; size_t key_len; size_t i; - ipad = malloc(cm->blocksize + len); + ipad = malloc(cm->blocksize); if (ipad == NULL) return ENOMEM; + opad = malloc(cm->blocksize + cm->checksumsize); if (opad == NULL) { free(ipad); return ENOMEM; } + + working = calloc(niov + 1, sizeof(struct krb5_crypto_iov)); + if (working == NULL) { + free(ipad); + free(opad); + return ENOMEM; + } + memset(ipad, 0x36, cm->blocksize); memset(opad, 0x5c, cm->blocksize); if(keyblock->key->keyvalue.length > cm->blocksize){ + working[0].data = keyblock->key->keyvalue; + working[0].flags = KRB5_CRYPTO_TYPE_DATA; (*cm->checksum)(context, keyblock, - keyblock->key->keyvalue.data, - keyblock->key->keyvalue.length, usage, + working, + 1, result); key = result->checksum.data; key_len = result->checksum.length; @@ -219,21 +233,48 @@ _krb5_internal_hmac(krb5_context context, ipad[i] ^= key[i]; opad[i] ^= key[i]; } - memcpy(ipad + cm->blocksize, data, len); - (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len, - usage, result); + + working[0].data.data = ipad; + working[0].data.length = cm->blocksize; + working[0].flags = KRB5_CRYPTO_TYPE_DATA; + for (i = 0; i < niov; i++) + working[i + 1] = iov[i]; + + (*cm->checksum)(context, keyblock, usage, working, niov + 1, result); memcpy(opad + cm->blocksize, result->checksum.data, result->checksum.length); - (*cm->checksum)(context, keyblock, opad, - cm->blocksize + cm->checksumsize, usage, result); - memset(ipad, 0, cm->blocksize + len); + + working[0].data.data = opad; + working[0].data.length = cm->blocksize + cm->checksumsize; + working[0].flags = KRB5_CRYPTO_TYPE_DATA; + (*cm->checksum)(context, keyblock, usage, working, 1, result); + memset(ipad, 0, cm->blocksize); free(ipad); memset(opad, 0, cm->blocksize + cm->checksumsize); free(opad); + free(working); return 0; } +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_internal_hmac(krb5_context context, + struct _krb5_checksum_type *cm, + const void *data, + size_t len, + unsigned usage, + struct _krb5_key_data *keyblock, + Checksum *result) +{ + struct krb5_crypto_iov iov[1]; + + iov[0].data.data = (void *) data; + iov[0].data.length = len; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + return _krb5_internal_hmac_iov(context, cm, usage, iov, 1, + keyblock, result); +} + KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_hmac(krb5_context context, krb5_cksumtype cktype, @@ -268,9 +309,9 @@ krb5_hmac(krb5_context context, krb5_error_code _krb5_SP_HMAC_SHA1_checksum(krb5_context context, struct _krb5_key_data *key, - const void *data, - size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, Checksum *result) { struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); @@ -281,7 +322,7 @@ _krb5_SP_HMAC_SHA1_checksum(krb5_context context, res.checksum.data = sha1_data; res.checksum.length = sizeof(sha1_data); - ret = _krb5_internal_hmac(context, c, data, len, usage, key, &res); + ret = _krb5_internal_hmac_iov(context, c, usage, iov, niov, key, &res); if (ret) krb5_abortx(context, "hmac failed"); memcpy(result->checksum.data, res.checksum.data, result->checksum.length); @@ -367,6 +408,7 @@ create_checksum (krb5_context context, { krb5_error_code ret; struct _krb5_key_data *dkey; + struct krb5_crypto_iov iov[1]; if (ct->flags & F_DISABLED) { krb5_clear_error_message (context); @@ -382,7 +424,11 @@ create_checksum (krb5_context context, ret = krb5_data_alloc(&result->checksum, ct->checksumsize); if (ret) return (ret); - return (*ct->checksum)(context, dkey, data, len, usage, result); + + iov[0].data.data = data; + iov[0].data.length = len; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + return (*ct->checksum)(context, dkey, usage, iov, 1, result); } static int @@ -442,6 +488,7 @@ verify_checksum(krb5_context context, struct _krb5_key_data *dkey; Checksum c; struct _krb5_checksum_type *ct; + struct krb5_crypto_iov iov[1]; ct = _krb5_find_checksum(cksum->cksumtype); if (ct == NULL || (ct->flags & F_DISABLED)) { @@ -472,6 +519,10 @@ verify_checksum(krb5_context context, * calling ->checksum and then compare result. */ + iov[0].data.data = data; + iov[0].data.length = len; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + if(ct->verify) { ret = (*ct->verify)(context, dkey, data, len, usage, cksum); if (ret) @@ -486,7 +537,7 @@ verify_checksum(krb5_context context, if (ret) return ret; - ret = (*ct->checksum)(context, dkey, data, len, usage, &c); + ret = (*ct->checksum)(context, dkey, usage, iov, 1, &c); if (ret) { krb5_data_free(&c.checksum); return ret; diff --git a/lib/krb5/crypto.h b/lib/krb5/crypto.h index 62f48395a1..f1ed1a5a33 100644 --- a/lib/krb5/crypto.h +++ b/lib/krb5/crypto.h @@ -98,8 +98,8 @@ struct _krb5_checksum_type { unsigned flags; krb5_error_code (*checksum)(krb5_context context, struct _krb5_key_data *key, - const void *buf, size_t len, unsigned usage, + const struct krb5_crypto_iov *iov, int niov, Checksum *csum); krb5_error_code (*verify)(krb5_context context, struct _krb5_key_data *key, diff --git a/lib/krb5/pac.c b/lib/krb5/pac.c index 8ad510998b..1788b59bd5 100644 --- a/lib/krb5/pac.c +++ b/lib/krb5/pac.c @@ -88,6 +88,7 @@ HMAC_MD5_any_checksum(krb5_context context, Checksum *result) { struct _krb5_key_data local_key; + struct krb5_crypto_iov iov; krb5_error_code ret; memset(&local_key, 0, sizeof(local_key)); @@ -103,7 +104,11 @@ HMAC_MD5_any_checksum(krb5_context context, } result->cksumtype = CKSUMTYPE_HMAC_MD5; - ret = _krb5_HMAC_MD5_checksum(context, &local_key, data, len, usage, result); + iov.data.data = (void *)data; + iov.data.length = len; + iov.flags = KRB5_CRYPTO_TYPE_DATA; + + ret = _krb5_HMAC_MD5_checksum(context, &local_key, usage, &iov, 1, result); if (ret) krb5_data_free(&result->checksum);