From 83c42156a237290f7ebf6d5270491a26e05e1eaa Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 3 Dec 2008 10:12:20 +0000 Subject: [PATCH] =?utf8?q?add=20support=20for=20smartcards=20in=20charon?= =?utf8?q?=20by=20using=20the=20ENGINE=20API=20provided=20by=20OpenSSL,=20?= =?utf8?q?based=20on=20patches=20by=20Michael=20Ro=C3=9Fberg.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/charon/plugins/stroke/stroke_cred.c | 90 ++++++++++++++++++-- src/libstrongswan/credentials/builder.c | 2 + src/libstrongswan/credentials/builder.h | 4 + src/libstrongswan/credentials/credential_factory.c | 2 + src/libstrongswan/plugins/openssl/openssl_plugin.c | 3 + .../plugins/openssl/openssl_rsa_private_key.c | 96 +++++++++++++++++++++- 6 files changed, 187 insertions(+), 10 deletions(-) diff --git a/src/charon/plugins/stroke/stroke_cred.c b/src/charon/plugins/stroke/stroke_cred.c index 23a6f99..07e0ca7 100644 --- a/src/charon/plugins/stroke/stroke_cred.c +++ b/src/charon/plugins/stroke/stroke_cred.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -720,13 +721,23 @@ static void load_secrets(private_stroke_cred_t *this) { 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)) { @@ -791,10 +802,75 @@ static void load_secrets(private_stroke_cred_t *this) } 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: */ + if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2) + { + snprintf(smartcard, sizeof(smartcard), "%u:%s", slot, keyid); + } + /* then try %smartcard: */ + 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; @@ -862,7 +938,7 @@ static void load_secrets(private_stroke_cred_t *this) 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; } } diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index 4295b30..0bca198 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -35,6 +35,8 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END, "BUILD_CA_CERT", "BUILD_CERT", "BUILD_X509_FLAG", + "BUILD_SMARTCARD_KEYID", + "BUILD_SMARTCARD_PIN", "BUILD_END", ); diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index cd75236..332d52d 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -76,6 +76,10 @@ enum builder_part_t { BUILD_CERT, /** enforce an additional X509 flag, x509_flag_t */ 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 */ BUILD_END, }; diff --git a/src/libstrongswan/credentials/credential_factory.c b/src/libstrongswan/credentials/credential_factory.c index 8527599..e4e0ce8 100644 --- a/src/libstrongswan/credentials/credential_factory.c +++ b/src/libstrongswan/credentials/credential_factory.c @@ -184,6 +184,8 @@ static void* create(private_credential_factory_t *this, credential_type_t type, case BUILD_CA_CERT: case BUILD_CERT: case BUILD_IETF_GROUP_ATTR: + case BUILD_SMARTCARD_KEYID: + case BUILD_SMARTCARD_PIN: builder->add(builder, part, va_arg(args, void*)); continue; /* no default to get a compiler warning */ diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index 35df1b0..952697b 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -16,6 +16,7 @@ * $Id$ */ +#include #include #include #include @@ -185,6 +186,7 @@ static void destroy(private_openssl_plugin_t *this) ENGINE_cleanup(); EVP_cleanup(); + CONF_modules_free(); threading_cleanup(); @@ -202,6 +204,7 @@ plugin_t *plugin_create() threading_init(); + OPENSSL_config(NULL); OpenSSL_add_all_algorithms(); /* activate support for hardware accelerators */ diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index c152b82..5f3a17b 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -22,6 +22,7 @@ #include #include +#include /** * Public exponent to use for key generation. @@ -43,6 +44,11 @@ struct private_openssl_rsa_private_key_t { * 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 @@ -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) { - 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; } @@ -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.destroy = (void (*)(private_key_t *this))destroy; + this->engine = FALSE; this->keyid = NULL; this->keyid_info = NULL; this->ref = 1; @@ -347,6 +358,61 @@ static openssl_rsa_private_key_t *load(chunk_t blob) 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 @@ -356,6 +422,10 @@ struct private_builder_t { 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; }; /** @@ -365,6 +435,10 @@ static openssl_rsa_private_key_t *build(private_builder_t *this) { 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; } @@ -396,6 +470,20 @@ static void add(private_builder_t *this, builder_part_t part, ...) 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; } @@ -424,6 +512,8 @@ builder_t *openssl_rsa_private_key_builder(key_type_t type) 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; } -- 2.7.4