1
1

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>
Этот коммит содержится в:
Sahana Prasad 2019-12-18 22:53:04 +01:00 коммит произвёл Andreas Schneider
родитель 6bf4ada240
Коммит 4ea09256f6
7 изменённых файлов: 232 добавлений и 2 удалений

Просмотреть файл

@ -28,7 +28,9 @@
#ifdef HAVE_OPENSSL_ECDSA_H
#include <openssl/ecdsa.h>
#endif
#ifdef HAVE_LIBCRYPTO
#include <openssl/evp.h>
#endif
#include "libssh/crypto.h"
#ifdef HAVE_OPENSSL_ED25519
/* If using OpenSSL implementation, define the signature lenght which would be
@ -46,6 +48,7 @@
#define SSH_KEY_FLAG_EMPTY 0x0
#define SSH_KEY_FLAG_PUBLIC 0x0001
#define SSH_KEY_FLAG_PRIVATE 0x0002
#define SSH_KEY_FLAG_PKCS11_URI 0x0004
struct ssh_key_struct {
enum ssh_keytypes_e type;
@ -63,6 +66,7 @@ struct ssh_key_struct {
#elif defined(HAVE_LIBCRYPTO)
DSA *dsa;
RSA *rsa;
EVP_PKEY *key; /* Saving the OpenSSL context here to save time while converting*/
# if defined(HAVE_OPENSSL_ECC)
EC_KEY *ecdsa;
# else

Просмотреть файл

@ -43,6 +43,12 @@ int bcrypt_pbkdf(const char *pass,
/* Magic defined in OpenSSH/PROTOCOL.key */
#define OPENSSH_AUTH_MAGIC "openssh-key-v1"
/* Determine type of ssh key. */
enum ssh_key_e {
SSH_KEY_PUBLIC = 0,
SSH_KEY_PRIVATE
};
int pki_key_ecdsa_nid_from_name(const char *name);
const char *pki_key_ecdsa_nid_to_name(int nid);
const char *ssh_key_signature_to_char(enum ssh_keytypes_e type,
@ -156,4 +162,7 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
const char *passphrase, ssh_auth_callback auth_fn, void *auth_data);
/* URI Function */
int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type);
#endif /* PKI_PRIV_H_ */

Просмотреть файл

@ -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",

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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 */