aboutsummaryrefslogtreecommitdiff
path: root/src/pki_crypto.c
diff options
context:
space:
mode:
authorSahana Prasad <sahana@redhat.com>2019-12-18 22:53:04 +0100
committerAndreas Schneider <asn@cryptomilk.org>2019-12-20 16:17:33 +0100
commit4ea09256f67c381bed44af54d8cbfa42d81df314 (patch)
treee458deb1590de6e003739c59c2c91d0c2c5eefd4 /src/pki_crypto.c
parent6bf4ada240f3ea28db00f5b48ae3c9ab6fc5c3d8 (diff)
downloadlibssh-4ea09256f67c381bed44af54d8cbfa42d81df314.tar.gz
libssh-4ea09256f67c381bed44af54d8cbfa42d81df314.tar.xz
libssh-4ea09256f67c381bed44af54d8cbfa42d81df314.zip
src: Implements PKCS11 URI support
Imports private and public keys from the engine via PKCS11 URIs. Uses the imported keys to authenticate to the ssh server. Signed-off-by: Sahana Prasad <sahana@redhat.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Diffstat (limited to 'src/pki_crypto.c')
-rw-r--r--src/pki_crypto.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index e2a3d3bf..000afd35 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -5,6 +5,7 @@
*
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2019 by Sahana Prasad <sahana@redhat.com>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -32,6 +33,8 @@
#include <openssl/pem.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
#include <openssl/rsa.h>
#include "libcrypto-compat.h"
@@ -297,6 +300,10 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
return NULL;
}
+#ifdef WITH_PKCS11_URI
+ new->key = key->key;
+#endif
+
new->type = key->type;
new->type_c = key->type_c;
if (demote) {
@@ -1993,6 +2000,13 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
{
EVP_PKEY *pkey = NULL;
+#ifdef WITH_PKCS11_URI
+ if (key->flags & SSH_KEY_FLAG_PKCS11_URI) {
+ pkey = key->key;
+ return pkey;
+ }
+#endif
+
switch(key->type) {
case SSH_KEYTYPE_DSS:
case SSH_KEYTYPE_DSS_CERT01:
@@ -2489,4 +2503,157 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
}
#endif /* HAVE_OPENSSL_ED25519 */
+/**
+ * @internal
+ *
+ * @brief Populate the public/private ssh_key from the engine with
+ * PKCS#11 URIs as the look up.
+ *
+ * @param[in] uri_name The PKCS#11 URI
+ * @param[in] nkey The ssh-key context for
+ * the key loaded from the engine.
+ * @param[in] key_type The type of the key used. Public/Private.
+ *
+ * @return SSH_OK if ssh-key is valid; SSH_ERROR otherwise.
+ */
+int pki_uri_import(const char *uri_name,
+ ssh_key *nkey,
+ enum ssh_key_e key_type)
+{
+ ENGINE *engine = NULL;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa = NULL;
+ ssh_key key = NULL;
+ enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
+#ifdef HAVE_OPENSSL_ECC
+ EC_KEY *ecdsa = NULL;
+#else
+ void *ecdsa = NULL;
+#endif
+ int ok;
+
+ ENGINE_load_builtin_engines();
+
+ engine = ENGINE_by_id("pkcs11");
+ if (engine == NULL) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Could not load the engine: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ return SSH_ERROR;
+ }
+ SSH_LOG(SSH_LOG_INFO, "Engine loaded successfully");
+
+ ok = ENGINE_init(engine);
+ if (!ok) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Could not initialize the engine: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ ENGINE_free(engine);
+ return SSH_ERROR;
+ }
+
+ SSH_LOG(SSH_LOG_INFO, "Engine init success");
+
+ switch (key_type) {
+ case SSH_KEY_CMP_PRIVATE:
+ pkey = ENGINE_load_private_key(engine, uri_name, NULL, NULL);
+ if (pkey == NULL) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Could not load key: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ goto fail;
+ }
+ break;
+ case SSH_KEY_CMP_PUBLIC:
+ pkey = ENGINE_load_public_key(engine, uri_name, NULL, NULL);
+ if (pkey == NULL) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Could not load key: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ goto fail;
+ }
+ break;
+ default:
+ SSH_LOG(SSH_LOG_WARN,
+ "Invalid key type: %d", key_type);
+ goto fail;
+ }
+
+ key = ssh_key_new();
+ if (key == NULL) {
+ goto fail;
+ }
+
+ switch (EVP_PKEY_base_id(pkey)) {
+ case EVP_PKEY_RSA:
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa == NULL) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Parsing pub key: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ goto fail;
+ }
+ type = SSH_KEYTYPE_RSA;
+ break;
+ case EVP_PKEY_EC:
+#ifdef HAVE_OPENSSL_ECC
+ ecdsa = EVP_PKEY_get1_EC_KEY(pkey);
+ if (ecdsa == NULL) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Parsing pub key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ /* pki_privatekey_type_from_string always returns P256 for ECDSA
+ * keys, so we need to figure out the correct type here */
+ type = pki_key_ecdsa_to_key_type(ecdsa);
+ if (type == SSH_KEYTYPE_UNKNOWN) {
+ SSH_LOG(SSH_LOG_WARN, "Invalid pub key.");
+ goto fail;
+ }
+
+ break;
+#endif
+ default:
+ SSH_LOG(SSH_LOG_WARN, "Unknown or invalid public key type %d",
+ EVP_PKEY_base_id(pkey));
+ goto fail;
+ }
+
+ key->key = pkey;
+ key->type = type;
+ key->type_c = ssh_key_type_to_char(type);
+ if (key_type == SSH_KEY_PRIVATE) {
+ key->flags = SSH_KEY_FLAG_PUBLIC | SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PKCS11_URI;
+ } else {
+ key->flags = SSH_KEY_FLAG_PUBLIC | SSH_KEY_FLAG_PKCS11_URI;
+ }
+ key->rsa = rsa;
+ key->ecdsa = ecdsa;
+#ifdef HAVE_OPENSSL_ECC
+ if (is_ecdsa_key_type(key->type)) {
+ key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
+ }
+#endif
+
+ *nkey = key;
+ ENGINE_finish(engine);
+ ENGINE_free(engine);
+
+ return SSH_OK;
+
+fail:
+ ENGINE_finish(engine);
+ ENGINE_free(engine);
+ EVP_PKEY_free(pkey);
+ ssh_key_free(key);
+ RSA_free(rsa);
+#ifdef HAVE_OPENSSL_ECC
+ EC_KEY_free(ecdsa);
+#endif
+
+ return SSH_ERROR;
+}
+
#endif /* _PKI_CRYPTO_H */