diff options
author | Sahana Prasad <sahana@redhat.com> | 2019-12-18 22:53:04 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2019-12-20 16:17:33 +0100 |
commit | 4ea09256f67c381bed44af54d8cbfa42d81df314 (patch) | |
tree | e458deb1590de6e003739c59c2c91d0c2c5eefd4 /src | |
parent | 6bf4ada240f3ea28db00f5b48ae3c9ab6fc5c3d8 (diff) | |
download | libssh-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.c | 18 | ||||
-rw-r--r-- | src/pki.c | 15 | ||||
-rw-r--r-- | src/pki_crypto.c | 167 | ||||
-rw-r--r-- | src/pki_gcrypt.c | 9 | ||||
-rw-r--r-- | src/pki_mbedcrypto.c | 10 |
5 files changed, 218 insertions, 1 deletions
@@ -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) { @@ -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 */ |