pki: Fail to sign when using wrong hash algorithm

Do not allow using SSH_DIGEST_AUTO for any algorithm other than
ed25519.

Do not allow using incompatible hash algorithms when signing or
verifying signatures.

Added negative tests for all combinations of signature and hash
algorithms.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Anderson Toshiyuki Sasaki
2019-05-09 17:38:54 +02:00
committed by Andreas Schneider
parent 550a1a7667
commit 248e5acd5c
9 changed files with 579 additions and 196 deletions

View File

@@ -344,8 +344,10 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
enum ssh_keytypes_e type)
{
switch (type) {
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_DSS:
return SSH_DIGEST_SHA1;
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_RSA:
if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
(session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
@@ -2070,6 +2072,79 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob,
return SSH_OK;
}
/**
* @internal
*
* @brief Check if the provided key can be used with the provided hash type for
* data signing or signature verification.
*
* @param[in] key The key to be checked.
* @param[in] hash_type The digest algorithm to be checked.
*
* @return SSH_OK if compatible; SSH_ERROR otherwise
*/
int pki_key_check_hash_compatible(ssh_key key,
enum ssh_digest_e hash_type)
{
if (key == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Null pointer provided as key to "
"pki_key_check_hash_compatible()");
return SSH_ERROR;
}
switch(key->type) {
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_DSS:
if (hash_type == SSH_DIGEST_SHA1) {
return SSH_OK;
}
break;
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_RSA:
if (hash_type == SSH_DIGEST_SHA1 ||
hash_type == SSH_DIGEST_SHA256 ||
hash_type == SSH_DIGEST_SHA512)
{
return SSH_OK;
}
break;
case SSH_KEYTYPE_ECDSA_P256_CERT01:
case SSH_KEYTYPE_ECDSA_P256:
if (hash_type == SSH_DIGEST_SHA256) {
return SSH_OK;
}
break;
case SSH_KEYTYPE_ECDSA_P384_CERT01:
case SSH_KEYTYPE_ECDSA_P384:
if (hash_type == SSH_DIGEST_SHA384) {
return SSH_OK;
}
break;
case SSH_KEYTYPE_ECDSA_P521_CERT01:
case SSH_KEYTYPE_ECDSA_P521:
if (hash_type == SSH_DIGEST_SHA512) {
return SSH_OK;
}
break;
case SSH_KEYTYPE_ED25519_CERT01:
case SSH_KEYTYPE_ED25519:
if (hash_type == SSH_DIGEST_AUTO) {
return SSH_OK;
}
break;
case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_ECDSA:
case SSH_KEYTYPE_UNKNOWN:
SSH_LOG(SSH_LOG_WARN, "Unknown key type %d", key->type);
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_WARN, "Key type %d incompatible with hash type %d",
key->type, hash_type);
return SSH_ERROR;
}
int ssh_pki_signature_verify(ssh_session session,
ssh_signature sig,
const ssh_key key,
@@ -2096,6 +2171,12 @@ int ssh_pki_signature_verify(ssh_session session,
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
rc = pki_signature_verify(session, sig, key, input, input_len);
return rc;
@@ -2106,12 +2187,20 @@ ssh_signature pki_do_sign(const ssh_key privkey,
size_t input_len,
enum ssh_digest_e hash_type)
{
int rc;
if (privkey == NULL || input == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
"pki_do_sign()");
return NULL;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(privkey, hash_type);
if (rc != SSH_OK) {
return NULL;
}
if (privkey->type == SSH_KEYTYPE_ED25519 ||
privkey->type == SSH_KEYTYPE_ED25519_CERT01)
{

View File

@@ -583,9 +583,13 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter) {
key->type = SSH_KEYTYPE_ECDSA_P521;
break;
case 256:
default:
key->ecdsa_nid = NID_X9_62_prime256v1;
key->type = SSH_KEYTYPE_ECDSA_P256;
break;
default:
SSH_LOG(SSH_LOG_WARN, "Invalid parameter %d for ECDSA key "
"generation", parameter);
return SSH_ERROR;
}
key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
@@ -1922,6 +1926,12 @@ int pki_signature_verify(ssh_session session,
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* For ed25519 keys, verify using the input directly */
if (key->type == SSH_KEYTYPE_ED25519 ||
key->type == SSH_KEYTYPE_ED25519_CERT01)
@@ -1957,9 +1967,9 @@ static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type)
md = EVP_sha512();
break;
case SSH_DIGEST_SHA1:
case SSH_DIGEST_AUTO:
md = EVP_sha1();
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type);
@@ -2063,6 +2073,12 @@ ssh_signature pki_sign_data(const ssh_key privkey,
return NULL;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(privkey, hash_type);
if (rc != SSH_OK) {
return NULL;
}
/* Set hash algorithm to be used */
md = pki_digest_to_md(hash_type);
if (md == NULL) {
@@ -2187,6 +2203,12 @@ int pki_verify_data_signature(ssh_signature signature,
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* Get the signature to be verified */
raw_sig_data = ssh_string_data(signature->raw_sig);
raw_sig_len = ssh_string_len(signature->raw_sig);

View File

@@ -2107,6 +2107,12 @@ int pki_signature_verify(ssh_session session,
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* For ed25519 keys, verify using the input directly */
if (key->type == SSH_KEYTYPE_ED25519 ||
key->type == SSH_KEYTYPE_ED25519_CERT01)
@@ -2171,7 +2177,6 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
case SSH_KEYTYPE_RSA:
switch (hash_type) {
case SSH_DIGEST_SHA1:
case SSH_DIGEST_AUTO:
hash_c = "sha1";
break;
case SSH_DIGEST_SHA256:
@@ -2180,8 +2185,9 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
case SSH_DIGEST_SHA512:
hash_c = "sha512";
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_WARN, "Incomplatible key algorithm");
SSH_LOG(SSH_LOG_WARN, "Incompatible key algorithm");
return NULL;
}
err = gcry_sexp_build(&sexp,
@@ -2261,6 +2267,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
{
unsigned char hash[SHA512_DIGEST_LEN] = {0};
uint32_t hlen = 0;
int rc;
if (privkey == NULL || !ssh_key_is_private(privkey) || input == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
@@ -2268,6 +2275,12 @@ ssh_signature pki_sign_data(const ssh_key privkey,
return NULL;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(privkey, hash_type);
if (rc != SSH_OK) {
return NULL;
}
switch (hash_type) {
case SSH_DIGEST_SHA256:
sha256(input, input_len, hash);
@@ -2281,11 +2294,11 @@ ssh_signature pki_sign_data(const ssh_key privkey,
sha512(input, input_len, hash);
hlen = SHA512_DIGEST_LEN;
break;
case SSH_DIGEST_AUTO:
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type);
@@ -2321,6 +2334,8 @@ int pki_verify_data_signature(ssh_signature signature,
unsigned char *hash = ghash + 1;
uint32_t hlen = 0;
int rc;
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
signature == NULL)
{
@@ -2329,6 +2344,12 @@ int pki_verify_data_signature(ssh_signature signature,
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
switch (signature->hash_type) {
case SSH_DIGEST_SHA256:
sha256(input, input_len, hash);
@@ -2345,12 +2366,12 @@ int pki_verify_data_signature(ssh_signature signature,
hlen = SHA512_DIGEST_LEN;
hash_type = "sha512";
break;
case SSH_DIGEST_AUTO:
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
hash_type = "sha1";
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d", signature->hash_type);
return SSH_ERROR;

View File

@@ -1040,6 +1040,12 @@ int pki_signature_verify(ssh_session session, const ssh_signature sig, const
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* For ed25519 keys, verify using the input directly */
if (key->type == SSH_KEYTYPE_ED25519 ||
key->type == SSH_KEYTYPE_ED25519_CERT01)
@@ -1073,7 +1079,6 @@ static ssh_string rsa_do_sign_hash(const unsigned char *digest,
switch (hash_type) {
case SSH_DIGEST_SHA1:
case SSH_DIGEST_AUTO:
md = MBEDTLS_MD_SHA1;
break;
case SSH_DIGEST_SHA256:
@@ -1082,8 +1087,9 @@ static ssh_string rsa_do_sign_hash(const unsigned char *digest,
case SSH_DIGEST_SHA512:
md = MBEDTLS_MD_SHA512;
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_WARN, "Incomplatible key algorithm");
SSH_LOG(SSH_LOG_WARN, "Incompatible key algorithm");
return NULL;
}
@@ -1208,6 +1214,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
{
unsigned char hash[SHA512_DIGEST_LEN] = {0};
uint32_t hlen = 0;
int rc;
if (privkey == NULL || !ssh_key_is_private(privkey) || input == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
@@ -1215,6 +1222,12 @@ ssh_signature pki_sign_data(const ssh_key privkey,
return NULL;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(privkey, hash_type);
if (rc != SSH_OK) {
return NULL;
}
switch (hash_type) {
case SSH_DIGEST_SHA256:
sha256(input, input_len, hash);
@@ -1228,11 +1241,11 @@ ssh_signature pki_sign_data(const ssh_key privkey,
sha512(input, input_len, hash);
hlen = SHA512_DIGEST_LEN;
break;
case SSH_DIGEST_AUTO:
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type);
@@ -1276,6 +1289,12 @@ int pki_verify_data_signature(ssh_signature signature,
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
switch (signature->hash_type) {
case SSH_DIGEST_SHA256:
sha256(input, input_len, hash);
@@ -1292,12 +1311,12 @@ int pki_verify_data_signature(ssh_signature signature,
hlen = SHA512_DIGEST_LEN;
md = MBEDTLS_MD_SHA512;
break;
case SSH_DIGEST_AUTO:
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
md = MBEDTLS_MD_SHA1;
break;
case SSH_DIGEST_AUTO:
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d",
signature->hash_type);