From 76f7b88f93dde7880b274bc0691b8d9d5763f627 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 20 Sep 2026 13:54:45 +0100 Subject: [PATCH] [crypto] Allow for signable MD5 or SHA-1 digests with TLS version 1.1 For TLS version 1.1, non-RSA signed digests use SHA-1 instead of MD5+SHA1. Commit f095adb ("[tls] Use SHA-1 for TLS version 1.1 ECDSA signatures") selected the correct digest algorithm for both server and client authentication. However, the key schedule currently refuses to generate client CertificateVerify digests for any digest algorithm other than MD5+SHA1, on the basis that only the MD5+SHA1 running transcript digest value is available. An MD5+SHA1 digest value is just the concatenation of an MD5 digest value with a SHA-1 digest value, and so the SHA-1 digest value can be provided for use with ECDSA client certificates. Fix by special-casing the SHA-1 (and MD5) algorithms when generating a signable digest value from the TLS version 1.1 key schedule. Signed-off-by: Michael Brown --- src/crypto/tlskey.c | 57 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/crypto/tlskey.c b/src/crypto/tlskey.c index b17284537..10b783685 100644 --- a/src/crypto/tlskey.c +++ b/src/crypto/tlskey.c @@ -1970,6 +1970,61 @@ static int tlskey_md5_sha1_apply ( struct tls_key_schedule *tlskey, return 0; } +/** + * Generate signable digest value + * + * @v tlskey Key schedule + * @v end Endpoint + * @v digest Signature digest algorithm + * @v data Additional data + * @v len Length of additional data + * @v tbs Signable digest value to fill in + * @ret rc Return status code + */ +static int tlskey_md5_sha1_tbshash ( struct tls_key_schedule *tlskey, + const struct tls_endpoint *end, + struct digest_algorithm *digest, + const void *data, size_t len, + void *tbs ) { + struct md5_sha1_digest *running = tlskey->transcript.running; + const void *hash; + + /* The client CertificateVerify digest value is the raw + * transcript digest. We retain an MD5+SHA1 transcript + * digest, which is the concatenation of the MD5 and SHA-1 + * transcript digests. We can therefore provide a signable + * digest value for MD5 or SHA-1 as well as for MD5+SHA1. + */ + if ( ( end->index == TLS_CLIENT ) && ( digest != tlskey->digest ) ) { + + /* Locate MD5 or SHA-1 portion */ + if ( digest == &md5_algorithm ) { + hash = running->md5; + } else if ( digest == &sha1_algorithm ) { + hash = running->sha1; + } else { + DBGC ( tlskey, "TLSKEY %p cannot generate %s " + "transcript digest\n", tlskey, digest->name ); + return -ENOTSUP; + } + + /* There is no way to incorporate additional data */ + if ( len ) { + DBGC ( tlskey, "TLSKEY %p cannot generate digest " + "with additional data\n", tlskey ); + return -ENOTSUP; + } + + /* Copy transcript digest value */ + memcpy ( tbs, hash, digest->digestsize ); + + return 0; + } + + /* Otherwise, generate MD5+SHA1 signable digest value */ + return tlskey_hash_tbshash ( tlskey, end, digest, data, len, tbs ); +} + /** * Save pre-shared key * @@ -2023,7 +2078,7 @@ const struct tls_key_schedule_operations tlskey_md5_sha1 = { .verify = tlskey_hash_verify, .traffic = tlskey_hash_traffic, .cipher = tlskey_hash_cipher, - .tbshash = tlskey_hash_tbshash, + .tbshash = tlskey_md5_sha1_tbshash, .save = tlskey_md5_sha1_save, .load = tlskey_hash_load, .bind = tlskey_hash_bind,