/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
{
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;
}
- /* NULL terminate the ids string by replacing the : separator */
- *(ids.ptr + ids.len) = '\0';
if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
{
}
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)) ||
(match("EAP", &token) && (type = SHARED_EAP)) ||
- (match("XAUTH", &token) && (type = SHARED_EAP)) ||
- (match("PIN", &token) && (type = SHARED_PIN)))
+ (match("XAUTH", &token) && (type = SHARED_EAP)))
{
stroke_shared_key_t *shared_key;
chunk_t secret = chunk_empty;
else
{
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;
}
}
#include <openssl/evp.h>
#include <openssl/rsa.h>
+#include <openssl/engine.h>
/**
* Public exponent to use for key generation.
* RSA object from OpenSSL
*/
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
*/
static chunk_t get_encoding(private_openssl_rsa_private_key_t *this)
{
- chunk_t enc = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL));
- u_char *p = enc.ptr;
- i2d_RSAPrivateKey(this->rsa, &p);
+ chunk_t enc = chunk_empty;
+ if (!this->engine)
+ {
+ enc = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL));
+ u_char *p = enc.ptr;
+ i2d_RSAPrivateKey(this->rsa, &p);
+ }
return enc;
}
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->engine = FALSE;
this->keyid = NULL;
this->keyid_info = NULL;
this->ref = 1;
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;
/**
* Builder implementation for key loading/generation
builder_t public;
/** loaded/generated private key */
openssl_rsa_private_key_t *key;
+ /** temporary stored smartcard key ID */
+ char *keyid;
+ /** temporary stored smartcard pin */
+ char *pin;
};
/**
{
openssl_rsa_private_key_t *key = this->key;
+ if (this->keyid && this->pin)
+ {
+ key = load_from_smartcard(this->keyid, this->pin);
+ }
free(this);
return key;
}
va_end(args);
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:
break;
}
this->key = NULL;
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
this->public.build = (void*(*)(builder_t *this))build;
+ this->keyid = NULL;
+ this->pin = NULL;
return &this->public;
}