forked from wolfSSL/wolfssl
Merge pull request #3472 from SparkiDev/pickhashsigalgo_rework
TLS PickHashSigAlgo: rework
This commit is contained in:
213
src/internal.c
213
src/internal.c
@@ -19604,138 +19604,181 @@ int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites, const char* list)
|
|||||||
|
|
||||||
|
|
||||||
#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS)
|
#if !defined(NO_WOLFSSL_SERVER) || !defined(NO_CERTS)
|
||||||
|
static int MatchSigAlgo(WOLFSSL* ssl, int sigAlgo)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_ED25519
|
||||||
|
if (ssl->pkCurveOID == ECC_ED25519_OID) {
|
||||||
|
/* Certificate has Ed25519 key, only match with Ed25519 sig alg */
|
||||||
|
return sigAlgo == ed25519_sa_algo;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_ED448
|
||||||
|
if (ssl->pkCurveOID == ECC_ED448_OID) {
|
||||||
|
/* Certificate has Ed448 key, only match with Ed448 sig alg */
|
||||||
|
return sigAlgo == ed448_sa_algo;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef WC_RSA_PSS
|
||||||
|
/* RSA certificate and PSS sig alg. */
|
||||||
|
if (ssl->suites->sigAlgo == rsa_sa_algo) {
|
||||||
|
#if defined(WOLFSSL_TLS13)
|
||||||
|
/* TLS 1.3 only supports RSA-PSS. */
|
||||||
|
if (IsAtLeastTLSv1_3(ssl->version))
|
||||||
|
return sigAlgo == rsa_pss_sa_algo;
|
||||||
|
#endif
|
||||||
|
/* TLS 1.2 and below - RSA-PSS allowed. */
|
||||||
|
if (sigAlgo == rsa_pss_sa_algo)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* Signature algorithm matches certificate. */
|
||||||
|
return sigAlgo == ssl->suites->sigAlgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_ECC) && defined(WOLFSSL_TLS13) || \
|
||||||
|
defined(USE_ECDSA_KEYSZ_HASH_ALGO)
|
||||||
|
static int CmpEccStrength(int hashAlgo, int curveSz)
|
||||||
|
{
|
||||||
|
int dgstSz = GetMacDigestSize(hashAlgo);
|
||||||
|
if (dgstSz <= 0)
|
||||||
|
return -1;
|
||||||
|
return dgstSz - (curveSz & (~0x3));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static byte MinHashAlgo(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
#ifdef WOLFSSL_TLS13
|
||||||
|
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||||
|
return sha256_mac;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_ALLOW_TLS_SHA1)
|
||||||
|
if (IsAtLeastTLSv1_2(ssl)) {
|
||||||
|
return sha256_mac;
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_NO_TLS12 */
|
||||||
|
return sha_mac;
|
||||||
|
}
|
||||||
|
|
||||||
int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz)
|
int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz)
|
||||||
{
|
{
|
||||||
word32 i;
|
word32 i;
|
||||||
int ret = MATCH_SUITE_ERROR;
|
int ret = MATCH_SUITE_ERROR;
|
||||||
|
byte minHash;
|
||||||
ssl->suites->sigAlgo = ssl->specs.sig_algo;
|
|
||||||
|
|
||||||
/* set defaults */
|
/* set defaults */
|
||||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||||
ssl->suites->hashAlgo = sha256_mac;
|
|
||||||
#ifndef NO_CERTS
|
#ifndef NO_CERTS
|
||||||
|
/* TLS 1.3 cipher suites don't have public key algorithms in them.
|
||||||
|
* Using the one in the certificate - if any.
|
||||||
|
*/
|
||||||
ssl->suites->sigAlgo = ssl->buffers.keyType;
|
ssl->suites->sigAlgo = ssl->buffers.keyType;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifndef WOLFSSL_NO_TLS12
|
else
|
||||||
else if (IsAtLeastTLSv1_2(ssl)) {
|
ssl->suites->sigAlgo = ssl->specs.sig_algo;
|
||||||
#ifdef WOLFSSL_ALLOW_TLS_SHA1
|
if (ssl->suites->sigAlgo == 0) {
|
||||||
ssl->suites->hashAlgo = sha_mac;
|
/* PSK ciphersuite - get digest to use from cipher suite */
|
||||||
#else
|
ssl->suites->hashAlgo = ssl->specs.mac_algorithm;
|
||||||
ssl->suites->hashAlgo = sha256_mac;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else {
|
ssl->suites->hashAlgo = minHash = MinHashAlgo(ssl);
|
||||||
ssl->suites->hashAlgo = sha_mac;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* No list means go with the defaults. */
|
||||||
if (hashSigAlgoSz == 0)
|
if (hashSigAlgoSz == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* i+1 since peek a byte ahead for type */
|
/* i+1 since two bytes used to describe hash and signature algorithm */
|
||||||
for (i = 0; (i+1) < hashSigAlgoSz; i += HELLO_EXT_SIGALGO_SZ) {
|
for (i = 0; (i+1) < hashSigAlgoSz; i += HELLO_EXT_SIGALGO_SZ) {
|
||||||
byte hashAlgo = 0, sigAlgo = 0;
|
byte hashAlgo = 0, sigAlgo = 0;
|
||||||
|
|
||||||
DecodeSigAlg(&hashSigAlgo[i], &hashAlgo, &sigAlgo);
|
DecodeSigAlg(&hashSigAlgo[i], &hashAlgo, &sigAlgo);
|
||||||
|
/* Keep looking if hash algorithm not strong enough. */
|
||||||
|
if (hashAlgo < minHash)
|
||||||
|
continue;
|
||||||
|
/* Keep looking if signature algorithm isn't supported by cert. */
|
||||||
|
if (!MatchSigAlgo(ssl, sigAlgo))
|
||||||
|
continue;
|
||||||
|
|
||||||
#ifdef HAVE_ED25519
|
#ifdef HAVE_ED25519
|
||||||
if (ssl->pkCurveOID == ECC_ED25519_OID) {
|
if (ssl->pkCurveOID == ECC_ED25519_OID) {
|
||||||
if (sigAlgo != ed25519_sa_algo)
|
/* Matched Ed25519 - set chosen and finished. */
|
||||||
continue;
|
|
||||||
if (sigAlgo == ed25519_sa_algo &&
|
|
||||||
ssl->suites->sigAlgo == ecc_dsa_sa_algo) {
|
|
||||||
ssl->suites->sigAlgo = sigAlgo;
|
ssl->suites->sigAlgo = sigAlgo;
|
||||||
ssl->suites->hashAlgo = sha512_mac;
|
ssl->suites->hashAlgo = hashAlgo;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ED448
|
#ifdef HAVE_ED448
|
||||||
if (ssl->pkCurveOID == ECC_ED448_OID) {
|
if (ssl->pkCurveOID == ECC_ED448_OID) {
|
||||||
if (sigAlgo != ed448_sa_algo)
|
/* Matched Ed448 - set chosen and finished. */
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sigAlgo == ed448_sa_algo &&
|
|
||||||
ssl->suites->sigAlgo == ecc_dsa_sa_algo) {
|
|
||||||
ssl->suites->sigAlgo = sigAlgo;
|
ssl->suites->sigAlgo = sigAlgo;
|
||||||
ssl->suites->hashAlgo = sha512_mac;
|
ssl->suites->hashAlgo = hashAlgo;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECC)
|
|
||||||
if (IsAtLeastTLSv1_3(ssl->version) && sigAlgo == ssl->suites->sigAlgo &&
|
#if defined(WOLFSSL_ECDSA_MATCH_HASH) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
|
||||||
sigAlgo == ecc_dsa_sa_algo) {
|
#error "WOLFSSL_ECDSA_MATCH_HASH and USE_ECDSA_KEYSZ_HASH_ALGO cannot "
|
||||||
int curveSz = ssl->buffers.keySz & (~0x3);
|
"be used together"
|
||||||
int digestSz = GetMacDigestSize(hashAlgo);
|
#endif
|
||||||
if (digestSz <= 0)
|
|
||||||
continue;
|
#if defined(HAVE_ECC) && (defined(WOLFSSL_TLS13) || \
|
||||||
|
defined(WOLFSSL_ECDSA_MATCH_HASH))
|
||||||
/* TLS 1.3 signature algorithms for ECDSA match hash length with
|
if (sigAlgo == ecc_dsa_sa_algo
|
||||||
* key size.
|
#ifndef WOLFSSL_ECDSA_MATCH_HASH
|
||||||
*/
|
&& IsAtLeastTLSv1_3(ssl->version)
|
||||||
if (digestSz != curveSz)
|
#endif
|
||||||
|
) {
|
||||||
|
/* Must be exact match. */
|
||||||
|
if (CmpEccStrength(hashAlgo, ssl->buffers.keySz) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Matched ECDSA exaclty - set chosen and finished. */
|
||||||
ssl->suites->hashAlgo = hashAlgo;
|
ssl->suites->hashAlgo = hashAlgo;
|
||||||
ssl->suites->sigAlgo = sigAlgo;
|
ssl->suites->sigAlgo = sigAlgo;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break; /* done selected sig/hash algorithms */
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* For ECDSA the `USE_ECDSA_KEYSZ_HASH_ALGO` build option will choose a hash
|
/* For ECDSA the `USE_ECDSA_KEYSZ_HASH_ALGO` build option will choose a hash
|
||||||
* algorithm that matches the ephemeral ECDHE key size or the next highest
|
* algorithm that matches the ephemeral ECDHE key size or the next highest
|
||||||
* available. This workaround resolves issue with some peer's that do not
|
* available. This workaround resolves issue with some peer's that do not
|
||||||
* properly support scenarios such as a P-256 key hashed with SHA512.
|
* properly support scenarios such as a P-256 key hashed with SHA512.
|
||||||
*/
|
*/
|
||||||
#if defined(HAVE_ECC) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
|
#if defined(HAVE_ECC) && defined(USE_ECDSA_KEYSZ_HASH_ALGO)
|
||||||
if (sigAlgo == ssl->suites->sigAlgo && sigAlgo == ecc_dsa_sa_algo) {
|
if (sigAlgo == ecc_dsa_sa_algo) {
|
||||||
int digestSz = GetMacDigestSize(hashAlgo);
|
int cmp = CmpEccStrength(hashAlgo, ssl->eccTempKeySz);
|
||||||
if (digestSz <= 0)
|
|
||||||
|
/* Keep looking if digest not strong enough. */
|
||||||
|
if (cmp < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* For ecc_dsa_sa_algo, pick hash algo that is curve size unless
|
/* Looking for exact match or next highest. */
|
||||||
algorithm in not compiled in, then choose next highest */
|
if (ret != 0 || hashAlgo <= ssl->suites->hashAlgo) {
|
||||||
if (digestSz == ssl->eccTempKeySz) {
|
|
||||||
ssl->suites->hashAlgo = hashAlgo;
|
ssl->suites->hashAlgo = hashAlgo;
|
||||||
ssl->suites->sigAlgo = sigAlgo;
|
ssl->suites->sigAlgo = sigAlgo;
|
||||||
#if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE)
|
#if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE)
|
||||||
ssl->namedGroup = 0;
|
ssl->namedGroup = 0;
|
||||||
#endif
|
#endif
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break; /* done selected sig/hash algorithms */
|
|
||||||
}
|
}
|
||||||
/* not strong enough, so keep checking hashSigAlso list */
|
|
||||||
if (digestSz < ssl->eccTempKeySz)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* mark as highest and check remainder of hashSigAlgo list */
|
/* Continue looking if not the same strength. */
|
||||||
ssl->suites->hashAlgo = hashAlgo;
|
if (cmp > 0)
|
||||||
ssl->suites->sigAlgo = sigAlgo;
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#ifdef WC_RSA_PSS
|
|
||||||
if (IsAtLeastTLSv1_3(ssl->version) &&
|
|
||||||
ssl->suites->sigAlgo == rsa_sa_algo &&
|
|
||||||
sigAlgo != rsa_pss_sa_algo) {
|
|
||||||
continue;
|
continue;
|
||||||
|
/* Exact match - finished. */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (sigAlgo == ssl->suites->sigAlgo ||
|
|
||||||
(sigAlgo == rsa_pss_sa_algo &&
|
|
||||||
(ssl->suites->sigAlgo == rsa_sa_algo)))
|
|
||||||
#else
|
|
||||||
if (sigAlgo == ssl->suites->sigAlgo)
|
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
/* pick highest available between both server and client */
|
|
||||||
switch (hashAlgo) {
|
switch (hashAlgo) {
|
||||||
|
#ifndef NO_SHA
|
||||||
case sha_mac:
|
case sha_mac:
|
||||||
|
#endif
|
||||||
#ifdef WOLFSSL_SHA224
|
#ifdef WOLFSSL_SHA224
|
||||||
case sha224_mac:
|
case sha224_mac:
|
||||||
#endif
|
#endif
|
||||||
@@ -19748,30 +19791,24 @@ int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz)
|
|||||||
#ifdef WOLFSSL_SHA512
|
#ifdef WOLFSSL_SHA512
|
||||||
case sha512_mac:
|
case sha512_mac:
|
||||||
#endif
|
#endif
|
||||||
/* not strong enough, so keep checking hashSigAlso list */
|
#ifdef WOLFSSL_STRONGEST_HASH_SIG
|
||||||
if (hashAlgo < ssl->suites->hashAlgo) {
|
/* Is hash algorithm weaker than chosen/min? */
|
||||||
ret = 0;
|
if (hashAlgo < ssl->suites->hashAlgo)
|
||||||
continue;
|
break;
|
||||||
}
|
#else
|
||||||
/* mark as highest and check remainder of hashSigAlgo list */
|
/* Is hash algorithm stonger than last chosen? */
|
||||||
|
if (ret == 0 && hashAlgo > ssl->suites->hashAlgo)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/* The chosen one - but keep looking. */
|
||||||
ssl->suites->hashAlgo = hashAlgo;
|
ssl->suites->hashAlgo = hashAlgo;
|
||||||
ssl->suites->sigAlgo = sigAlgo;
|
ssl->suites->sigAlgo = sigAlgo;
|
||||||
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
/* Support for hash algorithm not compiled in. */
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if defined(WOLFSSL_TLS13)
|
|
||||||
else if (ssl->specs.sig_algo == 0 && IsAtLeastTLSv1_3(ssl->version)) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (ssl->specs.sig_algo == 0)
|
|
||||||
{
|
|
||||||
ssl->suites->hashAlgo = ssl->specs.mac_algorithm;
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user