add support for smartcards in charon by using the ENGINE API provided by OpenSSL...
authorTobias Brunner <tobias@strongswan.org>
Wed, 3 Dec 2008 10:12:20 +0000 (10:12 -0000)
committerTobias Brunner <tobias@strongswan.org>
Wed, 3 Dec 2008 10:12:20 +0000 (10:12 -0000)
src/charon/plugins/stroke/stroke_cred.c
src/libstrongswan/credentials/builder.c
src/libstrongswan/credentials/builder.h
src/libstrongswan/credentials/credential_factory.c
src/libstrongswan/plugins/openssl/openssl_plugin.c
src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c

index 23a6f99..07e0ca7 100644 (file)
@@ -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<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;
@@ -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;
                }
        }
index 4295b30..0bca198 100644 (file)
@@ -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",
 );
 
index cd75236..332d52d 100644 (file)
@@ -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,
 };
index 8527599..e4e0ce8 100644 (file)
@@ -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 */
index 35df1b0..952697b 100644 (file)
@@ -16,6 +16,7 @@
  * $Id$
  */
 
+#include <openssl/conf.h>
 #include <openssl/evp.h>
 #include <openssl/engine.h>
 #include <openssl/crypto.h>
@@ -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 */
index c152b82..5f3a17b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
+#include <openssl/engine.h>
 
 /**
  *  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;
 }