aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2018-08-07 12:17:29 +0200
committerAndreas Schneider <asn@cryptomilk.org>2018-08-31 14:18:34 +0200
commitfa60827840d893187c32a6de538c3955b46256ac (patch)
tree17ec533fc97327d2754813a63c6220f2af7f5fcb
parent761225712a28d70adea7a2b872c265bc98a83511 (diff)
downloadlibssh-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.h1
-rw-r--r--include/libssh/pki_priv.h5
-rw-r--r--include/libssh/wrapper.h7
-rw-r--r--src/pki.c108
-rw-r--r--src/pki_crypto.c30
-rw-r--r--src/pki_gcrypt.c29
-rw-r--r--src/pki_mbedcrypto.c31
-rw-r--r--tests/unittests/torture_pki_ed25519.c4
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,
diff --git a/src/pki.c b/src/pki.c
index b8731730..f0557708 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -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));