add support for smartcards in charon by using the ENGINE API provided by OpenSSL, based on patches by Michael Roßberg.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2008 Tobias Brunner
|
||||||
* Copyright (C) 2008 Martin Willi
|
* Copyright (C) 2008 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -720,13 +721,23 @@ static void load_secrets(private_stroke_cred_t *this)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!extract_last_token(&ids, ':', &line))
|
if (line.len > 2 && strneq(": ", line.ptr, 2))
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr);
|
/* no ids, skip the ':' */
|
||||||
|
ids = chunk_empty;
|
||||||
|
line.ptr++;
|
||||||
|
line.len--;
|
||||||
|
}
|
||||||
|
else if (extract_token_str(&ids, " : ", &line))
|
||||||
|
{
|
||||||
|
/* NULL terminate the extracted id string */
|
||||||
|
*(ids.ptr + ids.len) = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "line %d: missing ' : ' separator", line_nr);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/* NULL terminate the ids string by replacing the : separator */
|
|
||||||
*(ids.ptr + ids.len) = '\0';
|
|
||||||
|
|
||||||
if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
|
if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
|
||||||
{
|
{
|
||||||
@@ -791,10 +802,75 @@ static void load_secrets(private_stroke_cred_t *this)
|
|||||||
}
|
}
|
||||||
chunk_clear(&secret);
|
chunk_clear(&secret);
|
||||||
}
|
}
|
||||||
|
else if (match("PIN", &token))
|
||||||
|
{
|
||||||
|
chunk_t sc = chunk_empty;
|
||||||
|
char smartcard[32], keyid[22], pin[32];
|
||||||
|
private_key_t *key;
|
||||||
|
u_int slot;
|
||||||
|
|
||||||
|
err_t ugh = extract_value(&sc, &line);
|
||||||
|
|
||||||
|
if (ugh != NULL)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (sc.len == 0)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
snprintf(smartcard, sizeof(smartcard), "%.*s", sc.len, sc.ptr);
|
||||||
|
smartcard[sizeof(smartcard) - 1] = '\0';
|
||||||
|
|
||||||
|
/* parse slot and key id. only two formats are supported.
|
||||||
|
* first try %smartcard<slot>:<keyid> */
|
||||||
|
if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2)
|
||||||
|
{
|
||||||
|
snprintf(smartcard, sizeof(smartcard), "%u:%s", slot, keyid);
|
||||||
|
}
|
||||||
|
/* then try %smartcard:<keyid> */
|
||||||
|
else if (sscanf(smartcard, "%%smartcard:%s", keyid) == 1)
|
||||||
|
{
|
||||||
|
snprintf(smartcard, sizeof(smartcard), "%s", keyid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
|
||||||
|
" supported or invalid", line_nr);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eat_whitespace(&line))
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "line %d: expected PIN", line_nr);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ugh = extract_secret(&chunk, &line);
|
||||||
|
if (ugh != NULL)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
snprintf(pin, sizeof(pin), "%.*s", chunk.len, chunk.ptr);
|
||||||
|
pin[sizeof(pin) - 1] = '\0';
|
||||||
|
|
||||||
|
/* we assume an RSA key */
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
|
BUILD_SMARTCARD_KEYID, smartcard,
|
||||||
|
BUILD_SMARTCARD_PIN, pin, BUILD_END);
|
||||||
|
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, " loaded private key from %.*s", sc.len, sc.ptr);
|
||||||
|
this->private->insert_last(this->private, key);
|
||||||
|
}
|
||||||
|
memset(pin, 0, sizeof(pin));
|
||||||
|
}
|
||||||
else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
|
else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
|
||||||
(match("EAP", &token) && (type = SHARED_EAP)) ||
|
(match("EAP", &token) && (type = SHARED_EAP)) ||
|
||||||
(match("XAUTH", &token) && (type = SHARED_EAP)) ||
|
(match("XAUTH", &token) && (type = SHARED_EAP)))
|
||||||
(match("PIN", &token) && (type = SHARED_PIN)))
|
|
||||||
{
|
{
|
||||||
stroke_shared_key_t *shared_key;
|
stroke_shared_key_t *shared_key;
|
||||||
chunk_t secret = chunk_empty;
|
chunk_t secret = chunk_empty;
|
||||||
@@ -862,7 +938,7 @@ static void load_secrets(private_stroke_cred_t *this)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "line %d: token must be either "
|
DBG1(DBG_CFG, "line %d: token must be either "
|
||||||
"RSA, EC, PSK, EAP, or PIN", line_nr);
|
"RSA, ECDSA, PSK, EAP, XAUTH or PIN", line_nr);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
|
|||||||
"BUILD_CA_CERT",
|
"BUILD_CA_CERT",
|
||||||
"BUILD_CERT",
|
"BUILD_CERT",
|
||||||
"BUILD_X509_FLAG",
|
"BUILD_X509_FLAG",
|
||||||
|
"BUILD_SMARTCARD_KEYID",
|
||||||
|
"BUILD_SMARTCARD_PIN",
|
||||||
"BUILD_END",
|
"BUILD_END",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ enum builder_part_t {
|
|||||||
BUILD_CERT,
|
BUILD_CERT,
|
||||||
/** enforce an additional X509 flag, x509_flag_t */
|
/** enforce an additional X509 flag, x509_flag_t */
|
||||||
BUILD_X509_FLAG,
|
BUILD_X509_FLAG,
|
||||||
|
/** key ID of a key on a smartcard, null terminated char* ([slot:]keyid) */
|
||||||
|
BUILD_SMARTCARD_KEYID,
|
||||||
|
/** pin to access a key on a smartcard, null terminated char* */
|
||||||
|
BUILD_SMARTCARD_PIN,
|
||||||
/** end of variable argument builder list */
|
/** end of variable argument builder list */
|
||||||
BUILD_END,
|
BUILD_END,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
|
|||||||
case BUILD_CA_CERT:
|
case BUILD_CA_CERT:
|
||||||
case BUILD_CERT:
|
case BUILD_CERT:
|
||||||
case BUILD_IETF_GROUP_ATTR:
|
case BUILD_IETF_GROUP_ATTR:
|
||||||
|
case BUILD_SMARTCARD_KEYID:
|
||||||
|
case BUILD_SMARTCARD_PIN:
|
||||||
builder->add(builder, part, va_arg(args, void*));
|
builder->add(builder, part, va_arg(args, void*));
|
||||||
continue;
|
continue;
|
||||||
/* no default to get a compiler warning */
|
/* no default to get a compiler warning */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <openssl/conf.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/engine.h>
|
#include <openssl/engine.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
@@ -185,6 +186,7 @@ static void destroy(private_openssl_plugin_t *this)
|
|||||||
|
|
||||||
ENGINE_cleanup();
|
ENGINE_cleanup();
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
|
CONF_modules_free();
|
||||||
|
|
||||||
threading_cleanup();
|
threading_cleanup();
|
||||||
|
|
||||||
@@ -202,6 +204,7 @@ plugin_t *plugin_create()
|
|||||||
|
|
||||||
threading_init();
|
threading_init();
|
||||||
|
|
||||||
|
OPENSSL_config(NULL);
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
/* activate support for hardware accelerators */
|
/* activate support for hardware accelerators */
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/engine.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public exponent to use for key generation.
|
* Public exponent to use for key generation.
|
||||||
@@ -43,6 +44,11 @@ struct private_openssl_rsa_private_key_t {
|
|||||||
* RSA object from OpenSSL
|
* RSA object from OpenSSL
|
||||||
*/
|
*/
|
||||||
RSA *rsa;
|
RSA *rsa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRUE if the key is from an OpenSSL ENGINE and might not be readable
|
||||||
|
*/
|
||||||
|
bool engine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keyid formed as a SHA-1 hash of a privateKey object
|
* Keyid formed as a SHA-1 hash of a privateKey object
|
||||||
@@ -238,9 +244,13 @@ static bool belongs_to(private_openssl_rsa_private_key_t *this, public_key_t *pu
|
|||||||
*/
|
*/
|
||||||
static chunk_t get_encoding(private_openssl_rsa_private_key_t *this)
|
static chunk_t get_encoding(private_openssl_rsa_private_key_t *this)
|
||||||
{
|
{
|
||||||
chunk_t enc = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL));
|
chunk_t enc = chunk_empty;
|
||||||
u_char *p = enc.ptr;
|
if (!this->engine)
|
||||||
i2d_RSAPrivateKey(this->rsa, &p);
|
{
|
||||||
|
enc = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL));
|
||||||
|
u_char *p = enc.ptr;
|
||||||
|
i2d_RSAPrivateKey(this->rsa, &p);
|
||||||
|
}
|
||||||
return enc;
|
return enc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +299,7 @@ static private_openssl_rsa_private_key_t *openssl_rsa_private_key_create_empty(v
|
|||||||
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
|
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
|
||||||
this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
|
this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
|
||||||
|
|
||||||
|
this->engine = FALSE;
|
||||||
this->keyid = NULL;
|
this->keyid = NULL;
|
||||||
this->keyid_info = NULL;
|
this->keyid_info = NULL;
|
||||||
this->ref = 1;
|
this->ref = 1;
|
||||||
@@ -347,6 +358,61 @@ static openssl_rsa_private_key_t *load(chunk_t blob)
|
|||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load private key from a smart card
|
||||||
|
*/
|
||||||
|
static openssl_rsa_private_key_t *load_from_smartcard(char *keyid, char *pin)
|
||||||
|
{
|
||||||
|
private_openssl_rsa_private_key_t *this = NULL;
|
||||||
|
EVP_PKEY *key;
|
||||||
|
char *engine_id = lib->settings->get_str(lib->settings,
|
||||||
|
"library.plugins.openssl.engine_id", "pkcs11");
|
||||||
|
|
||||||
|
ENGINE *engine = ENGINE_by_id(engine_id);
|
||||||
|
if (!engine)
|
||||||
|
{
|
||||||
|
DBG1("engine '%s' is not available", engine_id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ENGINE_init(engine))
|
||||||
|
{
|
||||||
|
DBG1("failed to initialize engine '%s'", engine_id);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
|
||||||
|
{
|
||||||
|
DBG1("failed to set PIN on engine '%s'", engine_id);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = ENGINE_load_private_key(engine, keyid, NULL, NULL);
|
||||||
|
|
||||||
|
if (!key)
|
||||||
|
{
|
||||||
|
DBG1("failed to load private key with ID '%s' from engine '%s'", keyid,
|
||||||
|
engine_id);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ENGINE_free(engine);
|
||||||
|
|
||||||
|
this = openssl_rsa_private_key_create_empty();
|
||||||
|
this->rsa = EVP_PKEY_get1_RSA(key);
|
||||||
|
this->engine = TRUE;
|
||||||
|
|
||||||
|
if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info))
|
||||||
|
{
|
||||||
|
destroy(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return &this->public;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ENGINE_free(engine);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct private_builder_t private_builder_t;
|
typedef struct private_builder_t private_builder_t;
|
||||||
/**
|
/**
|
||||||
* Builder implementation for key loading/generation
|
* Builder implementation for key loading/generation
|
||||||
@@ -356,6 +422,10 @@ struct private_builder_t {
|
|||||||
builder_t public;
|
builder_t public;
|
||||||
/** loaded/generated private key */
|
/** loaded/generated private key */
|
||||||
openssl_rsa_private_key_t *key;
|
openssl_rsa_private_key_t *key;
|
||||||
|
/** temporary stored smartcard key ID */
|
||||||
|
char *keyid;
|
||||||
|
/** temporary stored smartcard pin */
|
||||||
|
char *pin;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,6 +435,10 @@ static openssl_rsa_private_key_t *build(private_builder_t *this)
|
|||||||
{
|
{
|
||||||
openssl_rsa_private_key_t *key = this->key;
|
openssl_rsa_private_key_t *key = this->key;
|
||||||
|
|
||||||
|
if (this->keyid && this->pin)
|
||||||
|
{
|
||||||
|
key = load_from_smartcard(this->keyid, this->pin);
|
||||||
|
}
|
||||||
free(this);
|
free(this);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@@ -396,6 +470,20 @@ static void add(private_builder_t *this, builder_part_t part, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case BUILD_SMARTCARD_KEYID:
|
||||||
|
{
|
||||||
|
va_start(args, part);
|
||||||
|
this->keyid = va_arg(args, char*);
|
||||||
|
va_end(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case BUILD_SMARTCARD_PIN:
|
||||||
|
{
|
||||||
|
va_start(args, part);
|
||||||
|
this->pin = va_arg(args, char*);
|
||||||
|
va_end(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -424,6 +512,8 @@ builder_t *openssl_rsa_private_key_builder(key_type_t type)
|
|||||||
this->key = NULL;
|
this->key = NULL;
|
||||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||||
this->public.build = (void*(*)(builder_t *this))build;
|
this->public.build = (void*(*)(builder_t *this))build;
|
||||||
|
this->keyid = NULL;
|
||||||
|
this->pin = NULL;
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user