mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-11 02:38:09 +09:00
Use Ed25519 in OpenSSL through the EVP_PKEY API
... instead of keeping around public and private key blobs. Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Sahana Prasad <sahana@redhat.com>
This commit is contained in:
@@ -63,11 +63,9 @@ struct ssh_key_struct {
|
|||||||
mbedtls_pk_context *pk;
|
mbedtls_pk_context *pk;
|
||||||
mbedtls_ecdsa_context *ecdsa;
|
mbedtls_ecdsa_context *ecdsa;
|
||||||
#elif defined(HAVE_LIBCRYPTO)
|
#elif defined(HAVE_LIBCRYPTO)
|
||||||
/* This holds either ENGINE key for PKCS#11 support or just key in
|
/* This holds either ENGINE/PROVIDER key for PKCS#11 support
|
||||||
* high-level format */
|
* or just key in high-level format */
|
||||||
EVP_PKEY *key;
|
EVP_PKEY *key;
|
||||||
uint8_t *ed25519_pubkey;
|
|
||||||
uint8_t *ed25519_privkey;
|
|
||||||
#endif /* HAVE_LIBGCRYPT */
|
#endif /* HAVE_LIBGCRYPT */
|
||||||
#ifndef HAVE_LIBCRYPTO
|
#ifndef HAVE_LIBCRYPTO
|
||||||
ed25519_pubkey *ed25519_pubkey;
|
ed25519_pubkey *ed25519_pubkey;
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
|
|||||||
int pki_privkey_build_ed25519(ssh_key key,
|
int pki_privkey_build_ed25519(ssh_key key,
|
||||||
ssh_string pubkey,
|
ssh_string pubkey,
|
||||||
ssh_string privkey);
|
ssh_string privkey);
|
||||||
|
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey);
|
||||||
|
|
||||||
/* PKI Container OpenSSH */
|
/* PKI Container OpenSSH */
|
||||||
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key);
|
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key);
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld, EVP_PKEY **pkey,
|
|||||||
int evp_dup_dsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
int evp_dup_dsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||||
int evp_dup_rsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
int evp_dup_rsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||||
int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||||
|
int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||||
#endif /* HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER */
|
#endif /* HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -1543,6 +1543,12 @@ int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote)
|
|||||||
{
|
{
|
||||||
return evp_dup_pkey("EC", key, demote, new_key);
|
return evp_dup_pkey("EC", key, demote, new_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote)
|
||||||
|
{
|
||||||
|
return evp_dup_pkey("ED25519", key, demote, new_key);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
|
||||||
ssh_string
|
ssh_string
|
||||||
|
|||||||
26
src/pki.c
26
src/pki.c
@@ -143,18 +143,13 @@ void ssh_key_clean (ssh_key key)
|
|||||||
|
|
||||||
pki_key_clean(key);
|
pki_key_clean(key);
|
||||||
|
|
||||||
if (key->ed25519_privkey != NULL){
|
#ifndef HAVE_LIBCRYPTO
|
||||||
#ifdef HAVE_LIBCRYPTO
|
if (key->ed25519_privkey != NULL) {
|
||||||
/* 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 /* HAVE_LIBCRYPTO*/
|
|
||||||
SAFE_FREE(key->ed25519_privkey);
|
SAFE_FREE(key->ed25519_privkey);
|
||||||
}
|
}
|
||||||
SAFE_FREE(key->ed25519_pubkey);
|
SAFE_FREE(key->ed25519_pubkey);
|
||||||
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
if (key->cert != NULL) {
|
if (key->cert != NULL) {
|
||||||
SSH_BUFFER_FREE(key->cert);
|
SSH_BUFFER_FREE(key->cert);
|
||||||
}
|
}
|
||||||
@@ -701,10 +696,12 @@ int ssh_key_cmp(const ssh_key k1,
|
|||||||
ssh_buffer_get_len(k1->cert));
|
ssh_buffer_get_len(k1->cert));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBCRYPTO
|
||||||
if (k1->type == SSH_KEYTYPE_ED25519 ||
|
if (k1->type == SSH_KEYTYPE_ED25519 ||
|
||||||
k1->type == SSH_KEYTYPE_SK_ED25519) {
|
k1->type == SSH_KEYTYPE_SK_ED25519) {
|
||||||
return pki_ed25519_key_cmp(k1, k2, what);
|
return pki_ed25519_key_cmp(k1, k2, what);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return pki_key_compare(k1, k2, what);
|
return pki_key_compare(k1, k2, what);
|
||||||
}
|
}
|
||||||
@@ -1489,16 +1486,13 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
rc = pki_pubkey_build_ed25519(key, pubkey);
|
||||||
if (key->ed25519_pubkey == NULL) {
|
|
||||||
ssh_string_burn(pubkey);
|
|
||||||
SSH_STRING_FREE(pubkey);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
if (rc < 0) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Failed to build ED25519 public key");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == SSH_KEYTYPE_SK_ED25519) {
|
if (type == SSH_KEYTYPE_SK_ED25519) {
|
||||||
ssh_string application = ssh_buffer_get_ssh_string(buffer);
|
ssh_string application = ssh_buffer_get_ssh_string(buffer);
|
||||||
|
|||||||
319
src/pki_crypto.c
319
src/pki_crypto.c
@@ -415,6 +415,59 @@ err:
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_OPENSSL_ECC */
|
#endif /* HAVE_OPENSSL_ECC */
|
||||||
|
|
||||||
|
int pki_privkey_build_ed25519(ssh_key key,
|
||||||
|
ssh_string pubkey,
|
||||||
|
ssh_string privkey)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
|
||||||
|
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
|
||||||
|
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519,
|
||||||
|
NULL,
|
||||||
|
(const uint8_t *)ssh_string_data(privkey),
|
||||||
|
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 SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
key->key = pkey;
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
|
||||||
|
if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519,
|
||||||
|
NULL,
|
||||||
|
(const uint8_t *)ssh_string_data(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 SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
key->key = pkey;
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
ssh_key pki_key_dup(const ssh_key key, int demote)
|
ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||||
{
|
{
|
||||||
ssh_key new = NULL;
|
ssh_key new = NULL;
|
||||||
@@ -651,7 +704,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
|||||||
break;
|
break;
|
||||||
#endif /* HAVE_OPENSSL_ECC */
|
#endif /* HAVE_OPENSSL_ECC */
|
||||||
case SSH_KEYTYPE_ED25519:
|
case SSH_KEYTYPE_ED25519:
|
||||||
rc = pki_ed25519_key_dup(new, key);
|
rc = evp_dup_ed25519_pkey(key, new, demote);
|
||||||
if (rc != SSH_OK) {
|
if (rc != SSH_OK) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -865,14 +918,13 @@ int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
|
|||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
case SSH_KEYTYPE_RSA:
|
case SSH_KEYTYPE_RSA:
|
||||||
case SSH_KEYTYPE_RSA1:
|
case SSH_KEYTYPE_RSA1:
|
||||||
|
case SSH_KEYTYPE_ED25519:
|
||||||
|
case SSH_KEYTYPE_SK_ED25519:
|
||||||
rc = EVP_PKEY_eq(k1->key, k2->key);
|
rc = EVP_PKEY_eq(k1->key, k2->key);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_KEYTYPE_ED25519:
|
|
||||||
case SSH_KEYTYPE_SK_ED25519:
|
|
||||||
/* ed25519 keys handled globally */
|
|
||||||
case SSH_KEYTYPE_UNKNOWN:
|
case SSH_KEYTYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
@@ -902,6 +954,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
|
|||||||
case SSH_KEYTYPE_ECDSA_P256:
|
case SSH_KEYTYPE_ECDSA_P256:
|
||||||
case SSH_KEYTYPE_ECDSA_P384:
|
case SSH_KEYTYPE_ECDSA_P384:
|
||||||
case SSH_KEYTYPE_ECDSA_P521:
|
case SSH_KEYTYPE_ECDSA_P521:
|
||||||
|
case SSH_KEYTYPE_ED25519:
|
||||||
rc = EVP_PKEY_up_ref(key->key);
|
rc = EVP_PKEY_up_ref(key->key);
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
goto err;
|
goto err;
|
||||||
@@ -911,24 +964,6 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
|
|||||||
/* Mark the operation as successful as for the other key types */
|
/* Mark the operation as successful as for the other key types */
|
||||||
rc = 1;
|
rc = 1;
|
||||||
|
|
||||||
break;
|
|
||||||
case SSH_KEYTYPE_ED25519:
|
|
||||||
/* 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) */
|
|
||||||
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519,
|
|
||||||
NULL,
|
|
||||||
(const uint8_t *)key->ed25519_privkey,
|
|
||||||
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));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark the operation as successful as for the other key types */
|
|
||||||
rc = 1;
|
|
||||||
break;
|
break;
|
||||||
case SSH_KEYTYPE_RSA_CERT01:
|
case SSH_KEYTYPE_RSA_CERT01:
|
||||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||||
@@ -1008,8 +1043,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
|||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
EC_KEY *ecdsa = NULL;
|
EC_KEY *ecdsa = NULL;
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
uint8_t *ed25519 = NULL;
|
|
||||||
uint8_t *ed25519_pubkey = NULL;
|
|
||||||
ssh_key key = NULL;
|
ssh_key key = NULL;
|
||||||
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
|
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
|
||||||
EVP_PKEY *pkey = NULL;
|
EVP_PKEY *pkey = NULL;
|
||||||
@@ -1068,57 +1101,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
|||||||
break;
|
break;
|
||||||
#endif /* HAVE_OPENSSL_ECC */
|
#endif /* HAVE_OPENSSL_ECC */
|
||||||
case EVP_PKEY_ED25519:
|
case EVP_PKEY_ED25519:
|
||||||
{
|
|
||||||
size_t key_len;
|
|
||||||
int evp_rc = 0;
|
|
||||||
|
|
||||||
/* Get the key length */
|
|
||||||
evp_rc = EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len);
|
|
||||||
if (evp_rc != 1) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"Failed to get ed25519 raw private key length: %s",
|
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key_len != ED25519_KEY_LEN) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ed25519 = malloc(key_len);
|
|
||||||
if (ed25519 == NULL) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)ed25519,
|
|
||||||
&key_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 fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* length matches the private key length */
|
|
||||||
ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
|
||||||
if (ed25519_pubkey == NULL) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
evp_rc = EVP_PKEY_get_raw_public_key(pkey, (uint8_t *)ed25519_pubkey,
|
|
||||||
&key_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 fail;
|
|
||||||
}
|
|
||||||
type = SSH_KEYTYPE_ED25519;
|
type = SSH_KEYTYPE_ED25519;
|
||||||
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d",
|
SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d",
|
||||||
EVP_PKEY_base_id(pkey));
|
EVP_PKEY_base_id(pkey));
|
||||||
@@ -1135,8 +1119,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
|||||||
key->type_c = ssh_key_type_to_char(type);
|
key->type_c = ssh_key_type_to_char(type);
|
||||||
key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
|
key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
|
||||||
key->key = pkey;
|
key->key = pkey;
|
||||||
key->ed25519_privkey = ed25519;
|
|
||||||
key->ed25519_pubkey = ed25519_pubkey;
|
|
||||||
#ifdef HAVE_OPENSSL_ECC
|
#ifdef HAVE_OPENSSL_ECC
|
||||||
if (is_ecdsa_key_type(key->type)) {
|
if (is_ecdsa_key_type(key->type)) {
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||||
@@ -1151,8 +1133,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
|||||||
fail:
|
fail:
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
ssh_key_free(key);
|
ssh_key_free(key);
|
||||||
SAFE_FREE(ed25519);
|
|
||||||
SAFE_FREE(ed25519_pubkey);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1408,8 +1388,8 @@ fail:
|
|||||||
|
|
||||||
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||||
{
|
{
|
||||||
ssh_buffer buffer;
|
ssh_buffer buffer = NULL;
|
||||||
ssh_string type_s;
|
ssh_string type_s = NULL;
|
||||||
ssh_string str = NULL;
|
ssh_string str = NULL;
|
||||||
ssh_string e = NULL;
|
ssh_string e = NULL;
|
||||||
ssh_string n = NULL;
|
ssh_string n = NULL;
|
||||||
@@ -1425,6 +1405,9 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
|||||||
*bd = NULL, *biqmp = NULL;
|
*bd = NULL, *biqmp = NULL;
|
||||||
OSSL_PARAM *params = NULL;
|
OSSL_PARAM *params = NULL;
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
uint8_t *ed25519_pubkey = NULL;
|
||||||
|
uint8_t *ed25519_privkey = NULL;
|
||||||
|
size_t key_len = 0;
|
||||||
|
|
||||||
buffer = ssh_buffer_new();
|
buffer = ssh_buffer_new();
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
@@ -1632,11 +1615,94 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
|||||||
}
|
}
|
||||||
case SSH_KEYTYPE_ED25519:
|
case SSH_KEYTYPE_ED25519:
|
||||||
case SSH_KEYTYPE_SK_ED25519:
|
case SSH_KEYTYPE_SK_ED25519:
|
||||||
if (type == SSH_KEY_PUBLIC) {
|
rc = EVP_PKEY_get_raw_public_key(key->key, NULL, &key_len);
|
||||||
rc = pki_ed25519_public_key_to_blob(buffer, key);
|
if (rc != 1) {
|
||||||
if (rc == SSH_ERROR){
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
|
"Failed to get ed25519 raw public key length: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_len != ED25519_KEY_LEN) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
|
"Unexpected length of private key %zu. Expected %d.",
|
||||||
|
key_len,
|
||||||
|
ED25519_KEY_LEN);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ed25519_pubkey = malloc(key_len);
|
||||||
|
if (ed25519_pubkey == NULL) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = EVP_PKEY_get_raw_public_key(key->key,
|
||||||
|
(uint8_t *)ed25519_pubkey,
|
||||||
|
&key_len);
|
||||||
|
if (rc != 1) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
|
"Failed to get ed25519 raw public key: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_buffer_pack(buffer,
|
||||||
|
"dP",
|
||||||
|
(uint32_t)ED25519_KEY_LEN,
|
||||||
|
(size_t)ED25519_KEY_LEN,
|
||||||
|
ed25519_pubkey);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == SSH_KEY_PRIVATE) {
|
||||||
|
key_len = 0;
|
||||||
|
rc = EVP_PKEY_get_raw_private_key(key->key, NULL, &key_len);
|
||||||
|
if (rc != 1) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
|
"Failed to get ed25519 raw private key length: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key_len != ED25519_KEY_LEN) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
|
"Unexpected length of private key %zu. Expected %d.",
|
||||||
|
key_len,
|
||||||
|
ED25519_KEY_LEN);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ed25519_privkey = malloc(key_len);
|
||||||
|
if (ed25519_privkey == NULL) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = EVP_PKEY_get_raw_private_key(key->key,
|
||||||
|
ed25519_privkey,
|
||||||
|
&key_len);
|
||||||
|
if (rc != 1) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE,
|
||||||
|
"Failed to get ed25519 raw private key: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_buffer_pack(buffer,
|
||||||
|
"dPP",
|
||||||
|
(uint32_t)(2 * ED25519_KEY_LEN),
|
||||||
|
(size_t)ED25519_KEY_LEN,
|
||||||
|
ed25519_privkey,
|
||||||
|
(size_t)ED25519_KEY_LEN,
|
||||||
|
ed25519_pubkey);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
explicit_bzero(ed25519_privkey, ED25519_KEY_LEN);
|
||||||
|
SAFE_FREE(ed25519_privkey);
|
||||||
|
} else {
|
||||||
/* public key can contain certificate sk information */
|
/* public key can contain certificate sk information */
|
||||||
if (key->type == SSH_KEYTYPE_SK_ED25519) {
|
if (key->type == SSH_KEYTYPE_SK_ED25519) {
|
||||||
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
||||||
@@ -1644,12 +1710,8 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
rc = pki_ed25519_private_key_to_blob(buffer, key);
|
|
||||||
if (rc == SSH_ERROR){
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
SAFE_FREE(ed25519_pubkey);
|
||||||
break;
|
break;
|
||||||
case SSH_KEYTYPE_ECDSA_P256:
|
case SSH_KEYTYPE_ECDSA_P256:
|
||||||
case SSH_KEYTYPE_ECDSA_P384:
|
case SSH_KEYTYPE_ECDSA_P384:
|
||||||
@@ -1849,6 +1911,11 @@ fail:
|
|||||||
bignum_safe_free(biqmp);
|
bignum_safe_free(biqmp);
|
||||||
OSSL_PARAM_free(params);
|
OSSL_PARAM_free(params);
|
||||||
#endif /* OPENSSL_VERSION_NUMBER */
|
#endif /* OPENSSL_VERSION_NUMBER */
|
||||||
|
free(ed25519_pubkey);
|
||||||
|
if (ed25519_privkey) {
|
||||||
|
explicit_bzero(ed25519_privkey, ED25519_KEY_LEN);
|
||||||
|
free(ed25519_privkey);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2300,6 +2367,10 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
|
|||||||
case SSH_KEYTYPE_ECDSA_P521_CERT01:
|
case SSH_KEYTYPE_ECDSA_P521_CERT01:
|
||||||
case SSH_KEYTYPE_SK_ECDSA:
|
case SSH_KEYTYPE_SK_ECDSA:
|
||||||
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
||||||
|
case SSH_KEYTYPE_ED25519:
|
||||||
|
case SSH_KEYTYPE_ED25519_CERT01:
|
||||||
|
case SSH_KEYTYPE_SK_ED25519:
|
||||||
|
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
||||||
if (key->key == NULL) {
|
if (key->key == NULL) {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "NULL key->key");
|
SSH_LOG(SSH_LOG_TRACE, "NULL key->key");
|
||||||
goto error;
|
goto error;
|
||||||
@@ -2311,37 +2382,6 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
|
|||||||
}
|
}
|
||||||
pkey = key->key;
|
pkey = key->key;
|
||||||
break;
|
break;
|
||||||
case SSH_KEYTYPE_ED25519:
|
|
||||||
case SSH_KEYTYPE_ED25519_CERT01:
|
|
||||||
case SSH_KEYTYPE_SK_ED25519:
|
|
||||||
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
|
||||||
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;
|
|
||||||
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",
|
||||||
@@ -2628,8 +2668,6 @@ int pki_key_generate_ed25519(ssh_key key)
|
|||||||
int evp_rc;
|
int evp_rc;
|
||||||
EVP_PKEY_CTX *pctx = NULL;
|
EVP_PKEY_CTX *pctx = NULL;
|
||||||
EVP_PKEY *pkey = NULL;
|
EVP_PKEY *pkey = NULL;
|
||||||
size_t privkey_len = ED25519_KEY_LEN;
|
|
||||||
size_t pubkey_len = ED25519_KEY_LEN;
|
|
||||||
|
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@@ -2658,41 +2696,9 @@ int pki_key_generate_ed25519(ssh_key key)
|
|||||||
ERR_error_string(ERR_get_error(), NULL));
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
key->key = pkey;
|
||||||
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_CTX_free(pctx);
|
||||||
EVP_PKEY_free(pkey);
|
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -2702,8 +2708,6 @@ error:
|
|||||||
if (pkey != NULL) {
|
if (pkey != NULL) {
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
}
|
}
|
||||||
SAFE_FREE(key->ed25519_privkey);
|
|
||||||
SAFE_FREE(key->ed25519_pubkey);
|
|
||||||
|
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
@@ -2872,6 +2876,9 @@ int pki_uri_import(const char *uri_name,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case EVP_PKEY_ED25519:
|
||||||
|
type = SSH_KEYTYPE_ED25519;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid public key type %d",
|
SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid public key type %d",
|
||||||
EVP_PKEY_base_id(pkey));
|
EVP_PKEY_base_id(pkey));
|
||||||
|
|||||||
@@ -28,6 +28,205 @@
|
|||||||
#include "libssh/ed25519.h"
|
#include "libssh/ed25519.h"
|
||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
|
|
||||||
|
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey)
|
||||||
|
{
|
||||||
|
if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||||
|
if (key->ed25519_pubkey == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pki_privkey_build_ed25519(ssh_key key,
|
||||||
|
ssh_string pubkey,
|
||||||
|
ssh_string privkey)
|
||||||
|
{
|
||||||
|
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
|
||||||
|
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
if (key->ed25519_privkey == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||||
|
if (key->ed25519_pubkey == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(key->ed25519_privkey, ssh_string_data(privkey), 2 * ED25519_KEY_LEN);
|
||||||
|
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
SAFE_FREE(key->ed25519_privkey);
|
||||||
|
SAFE_FREE(key->ed25519_pubkey);
|
||||||
|
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Compare ed25519 keys if they are equal.
|
||||||
|
*
|
||||||
|
* @param[in] k1 The first key to compare.
|
||||||
|
*
|
||||||
|
* @param[in] k2 The second key to compare.
|
||||||
|
*
|
||||||
|
* @param[in] what What part or type of the key do you want to compare.
|
||||||
|
*
|
||||||
|
* @return 0 if equal, 1 if not.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pki_ed25519_key_cmp(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
|
||||||
|
{
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
switch (what) {
|
||||||
|
case SSH_KEY_CMP_PRIVATE:
|
||||||
|
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* 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);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
FALL_THROUGH;
|
||||||
|
case SSH_KEY_CMP_PUBLIC:
|
||||||
|
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
|
||||||
|
if (cmp != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SSH_KEY_CMP_CERTIFICATE:
|
||||||
|
/* handled globally */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Duplicate an Ed25519 key
|
||||||
|
*
|
||||||
|
* @param[out] new Pre-initialized ssh_key structure
|
||||||
|
*
|
||||||
|
* @param[in] key Key to copy
|
||||||
|
*
|
||||||
|
* @return SSH_ERROR on error, SSH_OK on success
|
||||||
|
*/
|
||||||
|
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key)
|
||||||
|
{
|
||||||
|
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key->ed25519_privkey != NULL) {
|
||||||
|
/* In the internal implementation, the private key is the concatenation
|
||||||
|
* of the private seed with the public key. */
|
||||||
|
new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||||
|
if (new_key->ed25519_privkey == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
memcpy(new_key->ed25519_privkey,
|
||||||
|
key->ed25519_privkey,
|
||||||
|
2 * ED25519_KEY_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key->ed25519_pubkey != NULL) {
|
||||||
|
new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||||
|
if (new_key->ed25519_pubkey == NULL) {
|
||||||
|
SAFE_FREE(new_key->ed25519_privkey);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Outputs an Ed25519 public key in a blob buffer.
|
||||||
|
*
|
||||||
|
* @param[out] buffer Output buffer
|
||||||
|
*
|
||||||
|
* @param[in] key Key to output
|
||||||
|
*
|
||||||
|
* @return SSH_ERROR on error, SSH_OK on success
|
||||||
|
*/
|
||||||
|
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (key->ed25519_pubkey == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_buffer_pack(buffer,
|
||||||
|
"dP",
|
||||||
|
(uint32_t)ED25519_KEY_LEN,
|
||||||
|
(size_t)ED25519_KEY_LEN,
|
||||||
|
key->ed25519_pubkey);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief exports a ed25519 private key to a string blob.
|
||||||
|
* @param[in] privkey private key to convert
|
||||||
|
* @param[out] buffer buffer to write the blob in.
|
||||||
|
* @returns SSH_OK on success
|
||||||
|
*/
|
||||||
|
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (privkey->type != SSH_KEYTYPE_ED25519) {
|
||||||
|
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
if (privkey->ed25519_privkey == NULL || privkey->ed25519_pubkey == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
rc = ssh_buffer_pack(buffer,
|
||||||
|
"dPdPP",
|
||||||
|
(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;
|
||||||
|
}
|
||||||
|
|
||||||
int pki_key_generate_ed25519(ssh_key key)
|
int pki_key_generate_ed25519(ssh_key key)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|||||||
@@ -27,213 +27,6 @@
|
|||||||
#include "libssh/pki_priv.h"
|
#include "libssh/pki_priv.h"
|
||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
|
|
||||||
int pki_privkey_build_ed25519(ssh_key key,
|
|
||||||
ssh_string pubkey,
|
|
||||||
ssh_string privkey)
|
|
||||||
{
|
|
||||||
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
|
|
||||||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
|
|
||||||
{
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
|
||||||
/* 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_KEY_LEN);
|
|
||||||
if (key->ed25519_pubkey == NULL) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
|
||||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
|
|
||||||
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_KEY_LEN);
|
|
||||||
|
|
||||||
return SSH_OK;
|
|
||||||
|
|
||||||
error:
|
|
||||||
SAFE_FREE(key->ed25519_privkey);
|
|
||||||
SAFE_FREE(key->ed25519_pubkey);
|
|
||||||
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @brief Compare ed25519 keys if they are equal.
|
|
||||||
*
|
|
||||||
* @param[in] k1 The first key to compare.
|
|
||||||
*
|
|
||||||
* @param[in] k2 The second key to compare.
|
|
||||||
*
|
|
||||||
* @param[in] what What part or type of the key do you want to compare.
|
|
||||||
*
|
|
||||||
* @return 0 if equal, 1 if not.
|
|
||||||
*/
|
|
||||||
int pki_ed25519_key_cmp(const ssh_key k1,
|
|
||||||
const ssh_key k2,
|
|
||||||
enum ssh_keycmp_e what)
|
|
||||||
{
|
|
||||||
int cmp;
|
|
||||||
|
|
||||||
switch(what) {
|
|
||||||
case SSH_KEY_CMP_PRIVATE:
|
|
||||||
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
FALL_THROUGH;
|
|
||||||
case SSH_KEY_CMP_PUBLIC:
|
|
||||||
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
|
|
||||||
if (cmp != 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SSH_KEY_CMP_CERTIFICATE:
|
|
||||||
/* handled globally */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @brief Duplicate an Ed25519 key
|
|
||||||
*
|
|
||||||
* @param[out] new Pre-initialized ssh_key structure
|
|
||||||
*
|
|
||||||
* @param[in] key Key to copy
|
|
||||||
*
|
|
||||||
* @return SSH_ERROR on error, SSH_OK on success
|
|
||||||
*/
|
|
||||||
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key)
|
|
||||||
{
|
|
||||||
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key->ed25519_privkey != NULL) {
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
|
||||||
/* In OpenSSL implementation, the private key is the original private
|
|
||||||
* seed, without the public key. */
|
|
||||||
new_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. */
|
|
||||||
new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
|
||||||
#endif
|
|
||||||
if (new_key->ed25519_privkey == NULL) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
#ifdef HAVE_LIBCRYPTO
|
|
||||||
memcpy(new_key->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
|
|
||||||
#else
|
|
||||||
memcpy(new_key->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key->ed25519_pubkey != NULL) {
|
|
||||||
new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
|
||||||
if (new_key->ed25519_pubkey == NULL) {
|
|
||||||
SAFE_FREE(new_key->ed25519_privkey);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SSH_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @brief Outputs an Ed25519 public key in a blob buffer.
|
|
||||||
*
|
|
||||||
* @param[out] buffer Output buffer
|
|
||||||
*
|
|
||||||
* @param[in] key Key to output
|
|
||||||
*
|
|
||||||
* @return SSH_ERROR on error, SSH_OK on success
|
|
||||||
*/
|
|
||||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (key->ed25519_pubkey == NULL){
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ssh_buffer_pack(buffer,
|
|
||||||
"dP",
|
|
||||||
(uint32_t)ED25519_KEY_LEN,
|
|
||||||
(size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal
|
|
||||||
* @brief exports a ed25519 private key to a string blob.
|
|
||||||
* @param[in] privkey private key to convert
|
|
||||||
* @param[out] buffer buffer to write the blob in.
|
|
||||||
* @returns SSH_OK on success
|
|
||||||
*/
|
|
||||||
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (privkey->type != SSH_KEYTYPE_ED25519) {
|
|
||||||
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
if (privkey->ed25519_privkey == NULL ||
|
|
||||||
privkey->ed25519_pubkey == NULL) {
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
rc = ssh_buffer_pack(buffer,
|
|
||||||
"dPdPP",
|
|
||||||
(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user