From 2a2c1c98bf4129f4c70ec1fef6558c2e5af15e5d Mon Sep 17 00:00:00 2001 From: Anderson Toshiyuki Sasaki Date: Thu, 22 Aug 2019 18:11:13 +0200 Subject: [PATCH] pki_crypto: Use OpenSSL for Ed25519 signatures Use OpenSSL to generate and verify Ed25519 signatures, if supported. Signed-off-by: Anderson Toshiyuki Sasaki Reviewed-by: Jakub Jelen --- include/libssh/pki.h | 15 ++ src/CMakeLists.txt | 9 +- src/pki.c | 24 ++-- src/pki_container_openssh.c | 11 +- src/pki_crypto.c | 190 +++++++++++++++++++++++--- src/pki_ed25519_common.c | 81 +++++++++-- tests/unittests/torture_pki_ed25519.c | 73 ++++++++-- 7 files changed, 343 insertions(+), 60 deletions(-) diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 57736f83..e7a20156 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -30,7 +30,15 @@ #endif #include "libssh/crypto.h" +#ifdef HAVE_OPENSSL_ED25519 +/* If using OpenSSL implementation, define the signature lenght which would be + * defined in libssh/ed25519.h otherwise */ +#define ED25519_SIG_LEN 64 +#else #include "libssh/ed25519.h" +#endif +/* This definition is used for both OpenSSL and internal implementations */ +#define ED25519_KEY_LEN 32 #define MAX_PUBKEY_SIZE 0x100000 /* 1M */ #define MAX_PRIVKEY_SIZE 0x400000 /* 4M */ @@ -61,8 +69,13 @@ struct ssh_key_struct { void *ecdsa; # endif /* HAVE_OPENSSL_EC_H */ #endif /* HAVE_LIBGCRYPT */ +#ifdef HAVE_OPENSSL_ED25519 + uint8_t *ed25519_pubkey; + uint8_t *ed25519_privkey; +#else ed25519_pubkey *ed25519_pubkey; ed25519_privkey *ed25519_privkey; +#endif void *cert; enum ssh_keytypes_e cert_type; }; @@ -79,7 +92,9 @@ struct ssh_signature_struct { ssh_string rsa_sig; struct mbedtls_ecdsa_sig ecdsa_sig; #endif /* HAVE_LIBGCRYPT */ +#ifndef HAVE_OPENSSL_ED25519 ed25519_signature *ed25519_sig; +#endif ssh_string raw_sig; }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f2b0337..bdb38619 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -146,7 +146,6 @@ set(libssh_SRCS pcap.c pki.c pki_container_openssh.c - pki_ed25519.c poll.c session.c scp.c @@ -202,6 +201,7 @@ if (WITH_GCRYPT) pki_gcrypt.c ecdh_gcrypt.c dh_key.c + pki_ed25519.c ) elseif (WITH_MBEDTLS) set(libssh_SRCS @@ -212,6 +212,7 @@ elseif (WITH_MBEDTLS) pki_mbedcrypto.c ecdh_mbedcrypto.c dh_key.c + pki_ed25519.c ) else (WITH_GCRYPT) set(libssh_SRCS @@ -222,6 +223,12 @@ else (WITH_GCRYPT) libcrypto.c dh_crypto.c ) + if (NOT HAVE_OPENSSL_ED25519) + set(libssh_SRCS + ${libssh_SRCS} + pki_ed25519.c + ) + endif (NOT HAVE_OPENSSL_ED25519) if(OPENSSL_VERSION VERSION_LESS "1.1.0") set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c) endif() diff --git a/src/pki.c b/src/pki.c index f99be0ac..2ee1bb5b 100644 --- a/src/pki.c +++ b/src/pki.c @@ -162,7 +162,14 @@ void ssh_key_clean (ssh_key key){ } #endif if (key->ed25519_privkey != NULL){ +#ifdef HAVE_OPENSSL_ED25519 + /* In OpenSSL implementation the private key is only the private + * original seed. In the internal implementation the private key is the + * concatenation of the original private seed with the public key.*/ + explicit_bzero(key->ed25519_privkey, ED25519_KEY_LEN); +#else explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey)); +#endif SAFE_FREE(key->ed25519_privkey); } SAFE_FREE(key->ed25519_pubkey); @@ -679,7 +686,10 @@ void ssh_signature_free(ssh_signature sig) #endif break; case SSH_KEYTYPE_ED25519: +#ifndef HAVE_OPENSSL_ED25519 + /* When using OpenSSL, the signature is stored in sig->raw_sig */ SAFE_FREE(sig->ed25519_sig); +#endif break; case SSH_KEYTYPE_DSS_CERT01: case SSH_KEYTYPE_RSA_CERT01: @@ -1321,21 +1331,21 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, case SSH_KEYTYPE_ED25519: { ssh_string pubkey = ssh_buffer_get_ssh_string(buffer); - if (ssh_string_len(pubkey) != ED25519_PK_LEN) { + if (ssh_string_len(pubkey) != ED25519_KEY_LEN) { SSH_LOG(SSH_LOG_WARN, "Invalid public key length"); ssh_string_burn(pubkey); ssh_string_free(pubkey); goto fail; } - key->ed25519_pubkey = malloc(ED25519_PK_LEN); + key->ed25519_pubkey = malloc(ED25519_KEY_LEN); if (key->ed25519_pubkey == NULL) { ssh_string_burn(pubkey); ssh_string_free(pubkey); goto fail; } - memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN); + memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN); ssh_string_burn(pubkey); ssh_string_free(pubkey); } @@ -2259,7 +2269,7 @@ int ssh_pki_signature_verify(ssh_session session, return SSH_ERROR; } - rc = pki_signature_verify(session, sig, key, input, input_len); + rc = pki_verify_data_signature(sig, key, input, input_len); return rc; } @@ -2283,12 +2293,6 @@ ssh_signature pki_do_sign(const ssh_key privkey, return NULL; } - if (privkey->type == SSH_KEYTYPE_ED25519 || - privkey->type == SSH_KEYTYPE_ED25519_CERT01) - { - return pki_do_sign_hash(privkey, input, input_len, SSH_DIGEST_AUTO); - } - return pki_sign_data(privkey, hash_type, input, input_len); } diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c index 4b98bccf..705cd19a 100644 --- a/src/pki_container_openssh.c +++ b/src/pki_container_openssh.c @@ -415,12 +415,13 @@ static int pki_openssh_export_privkey_blob(const ssh_key privkey, return SSH_ERROR; } rc = ssh_buffer_pack(buffer, - "sdPdP", + "sdPdPP", privkey->type_c, - (uint32_t)ED25519_PK_LEN, - (size_t)ED25519_PK_LEN, privkey->ed25519_pubkey, - (uint32_t)ED25519_SK_LEN, - (size_t)ED25519_SK_LEN, privkey->ed25519_privkey); + (uint32_t)ED25519_KEY_LEN, + (size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey, + (uint32_t)(2 * ED25519_KEY_LEN), + (size_t)ED25519_KEY_LEN, privkey->ed25519_privkey, + (size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey); return rc; } diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 3f876ee6..f73199c8 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -821,7 +821,11 @@ ssh_key pki_private_key_from_base64(const char *b64_key, BIO *mem = NULL; DSA *dsa = NULL; RSA *rsa = NULL; +#ifdef HAVE_OPENSSL_ED25519 + uint8_t *ed25519 = NULL; +#else ed25519_privkey *ed25519 = NULL; +#endif ssh_key key = NULL; enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN; #ifdef HAVE_OPENSSL_ECC @@ -1880,15 +1884,7 @@ int pki_signature_verify(ssh_session session, return SSH_ERROR; } - /* For ed25519 keys, verify using the input directly */ - if (key->type == SSH_KEYTYPE_ED25519 || - key->type == SSH_KEYTYPE_ED25519_CERT01) - { - rc = pki_ed25519_verify(key, sig, input, input_len); - } else { - /* For the other key types, calculate the hash and verify the signature */ - rc = pki_verify_data_signature(sig, key, input, input_len); - } + rc = pki_verify_data_signature(sig, key, input, input_len); if (rc != SSH_OK){ ssh_set_error(session, @@ -1918,6 +1914,8 @@ static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type) md = EVP_sha1(); break; case SSH_DIGEST_AUTO: + md = NULL; + break; default: SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d", hash_type); @@ -1931,12 +1929,6 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key) { EVP_PKEY *pkey = NULL; - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, "Out of memory"); - return NULL; - } - switch(key->type) { case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS_CERT01: @@ -1944,6 +1936,12 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key) SSH_LOG(SSH_LOG_TRACE, "NULL key->dsa"); goto error; } + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "Out of memory"); + return NULL; + } + EVP_PKEY_set1_DSA(pkey, key->dsa); break; case SSH_KEYTYPE_RSA: @@ -1953,6 +1951,12 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key) SSH_LOG(SSH_LOG_TRACE, "NULL key->rsa"); goto error; } + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "Out of memory"); + return NULL; + } + EVP_PKEY_set1_RSA(pkey, key->rsa); break; case SSH_KEYTYPE_ECDSA_P256: @@ -1966,12 +1970,46 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key) SSH_LOG(SSH_LOG_TRACE, "NULL key->ecdsa"); goto error; } + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "Out of memory"); + return NULL; + } + EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa); break; # endif case SSH_KEYTYPE_ED25519: - /* Not supported yet. This type requires the use of EVP_DigestSign*() - * API and ECX keys. There is no EVP_set1_ECX_KEY() or equivalent yet. */ + case SSH_KEYTYPE_ED25519_CERT01: +# if defined(HAVE_OPENSSL_ED25519) + if (ssh_key_is_private(key)) { + if (key->ed25519_privkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_privkey"); + goto error; + } + /* In OpenSSL, the input is the private key seed only, which means + * the first half of the SSH private key (the second half is the + * public key). Both keys have the same length (32 bytes) */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, + (const uint8_t *)key->ed25519_privkey, + ED25519_KEY_LEN); + } else { + if (key->ed25519_pubkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_pubkey"); + goto error; + } + pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, + (const uint8_t *)key->ed25519_pubkey, + ED25519_KEY_LEN); + } + if (pkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to create ed25519 EVP_PKEY: %s", + ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } + break; +#endif case SSH_KEYTYPE_UNKNOWN: default: SSH_LOG(SSH_LOG_TRACE, "Unknown private key algorithm for type: %d", @@ -2027,10 +2065,20 @@ ssh_signature pki_sign_data(const ssh_key privkey, return NULL; } +#ifndef HAVE_OPENSSL_ED25519 + if (privkey->type == SSH_KEYTYPE_ED25519 || + privkey->type == SSH_KEYTYPE_ED25519_CERT01) + { + return pki_do_sign_hash(privkey, input, input_len, hash_type); + } +#endif + /* Set hash algorithm to be used */ md = pki_digest_to_md(hash_type); if (md == NULL) { - return NULL; + if (hash_type != SSH_DIGEST_AUTO) { + return NULL; + } } /* Setup private key EVP_PKEY */ @@ -2160,7 +2208,11 @@ int pki_verify_data_signature(ssh_signature signature, int evp_rc; if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL || - signature == NULL || signature->raw_sig == NULL) + signature == NULL || (signature->raw_sig == NULL +#ifndef HAVE_OPENSSL_ED25519 + && signature->ed25519_sig == NULL +#endif + )) { SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to " "pki_verify_data_signature()"); @@ -2173,6 +2225,14 @@ int pki_verify_data_signature(ssh_signature signature, return SSH_ERROR; } +#ifndef HAVE_OPENSSL_ED25519 + if (pubkey->type == SSH_KEYTYPE_ED25519 || + pubkey->type == SSH_KEYTYPE_ED25519_CERT01) + { + return pki_ed25519_verify(pubkey, signature, input, input_len); + } +#endif + /* Get the signature to be verified */ raw_sig_data = ssh_string_data(signature->raw_sig); raw_sig_len = ssh_string_len(signature->raw_sig); @@ -2183,7 +2243,9 @@ int pki_verify_data_signature(ssh_signature signature, /* Set hash algorithm to be used */ md = pki_digest_to_md(signature->hash_type); if (md == NULL) { - return SSH_ERROR; + if (signature->hash_type != SSH_DIGEST_AUTO) { + return SSH_ERROR; + } } /* Setup public key EVP_PKEY */ @@ -2243,6 +2305,92 @@ out: return rc; } +#ifdef HAVE_OPENSSL_ED25519 +int pki_key_generate_ed25519(ssh_key key) +{ + int evp_rc; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *pkey = NULL; + size_t privkey_len = ED25519_KEY_LEN; + size_t pubkey_len = ED25519_KEY_LEN; + + if (key == NULL) { + return SSH_ERROR; + } + + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); + if (pctx == NULL) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to create ed25519 EVP_PKEY_CTX: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + evp_rc = EVP_PKEY_keygen_init(pctx); + if (evp_rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to initialize ed25519 key generation: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + evp_rc = EVP_PKEY_keygen(pctx, &pkey); + if (evp_rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to generate ed25519 key: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + key->ed25519_privkey = malloc(ED25519_KEY_LEN); + if (key->ed25519_privkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to allocate memory for ed25519 private key"); + goto error; + } + + key->ed25519_pubkey = malloc(ED25519_KEY_LEN); + if (key->ed25519_pubkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to allocate memory for ed25519 public key"); + goto error; + } + + evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)key->ed25519_privkey, + &privkey_len); + if (evp_rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to get ed25519 raw private key: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + evp_rc = EVP_PKEY_get_raw_public_key(pkey, (uint8_t *)key->ed25519_pubkey, + &pubkey_len); + if (evp_rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to get ed25519 raw public key: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_free(pkey); + return SSH_OK; + +error: + if (pctx != NULL) { + EVP_PKEY_CTX_free(pctx); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + SAFE_FREE(key->ed25519_privkey); + SAFE_FREE(key->ed25519_pubkey); + + return SSH_ERROR; +} +#else ssh_signature pki_do_sign_hash(const ssh_key privkey, const unsigned char *hash, size_t hlen, @@ -2275,4 +2423,6 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey, return sig; } +#endif /* HAVE_OPENSSL_ED25519 */ + #endif /* _PKI_CRYPTO_H */ diff --git a/src/pki_ed25519_common.c b/src/pki_ed25519_common.c index 25585874..738825f5 100644 --- a/src/pki_ed25519_common.c +++ b/src/pki_ed25519_common.c @@ -31,27 +31,40 @@ int pki_privkey_build_ed25519(ssh_key key, ssh_string pubkey, ssh_string privkey) { - if (ssh_string_len(pubkey) != ED25519_PK_LEN || - ssh_string_len(privkey) != ED25519_SK_LEN) + if (ssh_string_len(pubkey) != ED25519_KEY_LEN || + ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) { SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len"); return SSH_ERROR; } - key->ed25519_privkey = malloc(2 * ED25519_SK_LEN); +#ifdef HAVE_OPENSSL_ED25519 + /* In OpenSSL implementation, the private key is the original private seed, + * without the public key. */ + key->ed25519_privkey = malloc(ED25519_KEY_LEN); +#else + /* In the internal implementation, the private key is the concatenation of + * the private seed with the public key. */ + key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN); +#endif if (key->ed25519_privkey == NULL) { goto error; } - key->ed25519_pubkey = malloc(ED25519_PK_LEN); + key->ed25519_pubkey = malloc(ED25519_KEY_LEN); if (key->ed25519_pubkey == NULL) { goto error; } +#ifdef HAVE_OPENSSL_ED25519 memcpy(key->ed25519_privkey, ssh_string_data(privkey), - ED25519_SK_LEN); + ED25519_KEY_LEN); +#else + memcpy(key->ed25519_privkey, ssh_string_data(privkey), + 2 * ED25519_KEY_LEN); +#endif memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), - ED25519_PK_LEN); + ED25519_KEY_LEN); return SSH_OK; @@ -86,7 +99,16 @@ int pki_ed25519_key_cmp(const ssh_key k1, if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) { return 1; } - cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_SK_LEN); +#ifdef HAVE_OPENSSL_ED25519 + /* In OpenSSL implementation, the private key is the original private + * seed, without the public key. */ + cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN); +#else + /* In the internal implementation, the private key is the concatenation + * of the private seed with the public key. */ + cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, + 2 * ED25519_KEY_LEN); +#endif if (cmp != 0) { return 1; } @@ -95,7 +117,7 @@ int pki_ed25519_key_cmp(const ssh_key k1, if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) { return 1; } - cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_PK_LEN); + cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN); if (cmp != 0) { return 1; } @@ -122,20 +144,32 @@ int pki_ed25519_key_dup(ssh_key new, const ssh_key key) } if (key->ed25519_privkey != NULL) { - new->ed25519_privkey = malloc(ED25519_SK_LEN); +#ifdef HAVE_OPENSSL_ED25519 + /* In OpenSSL implementation, the private key is the original private + * seed, without the public key. */ + new->ed25519_privkey = malloc(ED25519_KEY_LEN); +#else + /* In the internal implementation, the private key is the concatenation + * of the private seed with the public key. */ + new->ed25519_privkey = malloc(2 * ED25519_KEY_LEN); +#endif if (new->ed25519_privkey == NULL) { return SSH_ERROR; } - memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN); +#ifdef HAVE_OPENSSL_ED25519 + memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN); +#else + memcpy(new->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN); +#endif } if (key->ed25519_pubkey != NULL) { - new->ed25519_pubkey = malloc(ED25519_PK_LEN); + new->ed25519_pubkey = malloc(ED25519_KEY_LEN); if (new->ed25519_pubkey == NULL) { SAFE_FREE(new->ed25519_privkey); return SSH_ERROR; } - memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN); + memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN); } return SSH_OK; @@ -162,8 +196,8 @@ int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key) rc = ssh_buffer_pack(buffer, "dP", - (uint32_t)ED25519_PK_LEN, - (size_t)ED25519_PK_LEN, key->ed25519_pubkey); + (uint32_t)ED25519_KEY_LEN, + (size_t)ED25519_KEY_LEN, key->ed25519_pubkey); return rc; } @@ -181,16 +215,31 @@ ssh_string pki_ed25519_signature_to_blob(ssh_signature sig) { ssh_string sig_blob; +#ifdef HAVE_OPENSSL_ED25519 + /* When using the OpenSSL implementation, the signature is stored in raw_sig + * which is shared by all algorithms.*/ + if (sig->raw_sig == NULL) { + return NULL; + } +#else + /* When using the internal implementation, the signature is stored in an + * algorithm specific field. */ if (sig->ed25519_sig == NULL) { return NULL; } +#endif sig_blob = ssh_string_new(ED25519_SIG_LEN); if (sig_blob == NULL) { return NULL; } +#ifdef HAVE_OPENSSL_ED25519 + ssh_string_fill(sig_blob, ssh_string_data(sig->raw_sig), + ssh_string_len(sig->raw_sig)); +#else ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN); +#endif return sig_blob; } @@ -216,11 +265,15 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob) return SSH_ERROR; } +#ifdef HAVE_OPENSSL_ED25519 + sig->raw_sig = ssh_string_copy(sig_blob); +#else sig->ed25519_sig = malloc(ED25519_SIG_LEN); if (sig->ed25519_sig == NULL){ return SSH_ERROR; } memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN); +#endif return SSH_OK; } diff --git a/tests/unittests/torture_pki_ed25519.c b/tests/unittests/torture_pki_ed25519.c index 94d9c7f9..422be580 100644 --- a/tests/unittests/torture_pki_ed25519.c +++ b/tests/unittests/torture_pki_ed25519.c @@ -422,8 +422,16 @@ static void torture_pki_ed25519_generate_key(void **state) enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN; const char *type_char = NULL; ssh_session session=ssh_new(); + uint8_t *raw_sig_data = NULL; (void) state; + /* Skip test if in FIPS mode */ + if (ssh_fips_mode()) { + skip(); + } + + assert_non_null(session); + rc = ssh_pki_generate(SSH_KEYTYPE_ED25519, 256, &key); assert_true(rc == SSH_OK); assert_non_null(key); @@ -440,7 +448,13 @@ static void torture_pki_ed25519_generate_key(void **state) assert_true(strcmp(type_char, "ssh-ed25519") == 0); /* try an invalid signature */ - (*sign->ed25519_sig)[3]^= 0xff; +#ifdef HAVE_OPENSSL_ED25519 + raw_sig_data = ssh_string_data(sign->raw_sig); +#else + raw_sig_data = (uint8_t *)sign->ed25519_sig; +#endif + assert_non_null(raw_sig_data); + (raw_sig_data)[3]^= 0xff; rc = pki_signature_verify(session, sign, pubkey, HASH, 20); assert_true(rc == SSH_ERROR); @@ -459,6 +473,13 @@ static void torture_pki_ed25519_cert_verify(void **state) ssh_session session=ssh_new(); (void) state; + /* Skip test if in FIPS mode */ + if (ssh_fips_mode()) { + skip(); + } + + assert_non_null(session); + rc = ssh_pki_import_privkey_file(LIBSSH_ED25519_TESTKEY, NULL, NULL, @@ -599,10 +620,12 @@ static void torture_pki_ed25519_sign(void **state) const char *keystring = NULL; int rc; - (void)state; + /* Skip test if in FIPS mode */ + if (ssh_fips_mode()) { + skip(); + } - sig = ssh_signature_new(); - assert_non_null(sig); + (void)state; keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0); rc = ssh_pki_import_privkey_base64(keystring, @@ -613,9 +636,8 @@ static void torture_pki_ed25519_sign(void **state) assert_true(rc == SSH_OK); assert_non_null(privkey); - sig->type = SSH_KEYTYPE_ED25519; - rc = pki_ed25519_sign(privkey, sig, HASH, sizeof(HASH)); - assert_true(rc == SSH_OK); + sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO); + assert_non_null(sig); blob = pki_signature_to_blob(sig); assert_non_null(blob); @@ -632,12 +654,22 @@ static void torture_pki_ed25519_sign(void **state) static void torture_pki_ed25519_verify(void **state){ ssh_key pubkey = NULL; ssh_signature sig = NULL; + ssh_session session = NULL; ssh_string blob = ssh_string_new(ED25519_SIG_LEN); char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1); char *ptr = NULL; + uint8_t *raw_sig_data = NULL; int rc; (void) state; + /* Skip test if in FIPS mode */ + if (ssh_fips_mode()) { + skip(); + } + + session = ssh_new(); + assert_non_null(session); + /* remove trailing comment */ ptr = strchr(pkey_ptr, ' '); if(ptr != NULL){ @@ -651,20 +683,32 @@ static void torture_pki_ed25519_verify(void **state){ sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO); assert_non_null(sig); - rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH)); + rc = pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH)); assert_true(rc == SSH_OK); + /* Alter signature and expect verification error */ +#if defined(HAVE_OPENSSL_ED25519) + raw_sig_data = ssh_string_data(sig->raw_sig); +#else + raw_sig_data = (uint8_t *)sig->ed25519_sig; +#endif + assert_non_null(raw_sig_data); + (raw_sig_data)[3]^= 0xff; + rc = pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH)); + assert_true(rc == SSH_ERROR); + ssh_signature_free(sig); - /* alter signature and expect false result */ SSH_KEY_FREE(pubkey); SSH_STRING_FREE(blob); free(pkey_ptr); + ssh_free(session); } static void torture_pki_ed25519_verify_bad(void **state){ ssh_key pubkey = NULL; ssh_signature sig = NULL; + ssh_session session = NULL; ssh_string blob = ssh_string_new(ED25519_SIG_LEN); char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1); char *ptr = NULL; @@ -672,6 +716,14 @@ static void torture_pki_ed25519_verify_bad(void **state){ int i; (void) state; + /* Skip test if in FIPS mode */ + if (ssh_fips_mode()) { + skip(); + } + + session = ssh_new(); + assert_non_null(session); + /* remove trailing comment */ ptr = strchr(pkey_ptr, ' '); if(ptr != NULL){ @@ -689,7 +741,7 @@ static void torture_pki_ed25519_verify_bad(void **state){ sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO); assert_non_null(sig); - rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH)); + rc = pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH)); assert_true(rc == SSH_ERROR); ssh_signature_free(sig); @@ -697,6 +749,7 @@ static void torture_pki_ed25519_verify_bad(void **state){ SSH_KEY_FREE(pubkey); SSH_STRING_FREE(blob); free(pkey_ptr); + ssh_free(session); } static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state)