1
1

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>
Этот коммит содержится в:
Anderson Toshiyuki Sasaki 2019-08-22 18:11:13 +02:00
родитель bdcaf55b90
Коммит 2a2c1c98bf
7 изменённых файлов: 343 добавлений и 60 удалений

Просмотреть файл

@ -30,7 +30,15 @@
#endif #endif
#include "libssh/crypto.h" #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" #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_PUBKEY_SIZE 0x100000 /* 1M */
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */ #define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
@ -61,8 +69,13 @@ struct ssh_key_struct {
void *ecdsa; void *ecdsa;
# endif /* HAVE_OPENSSL_EC_H */ # endif /* HAVE_OPENSSL_EC_H */
#endif /* HAVE_LIBGCRYPT */ #endif /* HAVE_LIBGCRYPT */
#ifdef HAVE_OPENSSL_ED25519
uint8_t *ed25519_pubkey;
uint8_t *ed25519_privkey;
#else
ed25519_pubkey *ed25519_pubkey; ed25519_pubkey *ed25519_pubkey;
ed25519_privkey *ed25519_privkey; ed25519_privkey *ed25519_privkey;
#endif
void *cert; void *cert;
enum ssh_keytypes_e cert_type; enum ssh_keytypes_e cert_type;
}; };
@ -79,7 +92,9 @@ struct ssh_signature_struct {
ssh_string rsa_sig; ssh_string rsa_sig;
struct mbedtls_ecdsa_sig ecdsa_sig; struct mbedtls_ecdsa_sig ecdsa_sig;
#endif /* HAVE_LIBGCRYPT */ #endif /* HAVE_LIBGCRYPT */
#ifndef HAVE_OPENSSL_ED25519
ed25519_signature *ed25519_sig; ed25519_signature *ed25519_sig;
#endif
ssh_string raw_sig; ssh_string raw_sig;
}; };

Просмотреть файл

@ -146,7 +146,6 @@ set(libssh_SRCS
pcap.c pcap.c
pki.c pki.c
pki_container_openssh.c pki_container_openssh.c
pki_ed25519.c
poll.c poll.c
session.c session.c
scp.c scp.c
@ -202,6 +201,7 @@ if (WITH_GCRYPT)
pki_gcrypt.c pki_gcrypt.c
ecdh_gcrypt.c ecdh_gcrypt.c
dh_key.c dh_key.c
pki_ed25519.c
) )
elseif (WITH_MBEDTLS) elseif (WITH_MBEDTLS)
set(libssh_SRCS set(libssh_SRCS
@ -212,6 +212,7 @@ elseif (WITH_MBEDTLS)
pki_mbedcrypto.c pki_mbedcrypto.c
ecdh_mbedcrypto.c ecdh_mbedcrypto.c
dh_key.c dh_key.c
pki_ed25519.c
) )
else (WITH_GCRYPT) else (WITH_GCRYPT)
set(libssh_SRCS set(libssh_SRCS
@ -222,6 +223,12 @@ else (WITH_GCRYPT)
libcrypto.c libcrypto.c
dh_crypto.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") if(OPENSSL_VERSION VERSION_LESS "1.1.0")
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c) set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
endif() endif()

Просмотреть файл

@ -162,7 +162,14 @@ void ssh_key_clean (ssh_key key){
} }
#endif #endif
if (key->ed25519_privkey != NULL){ 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)); explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey));
#endif
SAFE_FREE(key->ed25519_privkey); SAFE_FREE(key->ed25519_privkey);
} }
SAFE_FREE(key->ed25519_pubkey); SAFE_FREE(key->ed25519_pubkey);
@ -679,7 +686,10 @@ void ssh_signature_free(ssh_signature sig)
#endif #endif
break; break;
case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_ED25519:
#ifndef HAVE_OPENSSL_ED25519
/* When using OpenSSL, the signature is stored in sig->raw_sig */
SAFE_FREE(sig->ed25519_sig); SAFE_FREE(sig->ed25519_sig);
#endif
break; break;
case SSH_KEYTYPE_DSS_CERT01: case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_RSA_CERT01:
@ -1321,21 +1331,21 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_ED25519:
{ {
ssh_string pubkey = ssh_buffer_get_ssh_string(buffer); 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_LOG(SSH_LOG_WARN, "Invalid public key length");
ssh_string_burn(pubkey); ssh_string_burn(pubkey);
ssh_string_free(pubkey); ssh_string_free(pubkey);
goto fail; goto fail;
} }
key->ed25519_pubkey = malloc(ED25519_PK_LEN); key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) { if (key->ed25519_pubkey == NULL) {
ssh_string_burn(pubkey); ssh_string_burn(pubkey);
ssh_string_free(pubkey); ssh_string_free(pubkey);
goto fail; 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_burn(pubkey);
ssh_string_free(pubkey); ssh_string_free(pubkey);
} }
@ -2259,7 +2269,7 @@ int ssh_pki_signature_verify(ssh_session session,
return SSH_ERROR; 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; return rc;
} }
@ -2283,12 +2293,6 @@ ssh_signature pki_do_sign(const ssh_key privkey,
return NULL; 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); return pki_sign_data(privkey, hash_type, input, input_len);
} }

Просмотреть файл

@ -415,12 +415,13 @@ static int pki_openssh_export_privkey_blob(const ssh_key privkey,
return SSH_ERROR; return SSH_ERROR;
} }
rc = ssh_buffer_pack(buffer, rc = ssh_buffer_pack(buffer,
"sdPdP", "sdPdPP",
privkey->type_c, privkey->type_c,
(uint32_t)ED25519_PK_LEN, (uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_PK_LEN, privkey->ed25519_pubkey, (size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
(uint32_t)ED25519_SK_LEN, (uint32_t)(2 * ED25519_KEY_LEN),
(size_t)ED25519_SK_LEN, privkey->ed25519_privkey); (size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
return rc; return rc;
} }

Просмотреть файл

@ -821,7 +821,11 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
BIO *mem = NULL; BIO *mem = NULL;
DSA *dsa = NULL; DSA *dsa = NULL;
RSA *rsa = NULL; RSA *rsa = NULL;
#ifdef HAVE_OPENSSL_ED25519
uint8_t *ed25519 = NULL;
#else
ed25519_privkey *ed25519 = NULL; ed25519_privkey *ed25519 = NULL;
#endif
ssh_key key = NULL; ssh_key key = NULL;
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN; enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
#ifdef HAVE_OPENSSL_ECC #ifdef HAVE_OPENSSL_ECC
@ -1880,15 +1884,7 @@ int pki_signature_verify(ssh_session session,
return SSH_ERROR; return SSH_ERROR;
} }
/* For ed25519 keys, verify using the input directly */ rc = pki_verify_data_signature(sig, key, input, input_len);
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);
}
if (rc != SSH_OK){ if (rc != SSH_OK){
ssh_set_error(session, 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(); md = EVP_sha1();
break; break;
case SSH_DIGEST_AUTO: case SSH_DIGEST_AUTO:
md = NULL;
break;
default: default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d", SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type); hash_type);
@ -1931,12 +1929,6 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
{ {
EVP_PKEY *pkey = NULL; EVP_PKEY *pkey = NULL;
pkey = EVP_PKEY_new();
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
return NULL;
}
switch(key->type) { switch(key->type) {
case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS:
case SSH_KEYTYPE_DSS_CERT01: 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"); SSH_LOG(SSH_LOG_TRACE, "NULL key->dsa");
goto error; 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); EVP_PKEY_set1_DSA(pkey, key->dsa);
break; break;
case SSH_KEYTYPE_RSA: 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"); SSH_LOG(SSH_LOG_TRACE, "NULL key->rsa");
goto error; 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); EVP_PKEY_set1_RSA(pkey, key->rsa);
break; break;
case SSH_KEYTYPE_ECDSA_P256: 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"); SSH_LOG(SSH_LOG_TRACE, "NULL key->ecdsa");
goto error; 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); EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
break; break;
# endif # endif
case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_ED25519:
/* Not supported yet. This type requires the use of EVP_DigestSign*() case SSH_KEYTYPE_ED25519_CERT01:
* API and ECX keys. There is no EVP_set1_ECX_KEY() or equivalent yet. */ # 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: case SSH_KEYTYPE_UNKNOWN:
default: default:
SSH_LOG(SSH_LOG_TRACE, "Unknown private key algorithm for type: %d", 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; 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 */ /* Set hash algorithm to be used */
md = pki_digest_to_md(hash_type); md = pki_digest_to_md(hash_type);
if (md == NULL) { if (md == NULL) {
return NULL; if (hash_type != SSH_DIGEST_AUTO) {
return NULL;
}
} }
/* Setup private key EVP_PKEY */ /* Setup private key EVP_PKEY */
@ -2160,7 +2208,11 @@ int pki_verify_data_signature(ssh_signature signature,
int evp_rc; int evp_rc;
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL || 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 " SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
"pki_verify_data_signature()"); "pki_verify_data_signature()");
@ -2173,6 +2225,14 @@ int pki_verify_data_signature(ssh_signature signature,
return SSH_ERROR; 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 */ /* Get the signature to be verified */
raw_sig_data = ssh_string_data(signature->raw_sig); raw_sig_data = ssh_string_data(signature->raw_sig);
raw_sig_len = ssh_string_len(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 */ /* Set hash algorithm to be used */
md = pki_digest_to_md(signature->hash_type); md = pki_digest_to_md(signature->hash_type);
if (md == NULL) { if (md == NULL) {
return SSH_ERROR; if (signature->hash_type != SSH_DIGEST_AUTO) {
return SSH_ERROR;
}
} }
/* Setup public key EVP_PKEY */ /* Setup public key EVP_PKEY */
@ -2243,6 +2305,92 @@ out:
return rc; 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, ssh_signature pki_do_sign_hash(const ssh_key privkey,
const unsigned char *hash, const unsigned char *hash,
size_t hlen, size_t hlen,
@ -2275,4 +2423,6 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
return sig; return sig;
} }
#endif /* HAVE_OPENSSL_ED25519 */
#endif /* _PKI_CRYPTO_H */ #endif /* _PKI_CRYPTO_H */

Просмотреть файл

@ -31,27 +31,40 @@ int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey, ssh_string pubkey,
ssh_string privkey) ssh_string privkey)
{ {
if (ssh_string_len(pubkey) != ED25519_PK_LEN || if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
ssh_string_len(privkey) != ED25519_SK_LEN) ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
{ {
SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len"); SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
return SSH_ERROR; 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) { if (key->ed25519_privkey == NULL) {
goto error; goto error;
} }
key->ed25519_pubkey = malloc(ED25519_PK_LEN); key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) { if (key->ed25519_pubkey == NULL) {
goto error; goto error;
} }
#ifdef HAVE_OPENSSL_ED25519
memcpy(key->ed25519_privkey, ssh_string_data(privkey), 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), memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
ED25519_PK_LEN); ED25519_KEY_LEN);
return SSH_OK; 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) { if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
return 1; 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) { if (cmp != 0) {
return 1; return 1;
} }
@ -95,7 +117,7 @@ int pki_ed25519_key_cmp(const ssh_key k1,
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) { if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
return 1; 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) { if (cmp != 0) {
return 1; return 1;
} }
@ -122,20 +144,32 @@ int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
} }
if (key->ed25519_privkey != NULL) { 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) { if (new->ed25519_privkey == NULL) {
return SSH_ERROR; 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) { if (key->ed25519_pubkey != NULL) {
new->ed25519_pubkey = malloc(ED25519_PK_LEN); new->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (new->ed25519_pubkey == NULL) { if (new->ed25519_pubkey == NULL) {
SAFE_FREE(new->ed25519_privkey); SAFE_FREE(new->ed25519_privkey);
return SSH_ERROR; 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; 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, rc = ssh_buffer_pack(buffer,
"dP", "dP",
(uint32_t)ED25519_PK_LEN, (uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_PK_LEN, key->ed25519_pubkey); (size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
return rc; return rc;
} }
@ -181,16 +215,31 @@ ssh_string pki_ed25519_signature_to_blob(ssh_signature sig)
{ {
ssh_string sig_blob; 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) { if (sig->ed25519_sig == NULL) {
return NULL; return NULL;
} }
#endif
sig_blob = ssh_string_new(ED25519_SIG_LEN); sig_blob = ssh_string_new(ED25519_SIG_LEN);
if (sig_blob == NULL) { if (sig_blob == NULL) {
return 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); ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
#endif
return sig_blob; return sig_blob;
} }
@ -216,11 +265,15 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob)
return SSH_ERROR; return SSH_ERROR;
} }
#ifdef HAVE_OPENSSL_ED25519
sig->raw_sig = ssh_string_copy(sig_blob);
#else
sig->ed25519_sig = malloc(ED25519_SIG_LEN); sig->ed25519_sig = malloc(ED25519_SIG_LEN);
if (sig->ed25519_sig == NULL){ if (sig->ed25519_sig == NULL){
return SSH_ERROR; return SSH_ERROR;
} }
memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN); memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
#endif
return SSH_OK; return SSH_OK;
} }

Просмотреть файл

@ -422,8 +422,16 @@ static void torture_pki_ed25519_generate_key(void **state)
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN; enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
const char *type_char = NULL; const char *type_char = NULL;
ssh_session session=ssh_new(); ssh_session session=ssh_new();
uint8_t *raw_sig_data = NULL;
(void) state; (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); rc = ssh_pki_generate(SSH_KEYTYPE_ED25519, 256, &key);
assert_true(rc == SSH_OK); assert_true(rc == SSH_OK);
assert_non_null(key); 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); assert_true(strcmp(type_char, "ssh-ed25519") == 0);
/* try an invalid signature */ /* 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); rc = pki_signature_verify(session, sign, pubkey, HASH, 20);
assert_true(rc == SSH_ERROR); assert_true(rc == SSH_ERROR);
@ -459,6 +473,13 @@ static void torture_pki_ed25519_cert_verify(void **state)
ssh_session session=ssh_new(); ssh_session session=ssh_new();
(void) state; (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, rc = ssh_pki_import_privkey_file(LIBSSH_ED25519_TESTKEY,
NULL, NULL,
NULL, NULL,
@ -599,10 +620,12 @@ static void torture_pki_ed25519_sign(void **state)
const char *keystring = NULL; const char *keystring = NULL;
int rc; int rc;
(void)state; /* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
sig = ssh_signature_new(); (void)state;
assert_non_null(sig);
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0); keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0);
rc = ssh_pki_import_privkey_base64(keystring, 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_true(rc == SSH_OK);
assert_non_null(privkey); assert_non_null(privkey);
sig->type = SSH_KEYTYPE_ED25519; sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
rc = pki_ed25519_sign(privkey, sig, HASH, sizeof(HASH)); assert_non_null(sig);
assert_true(rc == SSH_OK);
blob = pki_signature_to_blob(sig); blob = pki_signature_to_blob(sig);
assert_non_null(blob); assert_non_null(blob);
@ -632,12 +654,22 @@ static void torture_pki_ed25519_sign(void **state)
static void torture_pki_ed25519_verify(void **state){ static void torture_pki_ed25519_verify(void **state){
ssh_key pubkey = NULL; ssh_key pubkey = NULL;
ssh_signature sig = NULL; ssh_signature sig = NULL;
ssh_session session = NULL;
ssh_string blob = ssh_string_new(ED25519_SIG_LEN); ssh_string blob = ssh_string_new(ED25519_SIG_LEN);
char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1); char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1);
char *ptr = NULL; char *ptr = NULL;
uint8_t *raw_sig_data = NULL;
int rc; int rc;
(void) state; (void) state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
session = ssh_new();
assert_non_null(session);
/* remove trailing comment */ /* remove trailing comment */
ptr = strchr(pkey_ptr, ' '); ptr = strchr(pkey_ptr, ' ');
if(ptr != NULL){ 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); sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO);
assert_non_null(sig); 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); 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); ssh_signature_free(sig);
/* alter signature and expect false result */
SSH_KEY_FREE(pubkey); SSH_KEY_FREE(pubkey);
SSH_STRING_FREE(blob); SSH_STRING_FREE(blob);
free(pkey_ptr); free(pkey_ptr);
ssh_free(session);
} }
static void torture_pki_ed25519_verify_bad(void **state){ static void torture_pki_ed25519_verify_bad(void **state){
ssh_key pubkey = NULL; ssh_key pubkey = NULL;
ssh_signature sig = NULL; ssh_signature sig = NULL;
ssh_session session = NULL;
ssh_string blob = ssh_string_new(ED25519_SIG_LEN); ssh_string blob = ssh_string_new(ED25519_SIG_LEN);
char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1); char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1);
char *ptr = NULL; char *ptr = NULL;
@ -672,6 +716,14 @@ static void torture_pki_ed25519_verify_bad(void **state){
int i; int i;
(void) state; (void) state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
session = ssh_new();
assert_non_null(session);
/* remove trailing comment */ /* remove trailing comment */
ptr = strchr(pkey_ptr, ' '); ptr = strchr(pkey_ptr, ' ');
if(ptr != NULL){ 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); sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO);
assert_non_null(sig); 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); assert_true(rc == SSH_ERROR);
ssh_signature_free(sig); ssh_signature_free(sig);
@ -697,6 +749,7 @@ static void torture_pki_ed25519_verify_bad(void **state){
SSH_KEY_FREE(pubkey); SSH_KEY_FREE(pubkey);
SSH_STRING_FREE(blob); SSH_STRING_FREE(blob);
free(pkey_ptr); free(pkey_ptr);
ssh_free(session);
} }
static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state) static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state)