diff options
author | Jakub Jelen <jjelen@redhat.com> | 2018-08-07 12:17:29 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2018-08-31 14:18:34 +0200 |
commit | fa60827840d893187c32a6de538c3955b46256ac (patch) | |
tree | 17ec533fc97327d2754813a63c6220f2af7f5fcb | |
parent | 761225712a28d70adea7a2b872c265bc98a83511 (diff) | |
download | libssh-fa60827840d893187c32a6de538c3955b46256ac.tar.gz libssh-fa60827840d893187c32a6de538c3955b46256ac.tar.xz libssh-fa60827840d893187c32a6de538c3955b46256ac.zip |
pki: Support RSA verification using different hash algorithms
This changes the private API by adding one more argument to function
pki_signature_from_blob()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r-- | include/libssh/pki.h | 1 | ||||
-rw-r--r-- | include/libssh/pki_priv.h | 5 | ||||
-rw-r--r-- | include/libssh/wrapper.h | 7 | ||||
-rw-r--r-- | src/pki.c | 108 | ||||
-rw-r--r-- | src/pki_crypto.c | 30 | ||||
-rw-r--r-- | src/pki_gcrypt.c | 29 | ||||
-rw-r--r-- | src/pki_mbedcrypto.c | 31 | ||||
-rw-r--r-- | tests/unittests/torture_pki_ed25519.c | 4 |
8 files changed, 196 insertions, 19 deletions
diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 4a4ce612..558680d7 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -69,6 +69,7 @@ struct ssh_key_struct { struct ssh_signature_struct { enum ssh_keytypes_e type; + enum ssh_digest_e hash_type; const char *type_c; #ifdef HAVE_LIBGCRYPT gcry_sexp_t dsa_sig; diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h index af041504..b10e3b95 100644 --- a/include/libssh/pki_priv.h +++ b/include/libssh/pki_priv.h @@ -45,6 +45,8 @@ int bcrypt_pbkdf(const char *pass, int pki_key_ecdsa_nid_from_name(const char *name); const char *pki_key_ecdsa_nid_to_name(int nid); +const char *ssh_key_signature_to_char(enum ssh_keytypes_e type, + enum ssh_digest_e hash_type); /* SSH Key Functions */ ssh_key pki_key_dup(const ssh_key key, int demote); @@ -85,7 +87,8 @@ ssh_string pki_publickey_to_blob(const ssh_key key); ssh_string pki_signature_to_blob(const ssh_signature sign); ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string sig_blob, - enum ssh_keytypes_e type); + enum ssh_keytypes_e type, + enum ssh_digest_e hash_type); int pki_signature_verify(ssh_session session, const ssh_signature sig, const ssh_key key, diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h index 62a974fd..23d98afc 100644 --- a/include/libssh/wrapper.h +++ b/include/libssh/wrapper.h @@ -27,6 +27,13 @@ #include "libssh/libgcrypt.h" #include "libssh/libmbedcrypto.h" +enum ssh_digest_e { + SSH_DIGEST_AUTO=0, + SSH_DIGEST_SHA1=1, + SSH_DIGEST_SHA256, + SSH_DIGEST_SHA512 +}; + enum ssh_mac_e { SSH_MAC_SHA1=1, SSH_MAC_SHA256, @@ -194,6 +194,36 @@ enum ssh_keytypes_e ssh_key_type(const ssh_key key){ } /** + * @brief Convert a signature type to a string. + * + * @param[in] type The algorithm type to convert. + * + * @return A string for the keytype or NULL if unknown. + */ +const char * +ssh_key_signature_to_char(enum ssh_keytypes_e type, + enum ssh_digest_e hash_type) +{ + if (type != SSH_KEYTYPE_RSA) { + return ssh_key_type_to_char(type); + } + + switch (hash_type) { + case SSH_DIGEST_SHA256: + return "rsa-sha2-256"; + case SSH_DIGEST_SHA512: + return "rsa-sha2-512"; + case SSH_DIGEST_SHA1: + return "ssh-rsa"; + default: + return NULL; + } + + /* We should never reach this */ + return NULL; +} + +/** * @brief Convert a key type to a string. * * @param[in] type The type to convert. @@ -223,6 +253,45 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) { return NULL; } +static enum ssh_digest_e ssh_key_hash_from_name(const char *name) +{ + if (name == NULL) { + /* TODO we should rather fail */ + return SSH_DIGEST_AUTO; + } + + if (strcmp(name, "ssh-rsa") == 0) { + return SSH_DIGEST_SHA1; + } else if (strcmp(name, "rsa-sha2-256") == 0) { + return SSH_DIGEST_SHA256; + } else if (strcmp(name, "rsa-sha2-512") == 0) { + return SSH_DIGEST_SHA512; + } + + /* we do not care for others now */ + return SSH_DIGEST_AUTO; +} +/** + * @brief Convert a ssh key algorithm name to a ssh key algorithm type. + * + * @param[in] name The name to convert. + * + * @return The enum ssh key algorithm type. + */ +static enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name) { + if (name == NULL) { + return SSH_KEYTYPE_UNKNOWN; + } + + if ((strcmp(name, "rsa-sha2-256") == 0) || + (strcmp(name, "rsa-sha2-512") == 0)) { + return SSH_KEYTYPE_RSA; + } + + /* Otherwise the key type matches the signature type */ + return ssh_key_type_from_name(name); +} + /** * @brief Convert a ssh key name to a ssh key type. * @@ -1507,8 +1576,10 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob, { ssh_signature sig; enum ssh_keytypes_e type; + enum ssh_digest_e hash_type; ssh_string str; ssh_buffer buf; + const char *alg = NULL; int rc; if (sig_blob == NULL || psig == NULL) { @@ -1534,7 +1605,9 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob, return SSH_ERROR; } - type = ssh_key_type_from_name(ssh_string_get_char(str)); + alg = ssh_string_get_char(str); + type = ssh_key_type_from_signature_name(alg); + hash_type = ssh_key_hash_from_name(alg); ssh_string_free(str); str = ssh_buffer_get_ssh_string(buf); @@ -1543,7 +1616,7 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob, return SSH_ERROR; } - sig = pki_signature_from_blob(pubkey, str, type); + sig = pki_signature_from_blob(pubkey, str, type, hash_type); ssh_string_free(str); if (sig == NULL) { return SSH_ERROR; @@ -1593,22 +1666,45 @@ int ssh_pki_signature_verify_blob(ssh_session session, } else if (key->type == SSH_KEYTYPE_ED25519) { rc = pki_signature_verify(session, sig, key, digest, dlen); } else { - unsigned char hash[SHA_DIGEST_LEN] = {0}; + unsigned char hash[SHA512_DIGEST_LEN] = {0}; + uint32_t hlen = 0; + + if (sig->type != SSH_KEYTYPE_RSA && sig->hash_type != SSH_DIGEST_AUTO) { + SSH_LOG(SSH_LOG_TRACE, "Only RSA keys support non-SHA1 hashes."); + return SSH_ERROR; + } - sha1(digest, dlen, hash); + switch (sig->hash_type) { + case SSH_DIGEST_SHA256: + sha256(digest, dlen, hash); + hlen = SHA256_DIGEST_LEN; + break; + case SSH_DIGEST_SHA512: + sha512(digest, dlen, hash); + hlen = SHA512_DIGEST_LEN; + break; + case SSH_DIGEST_SHA1: + case SSH_DIGEST_AUTO: + sha1(digest, dlen, hash); + hlen = SHA_DIGEST_LEN; + break; + default: + SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d", sig->hash_type); + return SSH_ERROR; + } #ifdef DEBUG_CRYPTO ssh_print_hexa(key->type == SSH_KEYTYPE_DSS ? "Hash to be verified with DSA" : "Hash to be verified with RSA", hash, - SHA_DIGEST_LEN); + hlen); #endif rc = pki_signature_verify(session, sig, key, hash, - SHA_DIGEST_LEN); + hlen); } ssh_signature_free(sig); diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 7494b162..b41dcb3f 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -1409,7 +1409,8 @@ errout: ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string sig_blob, - enum ssh_keytypes_e type) + enum ssh_keytypes_e type, + enum ssh_digest_e hash_type) { ssh_signature sig; ssh_string r; @@ -1424,7 +1425,8 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, } sig->type = type; - sig->type_c = ssh_key_type_to_char(type); + sig->hash_type = hash_type; + sig->type_c = ssh_key_signature_to_char(type, hash_type); len = ssh_string_len(sig_blob); @@ -1598,6 +1600,7 @@ int pki_signature_verify(ssh_session session, size_t hlen) { int rc; + int nid; switch(key->type) { case SSH_KEYTYPE_DSS: @@ -1615,13 +1618,33 @@ int pki_signature_verify(ssh_session session, break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: - rc = RSA_verify(NID_sha1, + switch (sig->hash_type) { + case SSH_DIGEST_AUTO: + case SSH_DIGEST_SHA1: + nid = NID_sha1; + break; + case SSH_DIGEST_SHA256: + nid = NID_sha256; + break; + case SSH_DIGEST_SHA512: + nid = NID_sha512; + break; + default: + SSH_LOG(SSH_LOG_TRACE, "Unknown hash type %d", sig->hash_type); + ssh_set_error(session, + SSH_FATAL, + "Unexpected hash type %d during RSA verify", + sig->hash_type); + return SSH_ERROR; + } + rc = RSA_verify(nid, hash, hlen, ssh_string_data(sig->rsa_sig), ssh_string_len(sig->rsa_sig), key->rsa); if (rc <= 0) { + SSH_LOG(SSH_LOG_TRACE, "RSA verify failed"); ssh_set_error(session, SSH_FATAL, "RSA error: %s", @@ -1655,6 +1678,7 @@ int pki_signature_verify(ssh_session session, #endif case SSH_KEYTYPE_UNKNOWN: default: + SSH_LOG(SSH_LOG_TRACE, "Unknown key type"); ssh_set_error(session, SSH_FATAL, "Unknown public key type"); return SSH_ERROR; } diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c index 9f53321f..9a8e8622 100644 --- a/src/pki_gcrypt.c +++ b/src/pki_gcrypt.c @@ -1773,7 +1773,8 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string sig_blob, - enum ssh_keytypes_e type) + enum ssh_keytypes_e type, + enum ssh_digest_e hash_type) { ssh_signature sig; gcry_error_t err; @@ -1787,6 +1788,8 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, } sig->type = type; + sig->hash_type = hash_type; + sig->type_c = ssh_key_signature_to_char(type, hash_type); len = ssh_string_len(sig_blob); @@ -1952,6 +1955,7 @@ int pki_signature_verify(ssh_session session, size_t hlen) { unsigned char ghash[hlen + 1]; + const char *hash_type = NULL; gcry_sexp_t sexp; gcry_error_t err; @@ -1986,10 +1990,29 @@ int pki_signature_verify(ssh_session session, } break; case SSH_KEYTYPE_RSA: + switch (sig->hash_type) { + case SSH_DIGEST_SHA256: + hash_type = "sha256"; + break; + case SSH_DIGEST_SHA512: + hash_type = "sha512"; + break; + case SSH_DIGEST_SHA1: + case SSH_DIGEST_AUTO: + hash_type = "sha1"; + break; + default: + SSH_LOG(SSH_LOG_TRACE, "Unknown sig type %d", sig->hash_type); + ssh_set_error(session, + SSH_FATAL, + "Unexpected signature type %d during RSA verify", + sig->hash_type); + return SSH_ERROR; + } err = gcry_sexp_build(&sexp, NULL, - "(data(flags pkcs1)(hash sha1 %b))", - hlen, hash); + "(data(flags pkcs1)(hash %s %b))", + hash_type, hlen, hash); if (err) { ssh_set_error(session, SSH_FATAL, diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c index 6dbaa56f..57465009 100644 --- a/src/pki_mbedcrypto.c +++ b/src/pki_mbedcrypto.c @@ -825,8 +825,10 @@ errout: ssh_signature_free(sig); return NULL; } -ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string - sig_blob, enum ssh_keytypes_e type) +ssh_signature pki_signature_from_blob(const ssh_key pubkey, + const ssh_string sig_blob, + enum ssh_keytypes_e type, + enum ssh_digest_e hash_type) { ssh_signature sig = NULL; int rc; @@ -837,7 +839,8 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string } sig->type = type; - sig->type_c = ssh_key_type_to_char(type); + sig->hash_type = hash_type; + sig->type_c = ssh_key_signature_to_char(type, hash_type); switch(type) { case SSH_KEYTYPE_RSA: @@ -930,10 +933,30 @@ int pki_signature_verify(ssh_session session, const ssh_signature sig, const ssh_key key, const unsigned char *hash, size_t hlen) { int rc; + mbedtls_md_type_t md = 0; switch (key->type) { case SSH_KEYTYPE_RSA: - rc = mbedtls_pk_verify(key->rsa, MBEDTLS_MD_SHA1, hash, hlen, + switch (sig->hash_type) { + case SSH_DIGEST_SHA1: + case SSH_DIGEST_AUTO: + md = MBEDTLS_MD_SHA1; + break; + case SSH_DIGEST_SHA256: + md = MBEDTLS_MD_SHA256; + break; + case SSH_DIGEST_SHA512: + md = MBEDTLS_MD_SHA512; + break; + default: + SSH_LOG(SSH_LOG_TRACE, "Unknown sig type %d", sig->hash_type); + ssh_set_error(session, + SSH_FATAL, + "Unexpected signature hash type %d during RSA verify", + sig->hash_type); + return SSH_ERROR; + } + rc = mbedtls_pk_verify(key->rsa, md, hash, hlen, ssh_string_data(sig->rsa_sig), ssh_string_len(sig->rsa_sig)); if (rc != 0) { diff --git a/tests/unittests/torture_pki_ed25519.c b/tests/unittests/torture_pki_ed25519.c index 5c6f8703..98c96a59 100644 --- a/tests/unittests/torture_pki_ed25519.c +++ b/tests/unittests/torture_pki_ed25519.c @@ -374,7 +374,7 @@ static void torture_pki_ed25519_verify(void **state){ assert_true(rc == SSH_OK); ssh_string_fill(blob, ref_signature, ED25519_SIG_LEN); - sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519); + sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO); assert_true(sig != NULL); rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH)); @@ -411,7 +411,7 @@ static void torture_pki_ed25519_verify_bad(void **state){ for (i=0; i < ED25519_SIG_LEN; ++i){ ssh_string_fill(blob, ref_signature, ED25519_SIG_LEN); ((uint8_t *)ssh_string_data(blob))[i] ^= 0xff; - sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519); + sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO); assert_true(sig != NULL); rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH)); |