diff options
author | Anderson Toshiyuki Sasaki <ansasaki@redhat.com> | 2019-08-30 18:41:16 +0200 |
---|---|---|
committer | Anderson Toshiyuki Sasaki <ansasaki@redhat.com> | 2019-09-24 16:49:35 +0200 |
commit | a3a0529b41e5ce4789cc8a5bd5e09b4ed15efe32 (patch) | |
tree | 25a31744b2bdffad775c6329a6dd6c7da0ef6adb /src/pki_crypto.c | |
parent | 61e6b6cc59eb18ed2a226974eed2da9e51e9db88 (diff) | |
download | libssh-a3a0529b41e5ce4789cc8a5bd5e09b4ed15efe32.tar.gz libssh-a3a0529b41e5ce4789cc8a5bd5e09b4ed15efe32.tar.xz libssh-a3a0529b41e5ce4789cc8a5bd5e09b4ed15efe32.zip |
pki_crypto: Support Ed25519 keys in PEM files
This adds support for Ed25519 keys from files in PEM format when using
OpenSSL with Ed25519 support. The default encoding for the PEM file is
expected to be PKCS#8. Encrypted files are supported.
For the lack of an API, it is not possible to export keys in PEM format,
only in OpenSSH format.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Diffstat (limited to 'src/pki_crypto.c')
-rw-r--r-- | src/pki_crypto.c | 87 |
1 files changed, 78 insertions, 9 deletions
diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 13198249..4517e11d 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -730,29 +730,58 @@ ssh_string pki_private_key_to_pem(const ssh_key key, return NULL; } - pkey = EVP_PKEY_new(); - if (pkey == NULL) { - goto err; - } - switch (key->type) { case SSH_KEYTYPE_DSS: + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + goto err; + } + rc = EVP_PKEY_set1_DSA(pkey, key->dsa); break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + goto err; + } + rc = EVP_PKEY_set1_RSA(pkey, key->rsa); break; #ifdef HAVE_ECC case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P521: + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + goto err; + } + rc = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa); break; #endif case SSH_KEYTYPE_ED25519: +#ifdef HAVE_OPENSSL_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; +#else SSH_LOG(SSH_LOG_WARN, "PEM output not supported for key type ssh-ed25519"); goto err; +#endif case SSH_KEYTYPE_DSS_CERT01: case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_ECDSA_P256_CERT01: @@ -865,7 +894,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, SSH_LOG(SSH_LOG_WARN, "Parsing private key: %s", ERR_error_string(ERR_get_error(),NULL)); - return NULL; + goto fail; } type = SSH_KEYTYPE_DSS; break; @@ -875,7 +904,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, SSH_LOG(SSH_LOG_WARN, "Parsing private key: %s", ERR_error_string(ERR_get_error(),NULL)); - return NULL; + goto fail; } type = SSH_KEYTYPE_RSA; break; @@ -886,7 +915,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, SSH_LOG(SSH_LOG_WARN, "Parsing private key: %s", ERR_error_string(ERR_get_error(), NULL)); - return NULL; + goto fail; } /* pki_privatekey_type_from_string always returns P256 for ECDSA @@ -899,6 +928,43 @@ ssh_key pki_private_key_from_base64(const char *b64_key, break; #endif +#ifdef HAVE_OPENSSL_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_WARN, "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; + } + type = SSH_KEYTYPE_ED25519; + } + break; +#endif default: EVP_PKEY_free(pkey); SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", @@ -927,13 +993,16 @@ ssh_key pki_private_key_from_base64(const char *b64_key, return key; fail: + EVP_PKEY_free(pkey); ssh_key_free(key); DSA_free(dsa); RSA_free(rsa); #ifdef HAVE_OPENSSL_ECC EC_KEY_free(ecdsa); #endif - +#ifdef HAVE_OPENSSL_ED25519 + SAFE_FREE(ed25519); +#endif return NULL; } |