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>
Этот коммит содержится в:
родитель
6bf4ada240
Коммит
4ea09256f6
@ -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_ */
|
||||
|
16
src/auth.c
16
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;
|
||||
|
||||
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) {
|
||||
|
15
src/pki.c
15
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",
|
||||
|
167
src/pki_crypto.c
167
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 */
|
||||
|
@ -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 */
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user