aboutsummaryrefslogtreecommitdiff
path: root/src/pki_crypto.c
diff options
context:
space:
mode:
authorAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2019-08-30 18:41:16 +0200
committerAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2019-09-24 16:49:35 +0200
commita3a0529b41e5ce4789cc8a5bd5e09b4ed15efe32 (patch)
tree25a31744b2bdffad775c6329a6dd6c7da0ef6adb /src/pki_crypto.c
parent61e6b6cc59eb18ed2a226974eed2da9e51e9db88 (diff)
downloadlibssh-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.c87
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;
}