aboutsummaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/auth.c18
-rw-r--r--src/pki.c15
-rw-r--r--src/pki_crypto.c167
-rw-r--r--src/pki_gcrypt.c9
-rw-r--r--src/pki_mbedcrypto.c10
5 files changed, 218 insertions, 1 deletions
diff --git a/src/auth.c b/src/auth.c
index f2eeee0b..ac6c9b14 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -1055,12 +1055,28 @@ int ssh_userauth_publickey_auto(ssh_session session,
while (state->it != NULL) {
const char *privkey_file = state->it->data;
char pubkey_file[1024] = {0};
+
if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
SSH_LOG(SSH_LOG_DEBUG,
"Trying to authenticate with %s", privkey_file);
state->privkey = NULL;
state->pubkey = NULL;
- snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
+
+ if (ssh_pki_is_uri(privkey_file)) {
+ char *pub_uri_from_priv = NULL;
+ SSH_LOG(SSH_LOG_INFO,
+ "Authenticating with PKCS #11 URI.");
+ pub_uri_from_priv = ssh_pki_export_pub_uri_from_priv_uri(privkey_file);
+ if (pub_uri_from_priv == NULL) {
+ return SSH_ERROR;
+ } else {
+ snprintf(pubkey_file, sizeof(pubkey_file), "%s",
+ pub_uri_from_priv);
+ SAFE_FREE(pub_uri_from_priv);
+ }
+ } else {
+ snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
+ }
rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
if (rc == SSH_ERROR) {
diff --git a/src/pki.c b/src/pki.c
index 24ffd25d..ae470ffc 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -4,6 +4,7 @@
*
* Copyright (c) 2010 by Aris Adamantiadis
* Copyright (c) 2011-2013 Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2019 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
@@ -864,6 +865,13 @@ int ssh_pki_import_privkey_file(const char *filename,
return SSH_ERROR;
}
+#ifdef WITH_PKCS11_URI
+ if (ssh_pki_is_uri(filename)) {
+ rc = pki_uri_import(filename, pkey, SSH_KEY_PRIVATE);
+ return rc;
+ }
+#endif
+
file = fopen(filename, "rb");
if (file == NULL) {
SSH_LOG(SSH_LOG_WARN,
@@ -1639,6 +1647,13 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
return SSH_ERROR;
}
+#ifdef WITH_PKCS11_URI
+ if (ssh_pki_is_uri(filename)) {
+ rc = pki_uri_import(filename, pkey, SSH_KEY_PUBLIC);
+ return rc;
+ }
+#endif
+
file = fopen(filename, "rb");
if (file == NULL) {
SSH_LOG(SSH_LOG_WARN, "Error opening %s: %s",
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 */
diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c
index 4bfcb9f6..23572683 100644
--- a/src/pki_gcrypt.c
+++ b/src/pki_gcrypt.c
@@ -2457,4 +2457,13 @@ int pki_verify_data_signature(ssh_signature signature,
return SSH_OK;
}
+int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type)
+{
+ (void) uri_name;
+ (void) key;
+ (void) key_type;
+ SSH_LOG(SSH_LOG_WARN,
+ "gcrypt does not support PKCS #11");
+ return SSH_ERROR;
+}
#endif /* HAVE_LIBGCRYPT */
diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c
index dd1a513e..08905cd9 100644
--- a/src/pki_mbedcrypto.c
+++ b/src/pki_mbedcrypto.c
@@ -1591,4 +1591,14 @@ int pki_key_generate_dss(ssh_key key, int parameter)
(void) parameter;
return SSH_ERROR;
}
+
+int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type)
+{
+ (void) uri_name;
+ (void) key;
+ (void) key_type;
+ SSH_LOG(SSH_LOG_WARN,
+ "mbedcrypto does not support PKCS #11");
+ return SSH_ERROR;
+}
#endif /* HAVE_LIBMBEDCRYPTO */