aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2019-08-22 18:11:13 +0200
committerAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2019-09-30 16:57:23 +0200
commitc60ac3fe027d1eb240bef4e92ebacfa1e816c8af (patch)
treec3fcaa648a88bdb95478310536853b4efdfb4da1
parent84eab65edcf081e291da49cb1cc323d2b84aac81 (diff)
downloadlibssh-c60ac3fe027d1eb240bef4e92ebacfa1e816c8af.tar.gz
libssh-c60ac3fe027d1eb240bef4e92ebacfa1e816c8af.tar.xz
libssh-c60ac3fe027d1eb240bef4e92ebacfa1e816c8af.zip
pki_crypto: Use OpenSSL for Ed25519 signatures
Use OpenSSL to generate and verify Ed25519 signatures, if supported. Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> (cherry picked from commit 2a2c1c98bf4129f4c70ec1fef6558c2e5af15e5d)
-rw-r--r--include/libssh/pki.h15
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/pki.c24
-rw-r--r--src/pki_container_openssh.c11
-rw-r--r--src/pki_crypto.c190
-rw-r--r--src/pki_ed25519_common.c81
-rw-r--r--tests/unittests/torture_pki_ed25519.c73
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)