From 2f26b5d63cde0da954e237aff176701d51760ea1 Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Wed, 13 Feb 2019 13:00:53 -0700 Subject: [PATCH] pki: allow certificates to be used in signature verification A number of places checked that the signature type matched the key type. We losen these checks to, for example, allow an RSA signature with an RSA-cert key. Signed-off-by: Ben Toews Reviewed-by: Jakub Jelen --- include/libssh/pki.h | 1 + src/pki.c | 35 +++++++++++++++++++++++++++++++---- src/pki_crypto.c | 10 ++++++++-- src/pki_gcrypt.c | 10 ++++++++-- src/pki_mbedcrypto.c | 9 +++++++-- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/include/libssh/pki.h b/include/libssh/pki.h index c0102382..4c844a32 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -100,6 +100,7 @@ const char * ssh_key_get_signature_algorithm(ssh_session session, enum ssh_keytypes_e type); enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name); +enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type); #define is_ecdsa_key_type(t) \ ((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521) diff --git a/src/pki.c b/src/pki.c index ef83282e..9b5f504c 100644 --- a/src/pki.c +++ b/src/pki.c @@ -443,6 +443,32 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) { return SSH_KEYTYPE_UNKNOWN; } +/** + * @brief Get the pubic key type corresponding to a certificate type. + * + * @param[in] type The certificate or public key type. + * + * @return The matching public key type. + */ +enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type) { + switch (type) { + case SSH_KEYTYPE_DSS_CERT01: + return SSH_KEYTYPE_DSS; + case SSH_KEYTYPE_RSA_CERT01: + return SSH_KEYTYPE_RSA; + case SSH_KEYTYPE_ECDSA_P256_CERT01: + return SSH_KEYTYPE_ECDSA_P256; + case SSH_KEYTYPE_ECDSA_P384_CERT01: + return SSH_KEYTYPE_ECDSA_P384; + case SSH_KEYTYPE_ECDSA_P521_CERT01: + return SSH_KEYTYPE_ECDSA_P521; + case SSH_KEYTYPE_ED25519_CERT01: + return SSH_KEYTYPE_ED25519; + default: + return type; + } +} + /** * @brief Check if the key has/is a public key. * @@ -2025,19 +2051,20 @@ int ssh_pki_signature_verify(ssh_session session, size_t dlen) { int rc; + enum ssh_keytypes_e key_type = ssh_key_type_plain(key->type); SSH_LOG(SSH_LOG_FUNCTIONS, "Going to verify a %s type signature", sig->type_c); - if (key->type != sig->type) { + if (key_type != sig->type) { SSH_LOG(SSH_LOG_WARN, "Can not verify %s signature with %s key", sig->type_c, key->type_c); return SSH_ERROR; } - if (is_ecdsa_key_type(key->type)) { + if (is_ecdsa_key_type(key_type)) { #if HAVE_ECC unsigned char ehash[EVP_DIGEST_LEN] = {0}; uint32_t elen; @@ -2055,7 +2082,7 @@ int ssh_pki_signature_verify(ssh_session session, ehash, elen); #endif - } else if (key->type == SSH_KEYTYPE_ED25519) { + } else if (key_type == SSH_KEYTYPE_ED25519) { rc = pki_signature_verify(session, sig, key, digest, dlen); } else { unsigned char hash[SHA512_DIGEST_LEN] = {0}; @@ -2085,7 +2112,7 @@ int ssh_pki_signature_verify(ssh_session session, return SSH_ERROR; } #ifdef DEBUG_CRYPTO - ssh_print_hexa(key->type == SSH_KEYTYPE_DSS + ssh_print_hexa(key_type == SSH_KEYTYPE_DSS ? "Hash to be verified with DSA" : "Hash to be verified with RSA", hash, diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 11f0754a..c8ac33d1 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -1625,7 +1625,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, int rc; BIGNUM *pr = NULL, *ps = NULL; - if (type != pubkey->type) { + if (ssh_key_type_plain(pubkey->type) != type) { SSH_LOG(SSH_LOG_WARN, "Incompatible public key provided (%d) expecting (%d)", type, @@ -1833,7 +1833,7 @@ int pki_signature_verify(ssh_session session, int rc; int nid; - if (key->type != sig->type) { + if (ssh_key_type_plain(key->type) != sig->type) { SSH_LOG(SSH_LOG_WARN, "Can not verify %s signature with %s key", sig->type_c, @@ -1843,6 +1843,7 @@ int pki_signature_verify(ssh_session session, switch (key->type) { case SSH_KEYTYPE_DSS: + case SSH_KEYTYPE_DSS_CERT01: rc = DSA_do_verify(hash, hlen, sig->dsa_sig, @@ -1857,6 +1858,7 @@ int pki_signature_verify(ssh_session session, break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_RSA_CERT01: switch (sig->hash_type) { case SSH_DIGEST_AUTO: case SSH_DIGEST_SHA1: @@ -1892,6 +1894,7 @@ int pki_signature_verify(ssh_session session, } break; case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: rc = pki_ed25519_verify(key, sig, hash, hlen); if (rc != SSH_OK){ ssh_set_error(session, @@ -1903,6 +1906,9 @@ int pki_signature_verify(ssh_session session, case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_ECDSA_P384_CERT01: + case SSH_KEYTYPE_ECDSA_P521_CERT01: #ifdef HAVE_OPENSSL_ECC rc = ECDSA_do_verify(hash, hlen, diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c index 40280c52..8869b0f7 100644 --- a/src/pki_gcrypt.c +++ b/src/pki_gcrypt.c @@ -1909,7 +1909,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, size_t rsalen; int rc; - if (type != pubkey->type) { + if (ssh_key_type_plain(pubkey->type) != type) { SSH_LOG(SSH_LOG_WARN, "Incompatible public key provided (%d) expecting (%d)", type, @@ -2096,7 +2096,7 @@ int pki_signature_verify(ssh_session session, gcry_sexp_t sexp; gcry_error_t err; - if (key->type != sig->type) { + if (ssh_key_type_plain(key->type) != sig->type) { SSH_LOG(SSH_LOG_WARN, "Can not verify %s signature with %s key", sig->type_c, @@ -2106,6 +2106,7 @@ int pki_signature_verify(ssh_session session, switch(key->type) { case SSH_KEYTYPE_DSS: + case SSH_KEYTYPE_DSS_CERT01: /* That is to mark the number as positive */ if(hash[0] >= 0x80) { memcpy(ghash + 1, hash, hlen); @@ -2135,6 +2136,7 @@ int pki_signature_verify(ssh_session session, } break; case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA_CERT01: switch (sig->hash_type) { case SSH_DIGEST_SHA256: hash_type = "sha256"; @@ -2179,6 +2181,7 @@ int pki_signature_verify(ssh_session session, } break; case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: err = pki_ed25519_verify(key, sig, hash, hlen); if (err != SSH_OK){ ssh_set_error(session, SSH_FATAL, "ed25519 signature verification error"); @@ -2188,6 +2191,9 @@ int pki_signature_verify(ssh_session session, case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_ECDSA_P384_CERT01: + case SSH_KEYTYPE_ECDSA_P521_CERT01: #ifdef HAVE_GCRYPT_ECC err = gcry_sexp_build(&sexp, NULL, diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c index 0e7437bd..384189d3 100644 --- a/src/pki_mbedcrypto.c +++ b/src/pki_mbedcrypto.c @@ -912,7 +912,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, ssh_signature sig = NULL; int rc; - if (type != pubkey->type) { + if (ssh_key_type_plain(pubkey->type) != type) { SSH_LOG(SSH_LOG_WARN, "Incompatible public key provided (%d) expecting (%d)", type, @@ -1027,7 +1027,7 @@ int pki_signature_verify(ssh_session session, const ssh_signature sig, const int rc; mbedtls_md_type_t md = 0; - if (key->type != sig->type) { + if (ssh_key_type_plain(key->type) != sig->type) { SSH_LOG(SSH_LOG_WARN, "Can not verify %s signature with %s key", sig->type_c, @@ -1037,6 +1037,7 @@ int pki_signature_verify(ssh_session session, const ssh_signature sig, const switch (key->type) { case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA_CERT01: switch (sig->hash_type) { case SSH_DIGEST_SHA1: case SSH_DIGEST_AUTO: @@ -1069,6 +1070,9 @@ int pki_signature_verify(ssh_session session, const ssh_signature sig, const case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_ECDSA_P384_CERT01: + case SSH_KEYTYPE_ECDSA_P521_CERT01: rc = mbedtls_ecdsa_verify(&key->ecdsa->grp, hash, hlen, &key->ecdsa->Q, sig->ecdsa_sig.r, sig->ecdsa_sig.s); if (rc != 0) { @@ -1080,6 +1084,7 @@ int pki_signature_verify(ssh_session session, const ssh_signature sig, const } break; case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: rc = pki_ed25519_verify(key, sig, hash, hlen); if (rc != SSH_OK) { ssh_set_error(session, SSH_FATAL,