From 1c0372e0aafee6ee29e42d480021169221950803 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 9 May 2022 19:36:11 +0200 Subject: [PATCH] pki: Implement ssh_key_size to get key size in bits Thanks to Harry Sintonen from WithSecure for pointing this out. Signed-off-by: Jakub Jelen Reviewed-by: Andreas Schneider --- include/libssh/pki.h | 3 +++ src/pki_crypto.c | 38 +++++++++++++++++++++++++++++++++++ src/pki_gcrypt.c | 31 ++++++++++++++++++++++++++++ src/pki_mbedcrypto.c | 32 +++++++++++++++++++++++++++++ tests/unittests/torture_pki.c | 13 +++++++----- 5 files changed, 112 insertions(+), 5 deletions(-) diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 44f44bb7..3dc2d172 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -177,6 +177,9 @@ ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key); int ssh_key_algorithm_allowed(ssh_session session, const char *type); +/* Return the key size in bits */ +int ssh_key_size(ssh_key key); + /* PKCS11 URI function to check if filename is a path or a PKCS11 URI */ bool ssh_pki_is_uri(const char *filename); char *ssh_pki_export_pub_uri_from_priv_uri(const char *priv_uri); diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 6f4f435c..44a1db03 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -2428,6 +2428,44 @@ out: return rc; } +int ssh_key_size(ssh_key key) +{ + int bits = 0; + EVP_PKEY *pkey; + + switch (key->type) { + case SSH_KEYTYPE_DSS: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA_CERT01: + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P384_CERT01: + case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ECDSA_P521_CERT01: + case SSH_KEYTYPE_SK_ECDSA: + case SSH_KEYTYPE_SK_ECDSA_CERT01: + pkey = pki_key_to_pkey(key); + if (pkey == NULL) { + return SSH_ERROR; + } + bits = EVP_PKEY_bits(pkey); + EVP_PKEY_free(pkey); + return bits; + case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: + case SSH_KEYTYPE_SK_ED25519: + case SSH_KEYTYPE_SK_ED25519_CERT01: + /* ed25519 keys have fixed size */ + return 255; + case SSH_KEYTYPE_UNKNOWN: + default: + return SSH_ERROR; + } +} + #ifdef HAVE_OPENSSL_ED25519 int pki_key_generate_ed25519(ssh_key key) { diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c index 7f8b140e..44a3cc2a 100644 --- a/src/pki_gcrypt.c +++ b/src/pki_gcrypt.c @@ -2495,6 +2495,37 @@ int pki_verify_data_signature(ssh_signature signature, return SSH_OK; } +int ssh_key_size(ssh_key key) +{ + switch (key->type) { + case SSH_KEYTYPE_DSS: + case SSH_KEYTYPE_DSS_CERT01: + return gcry_pk_get_nbits(key->dsa); + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA_CERT01: + case SSH_KEYTYPE_RSA1: + return gcry_pk_get_nbits(key->rsa); + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P384_CERT01: + case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ECDSA_P521_CERT01: + case SSH_KEYTYPE_SK_ECDSA: + case SSH_KEYTYPE_SK_ECDSA_CERT01: + return gcry_pk_get_nbits(key->ecdsa); + case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: + case SSH_KEYTYPE_SK_ED25519: + case SSH_KEYTYPE_SK_ED25519_CERT01: + /* ed25519 keys have fixed size */ + return 255; + case SSH_KEYTYPE_UNKNOWN: + default: + return SSH_ERROR; + } +} + int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type) { (void) uri_name; diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c index 52b298ee..5bdd7484 100644 --- a/src/pki_mbedcrypto.c +++ b/src/pki_mbedcrypto.c @@ -1622,6 +1622,38 @@ int pki_key_generate_dss(ssh_key key, int parameter) return SSH_ERROR; } +int ssh_key_size(ssh_key key) +{ + switch (key->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA_CERT01: + case SSH_KEYTYPE_RSA1: + return mbedtls_pk_get_bitlen(key->rsa); + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P256_CERT01: + case SSH_KEYTYPE_SK_ECDSA: + case SSH_KEYTYPE_SK_ECDSA_CERT01: + return 256; + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P384_CERT01: + return 384; + case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ECDSA_P521_CERT01: + return 521; + case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: + case SSH_KEYTYPE_SK_ED25519: + case SSH_KEYTYPE_SK_ED25519_CERT01: + /* ed25519 keys have fixed size */ + return 255; + case SSH_KEYTYPE_DSS: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_UNKNOWN: + default: + return SSH_ERROR; + } +} + int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type) { (void) uri_name; diff --git a/tests/unittests/torture_pki.c b/tests/unittests/torture_pki.c index d886245c..a1ddb8c7 100644 --- a/tests/unittests/torture_pki.c +++ b/tests/unittests/torture_pki.c @@ -164,11 +164,11 @@ struct key_attrs key_attrs_list[][5] = { {0, 1, "", 521, 0, "", 0}, /* ECDSA, SHA512 */ }, { - {1, 1, "ssh-ed25519", 0, 33, "ssh-ed25519", 1}, /* ED25519, AUTO */ - {1, 1, "ssh-ed25519", 0, 0, "", 0}, /* ED25519, SHA1 */ - {1, 1, "ssh-ed25519", 0, 0, "", 0}, /* ED25519, SHA256 */ - {1, 1, "ssh-ed25519", 0, 0, "", 0}, /* ED25519, SHA384 */ - {1, 1, "ssh-ed25519", 0, 0, "", 0}, /* ED25519, SHA512 */ + {1, 1, "ssh-ed25519", 255, 33, "ssh-ed25519", 1}, /* ED25519, AUTO */ + {1, 1, "ssh-ed25519", 255, 0, "", 0}, /* ED25519, SHA1 */ + {1, 1, "ssh-ed25519", 255, 0, "", 0}, /* ED25519, SHA256 */ + {1, 1, "ssh-ed25519", 255, 0, "", 0}, /* ED25519, SHA384 */ + {1, 1, "ssh-ed25519", 255, 0, "", 0}, /* ED25519, SHA512 */ }, #ifdef HAVE_DSA { @@ -260,6 +260,7 @@ static void torture_pki_verify_mismatch(void **state) enum ssh_digest_e hash; size_t input_length = sizeof(INPUT); struct key_attrs skey_attrs, vkey_attrs; + int bits; (void) state; @@ -294,6 +295,8 @@ static void torture_pki_verify_mismatch(void **state) assert_non_null(key); assert_int_equal(key->type, sig_type); assert_string_equal(key->type_c, skey_attrs.type_c); + bits = ssh_key_size(key); + assert_int_equal(bits, skey_attrs.size_arg); SSH_LOG(SSH_LOG_TRACE, "Creating signature %d with hash %d", sig_type, hash);