botan: Load public/private keys generically
authorTobias Brunner <tobias@strongswan.org>
Thu, 9 Aug 2018 11:00:50 +0000 (13:00 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 12 Sep 2018 14:25:00 +0000 (16:25 +0200)
Simplifies public key loading and this way unencrypted PKCS#8-encoded
keys can be loaded directly without pkcs8 plugin (code for encrypted
keys could probably later be added, if necessary).

It also simplifies the implementation of private_key_t::get_public_key()
a lot.

12 files changed:
src/libstrongswan/plugins/botan/Makefile.am
src/libstrongswan/plugins/botan/botan_ec_private_key.c
src/libstrongswan/plugins/botan/botan_ec_private_key.h
src/libstrongswan/plugins/botan/botan_ec_public_key.c
src/libstrongswan/plugins/botan/botan_ec_public_key.h
src/libstrongswan/plugins/botan/botan_plugin.c
src/libstrongswan/plugins/botan/botan_rsa_private_key.c
src/libstrongswan/plugins/botan/botan_rsa_private_key.h
src/libstrongswan/plugins/botan/botan_rsa_public_key.c
src/libstrongswan/plugins/botan/botan_rsa_public_key.h
src/libstrongswan/plugins/botan/botan_util_keys.c [new file with mode: 0644]
src/libstrongswan/plugins/botan/botan_util_keys.h [new file with mode: 0644]

index bbad715..1188841 100644 (file)
@@ -24,6 +24,7 @@ libstrongswan_botan_la_SOURCES = \
        botan_ec_public_key.h botan_ec_public_key.c \
        botan_ec_private_key.h botan_ec_private_key.c \
        botan_util.h botan_util.c \
+       botan_util_keys.h botan_util_keys.c \
        botan_gcm.h botan_gcm.c
 
 libstrongswan_botan_la_LDFLAGS = -module -avoid-version
index bfe8f38..78ba43f 100644 (file)
@@ -27,6 +27,7 @@
 
 
 #include "botan_ec_private_key.h"
+#include "botan_ec_public_key.h"
 #include "botan_util.h"
 
 #include <botan/build.h>
@@ -177,39 +178,13 @@ METHOD(private_key_t, get_type, key_type_t,
 METHOD(private_key_t, get_public_key, public_key_t*,
        private_botan_ec_private_key_t *this)
 {
-       public_key_t *public;
        botan_pubkey_t pubkey;
-       chunk_t key = chunk_empty;
 
        if (botan_privkey_export_pubkey(&pubkey, this->key))
        {
-               return FALSE;
-       }
-
-       if (botan_pubkey_export(pubkey, NULL, &key.len,
-                                                       BOTAN_PRIVKEY_EXPORT_FLAG_DER)
-               != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
-       {
-               botan_pubkey_destroy(pubkey);
-               return FALSE;
-       }
-
-       key = chunk_alloc(key.len);
-
-       if (botan_pubkey_export(pubkey, key.ptr, &key.len,
-                                                       BOTAN_PRIVKEY_EXPORT_FLAG_DER))
-       {
-               chunk_free(&key);
-               botan_pubkey_destroy(pubkey);
-               return FALSE;
+               return NULL;
        }
-
-       public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
-                                                               BUILD_BLOB_ASN1_DER, key, BUILD_END);
-
-       chunk_free(&key);
-       botan_pubkey_destroy(pubkey);
-       return public;
+       return (public_key_t*)botan_ec_public_key_adopt(pubkey);
 }
 
 METHOD(private_key_t, get_fingerprint, bool,
@@ -405,6 +380,19 @@ static private_botan_ec_private_key_t *create_empty(int oid)
 /*
  * Described in header
  */
+botan_ec_private_key_t *botan_ec_private_key_adopt(botan_privkey_t key, int oid)
+{
+       private_botan_ec_private_key_t *this;
+
+       this = create_empty(oid);
+       this->key = key;
+
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
 botan_ec_private_key_t *botan_ec_private_key_gen(key_type_t type, va_list args)
 {
        private_botan_ec_private_key_t *this;
index 9450331..2b9686c 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2018 René Korthaus
  * Copyright (C) 2018 Konstantinos Kolelis
  * Rohde & Schwarz Cybersecurity GmbH
@@ -30,6 +33,8 @@
 #ifndef BOTAN_EC_PRIVATE_KEY_H_
 #define BOTAN_EC_PRIVATE_KEY_H_
 
+#include <botan/ffi.h>
+
 #include <credentials/builder.h>
 #include <credentials/keys/private_key.h>
 
@@ -69,4 +74,14 @@ botan_ec_private_key_t *botan_ec_private_key_gen(key_type_t type, va_list args);
 botan_ec_private_key_t *botan_ec_private_key_load(key_type_t type,
                                                                                                  va_list args);
 
+/**
+ * Load a ECDSA private key by adopting a botan_privkey_t object.
+ *
+ * @param key          private key object (adopted)
+ * @param oid          EC curve OID
+ * @return                     loaded key, NULL on failure
+ */
+botan_ec_private_key_t *botan_ec_private_key_adopt(botan_privkey_t key,
+                                                                                                  int oid);
+
 #endif /** BOTAN_EC_PRIVATE_KEY_H_ @}*/
index 54782bc..4c85dbc 100644 (file)
@@ -248,33 +248,9 @@ METHOD(public_key_t, destroy, void,
 /*
  * Described in header
  */
-botan_ec_public_key_t *botan_ec_public_key_load(key_type_t type, va_list args)
+botan_ec_public_key_t *botan_ec_public_key_adopt(botan_pubkey_t key)
 {
        private_botan_ec_public_key_t *this;
-       chunk_t blob = chunk_empty;
-       botan_rng_t rng;
-       size_t namesize = 0;
-       char *namebuf;
-
-       if (type != KEY_ECDSA)
-       {
-               return NULL;
-       }
-
-       while (TRUE)
-       {
-               switch (va_arg(args, builder_part_t))
-               {
-                       case BUILD_BLOB_ASN1_DER:
-                               blob = va_arg(args, chunk_t);
-                               continue;
-                       case BUILD_END:
-                               break;
-                       default:
-                               return NULL;
-               }
-               break;
-       }
 
        INIT(this,
                .public = {
@@ -291,52 +267,10 @@ botan_ec_public_key_t *botan_ec_public_key_load(key_type_t type, va_list args)
                                .destroy = _destroy,
                        },
                },
+               .key = key,
                .ref = 1,
        );
 
-       if (botan_pubkey_load(&this->key, blob.ptr, blob.len))
-       {
-               free(this);
-               return NULL;
-       }
-
-       if (botan_pubkey_algo_name(this->key, NULL, &namesize)
-               != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
-       {
-               destroy(this);
-               return NULL;
-       }
-
-       namebuf = malloc(namesize);
-       if (botan_pubkey_algo_name(this->key, namebuf, &namesize))
-       {
-               free(namebuf);
-               destroy(this);
-               return NULL;
-       }
-
-       if (!strneq(namebuf, "ECDSA", namesize))
-       {
-               free(namebuf);
-               destroy(this);
-               return NULL;
-       }
-       free(namebuf);
-
-       if (botan_rng_init(&rng, "user"))
-       {
-               return NULL;
-       }
-
-       if (botan_pubkey_check_key(this->key, rng, BOTAN_CHECK_KEY_EXPENSIVE_TESTS))
-       {
-               DBG1(DBG_LIB, "public key failed key checks");
-               botan_rng_destroy(rng);
-               destroy(this);
-               return NULL;
-       }
-
-       botan_rng_destroy(rng);
        return &this->public;
 }
 
index eb49ec3..ddb3d5b 100644 (file)
 #ifndef BOTAN_EC_PUBLIC_KEY_H_
 #define BOTAN_EC_PUBLIC_KEY_H_
 
-typedef struct botan_ec_public_key_t botan_ec_public_key_t;
+#include <botan/ffi.h>
 
 #include <credentials/builder.h>
 #include <credentials/keys/public_key.h>
 
+typedef struct botan_ec_public_key_t botan_ec_public_key_t;
+
 /**
  * public_key_t implementation of ECDSA using botan.
  */
@@ -42,14 +44,11 @@ struct botan_ec_public_key_t {
 };
 
 /**
- * Load a ECDSA public key using botan.
- *
- * Accepts a BUILD_BLOB_ASN1_DER argument.
+ * Load a ECDSA public key by adopting a botan_pubkey_t object.
  *
- * @param type         type of the key, must be KEY_ECDSA
- * @param args         builder_part_t argument list
- * @return                     loaded key, NULL on failure
+ * @param key          public key object (adopted)
+ * @return                     loaded key, NULL on failure
  */
-botan_ec_public_key_t *botan_ec_public_key_load(key_type_t type, va_list args);
+botan_ec_public_key_t *botan_ec_public_key_adopt(botan_pubkey_t key);
 
 #endif /** BOTAN_EC_PUBLIC_KEY_H_ @}*/
index 468d505..b387a2b 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2018 René Korthaus
  * Copyright (C) 2018 Konstantinos Kolelis
  * Rohde & Schwarz Cybersecurity GmbH
@@ -34,6 +37,7 @@
 #include "botan_ec_public_key.h"
 #include "botan_ec_private_key.h"
 #include "botan_gcm.h"
+#include "botan_util_keys.h"
 
 #include <library.h>
 
@@ -80,6 +84,16 @@ METHOD(plugin_t, get_features, int,
                        PLUGIN_PROVIDE(DH, MODP_768_BIT),
                        PLUGIN_PROVIDE(DH, MODP_CUSTOM),
 #endif
+#ifdef BOTAN_HAS_ECDH
+               /* EC DH groups */
+               PLUGIN_REGISTER(DH, botan_ec_diffie_hellman_create),
+                       PLUGIN_PROVIDE(DH, ECP_256_BIT),
+                       PLUGIN_PROVIDE(DH, ECP_384_BIT),
+                       PLUGIN_PROVIDE(DH, ECP_521_BIT),
+                       PLUGIN_PROVIDE(DH, ECP_256_BP),
+                       PLUGIN_PROVIDE(DH, ECP_384_BP),
+                       PLUGIN_PROVIDE(DH, ECP_512_BP),
+#endif
                /* crypters */
                PLUGIN_REGISTER(CRYPTER, botan_crypter_create),
 #ifdef BOTAN_HAS_AES
@@ -147,15 +161,24 @@ METHOD(plugin_t, get_features, int,
 #endif
 #endif /* BOTAN_HAS_HMAC */
 
-#ifdef BOTAN_HAS_ECDH
-               /* EC DH groups */
-               PLUGIN_REGISTER(DH, botan_ec_diffie_hellman_create),
-                       PLUGIN_PROVIDE(DH, ECP_256_BIT),
-                       PLUGIN_PROVIDE(DH, ECP_384_BIT),
-                       PLUGIN_PROVIDE(DH, ECP_521_BIT),
-                       PLUGIN_PROVIDE(DH, ECP_256_BP),
-                       PLUGIN_PROVIDE(DH, ECP_384_BP),
-                       PLUGIN_PROVIDE(DH, ECP_512_BP),
+               /* generic key loaders */
+#if defined (BOTAN_HAS_RSA) || defined(BOTAN_HAS_ECDSA)
+               PLUGIN_REGISTER(PUBKEY, botan_public_key_load, TRUE),
+                       PLUGIN_PROVIDE(PUBKEY, KEY_ANY),
+#ifdef BOTAN_HAS_RSA
+                       PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
+#endif
+#ifdef BOTAN_HAS_ECDSA
+                       PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
+#endif
+               PLUGIN_REGISTER(PRIVKEY, botan_private_key_load, TRUE),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
+#ifdef BOTAN_HAS_RSA
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
+#endif
+#ifdef BOTAN_HAS_ECDSA
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
+#endif
 #endif
                /* RSA */
 #ifdef BOTAN_HAS_RSA
@@ -164,6 +187,7 @@ METHOD(plugin_t, get_features, int,
                        PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
                PLUGIN_REGISTER(PRIVKEY, botan_rsa_private_key_load, TRUE),
                        PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
                PLUGIN_REGISTER(PRIVKEY_GEN, botan_rsa_private_key_gen, FALSE),
                        PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
                /* encryption/signature schemes */
@@ -214,8 +238,6 @@ METHOD(plugin_t, get_features, int,
                        PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
                PLUGIN_REGISTER(PRIVKEY_GEN, botan_ec_private_key_gen, FALSE),
                        PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ECDSA),
-               PLUGIN_REGISTER(PUBKEY, botan_ec_public_key_load, TRUE),
-                       PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
 #ifdef BOTAN_HAS_EMSA_RAW
                PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_NULL),
                PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_NULL),
index 29f6923..8b2583b 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2018 René Korthaus
  * Rohde & Schwarz Cybersecurity GmbH
  *
@@ -22,6 +25,7 @@
  */
 
 #include "botan_rsa_private_key.h"
+#include "botan_rsa_public_key.h"
 
 #include <botan/build.h>
 
@@ -57,39 +61,6 @@ struct private_botan_rsa_private_key_t {
 };
 
 /**
- * Get the binary representation of a named RSA parameter
- */
-static bool get_rsa_field(botan_privkey_t *key, const char *field_name,
-                                                 chunk_t *value)
-{
-       botan_mp_t field;
-       size_t field_size = 0;
-
-       if (botan_mp_init(&field))
-       {
-               return FALSE;
-       }
-
-       if (botan_privkey_get_field(field, *key, field_name) ||
-               botan_mp_num_bytes(field, &field_size) ||
-               !field_size)
-       {
-               botan_mp_destroy(field);
-               return FALSE;
-       }
-
-       *value = chunk_alloc(field_size);
-       if (botan_mp_to_bin(field, value->ptr))
-       {
-               botan_mp_destroy(field);
-               chunk_clear(value);
-               return FALSE;
-       }
-       botan_mp_destroy(field);
-       return TRUE;
-}
-
-/**
  * Build an EMSA PSS signature described in PKCS#1
  */
 static bool build_emsa_pss_signature(private_botan_rsa_private_key_t *this,
@@ -251,27 +222,13 @@ METHOD(private_key_t, get_keysize, int,
 METHOD(private_key_t, get_public_key, public_key_t*,
        private_botan_rsa_private_key_t *this)
 {
-       public_key_t *pub_key;
-       chunk_t n, e;
-
-       if (!get_rsa_field(&this->key, "n", &n))
-       {
-               return NULL;
-       }
+       botan_pubkey_t pubkey;
 
-       if (!get_rsa_field(&this->key, "e", &e))
+       if (botan_privkey_export_pubkey(&pubkey, this->key))
        {
-               chunk_free(&n);
                return NULL;
        }
-
-       pub_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
-                                                                BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e,
-                                                                BUILD_END);
-
-       chunk_free(&n);
-       chunk_free(&e);
-       return pub_key;
+       return (public_key_t*)botan_rsa_public_key_adopt(pubkey);
 }
 
 METHOD(private_key_t, get_fingerprint, bool,
@@ -385,6 +342,19 @@ static private_botan_rsa_private_key_t *create_empty()
 /*
  * Described in header
  */
+botan_rsa_private_key_t *botan_rsa_private_key_adopt(botan_privkey_t key)
+{
+       private_botan_rsa_private_key_t *this;
+
+       this = create_empty();
+       this->key = key;
+
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
 botan_rsa_private_key_t *botan_rsa_private_key_gen(key_type_t type,
                                                                                                   va_list args)
 {
@@ -650,6 +620,11 @@ botan_rsa_private_key_t *botan_rsa_private_key_load(key_type_t type,
                break;
        }
 
+       if (type == KEY_ANY && !blob.ptr)
+       {
+               return NULL;
+       }
+
        if (blob.ptr)
        {
                this = create_empty();
index 546b88d..f0f419c 100644 (file)
@@ -29,6 +29,8 @@
 #ifndef BOTAN_RSA_PRIVATE_KEY_H_
 #define BOTAN_RSA_PRIVATE_KEY_H_
 
+#include <botan/ffi.h>
+
 #include <credentials/builder.h>
 #include <credentials/keys/private_key.h>
 
@@ -69,4 +71,12 @@ botan_rsa_private_key_t *botan_rsa_private_key_gen(key_type_t type,
 botan_rsa_private_key_t *botan_rsa_private_key_load(key_type_t type,
                                                                                                        va_list args);
 
+/**
+ * Load a RSA private key by adopting a botan_privkey_t object.
+ *
+ * @param key          private key object (adopted)
+ * @return                     loaded key, NULL on failure
+ */
+botan_rsa_private_key_t *botan_rsa_private_key_adopt(botan_privkey_t key);
+
 #endif /** BOTAN_RSA_PRIVATE_KEY_H_ @}*/
index 617fad5..6adb1c4 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2018 René Korthaus
  * Rohde & Schwarz Cybersecurity GmbH
  *
@@ -319,20 +322,30 @@ static private_botan_rsa_public_key_t *create_empty()
 /*
  * Described in header
  */
+botan_rsa_public_key_t *botan_rsa_public_key_adopt(botan_pubkey_t key)
+{
+       private_botan_rsa_public_key_t *this;
+
+       this = create_empty();
+       this->key = key;
+
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
 botan_rsa_public_key_t *botan_rsa_public_key_load(key_type_t type,
                                                                                                  va_list args)
 {
        private_botan_rsa_public_key_t *this = NULL;
-       chunk_t blob, n, e;
+       chunk_t n, e;
 
-       n = e = blob = chunk_empty;
+       n = e = chunk_empty;
        while (TRUE)
        {
                switch (va_arg(args, builder_part_t))
                {
-                       case BUILD_BLOB_ASN1_DER:
-                               blob = va_arg(args, chunk_t);
-                               continue;
                        case BUILD_RSA_MODULUS:
                                n = va_arg(args, chunk_t);
                                continue;
@@ -347,54 +360,7 @@ botan_rsa_public_key_t *botan_rsa_public_key_load(key_type_t type,
                break;
        }
 
-       if (blob.ptr)
-       {
-               switch (type)
-               {
-                       /* SubjectPublicKeyInfo */
-                       case KEY_RSA:
-                       case KEY_ANY:
-                       {
-                               size_t namesize = 0;
-                               char *namebuf;
-
-                               this = create_empty();
-
-                               if (botan_pubkey_load(&this->key, blob.ptr, blob.len))
-                               {
-                                       free(this);
-                                       return NULL;
-                               }
-
-                               if (botan_pubkey_algo_name(this->key, NULL, &namesize)
-                                       != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
-                               {
-                                       destroy(this);
-                                       return NULL;
-                               }
-
-                               namebuf = malloc(namesize);
-                               if (botan_pubkey_algo_name(this->key, namebuf, &namesize))
-                               {
-                                       free(namebuf);
-                                       destroy(this);
-                                       return NULL;
-                               }
-
-                               if (!strneq(namebuf, "RSA", namesize))
-                               {
-                                       free(namebuf);
-                                       destroy(this);
-                                       return NULL;
-                               }
-                               free(namebuf);
-                               break;
-                       }
-                       default:
-                               return NULL;
-               }
-       }
-       else if (n.ptr && e.ptr && type == KEY_RSA)
+       if (n.ptr && e.ptr && type == KEY_RSA)
        {
                botan_mp_t mp_n, mp_e;
 
index 4f6be83..1d80df9 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2018 René Korthaus
  * Rohde & Schwarz Cybersecurity GmbH
  *
 #ifndef BOTAN_RSA_PUBLIC_KEY_H_
 #define BOTAN_RSA_PUBLIC_KEY_H_
 
-typedef struct botan_rsa_public_key_t botan_rsa_public_key_t;
+#include <botan/ffi.h>
 
 #include <credentials/keys/public_key.h>
 
+typedef struct botan_rsa_public_key_t botan_rsa_public_key_t;
+
 /**
  * public_key_t implementation of RSA algorithm using Botan.
  */
@@ -47,7 +52,7 @@ struct botan_rsa_public_key_t {
 /**
  * Load a RSA public key using Botan.
  *
- * Accepts a BUILD_BLOB_ASN1_DER argument.
+ * Accepts a BUILD_RSA_MODULUS/BUILD_RSA_PUB_EXP arguments.
  *
  * @param type         type of the key, must be KEY_RSA
  * @param args         builder_part_t argument list
@@ -56,4 +61,12 @@ struct botan_rsa_public_key_t {
 botan_rsa_public_key_t *botan_rsa_public_key_load(key_type_t type,
                                                                                                  va_list args);
 
+/**
+ * Load a RSA public key by adopting a botan_pubkey_t object.
+ *
+ * @param key          public key object (adopted)
+ * @return                     loaded key, NULL on failure
+ */
+botan_rsa_public_key_t *botan_rsa_public_key_adopt(botan_pubkey_t key);
+
 #endif /** BOTAN_RSA_PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/botan/botan_util_keys.c b/src/libstrongswan/plugins/botan/botan_util_keys.c
new file mode 100644 (file)
index 0000000..176c2ca
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "botan_util_keys.h"
+#include "botan_ec_public_key.h"
+#include "botan_ec_private_key.h"
+#include "botan_rsa_public_key.h"
+#include "botan_rsa_private_key.h"
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+
+/**
+ * Get the algorithm name of a public key
+ */
+static char *get_algo_name(botan_pubkey_t pubkey)
+{
+       char *name;
+       size_t len = 0;
+
+       if (botan_pubkey_algo_name(pubkey, NULL, &len)
+               != BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE)
+       {
+               return NULL;
+       }
+
+       name = malloc(len);
+       if (botan_pubkey_algo_name(pubkey, name, &len))
+       {
+               free(name);
+               return NULL;
+       }
+       return name;
+}
+
+/*
+ * Described in header
+ */
+public_key_t *botan_public_key_load(key_type_t type, va_list args)
+{
+       public_key_t *this = NULL;
+       botan_pubkey_t pubkey;
+       chunk_t blob = chunk_empty;
+       botan_rng_t rng;
+       char *name;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+
+       if (botan_rng_init(&rng, "user"))
+       {
+               return NULL;
+       }
+       if (botan_pubkey_load(&pubkey, blob.ptr, blob.len))
+       {
+               botan_rng_destroy(rng);
+               return NULL;
+       }
+       if (botan_pubkey_check_key(pubkey, rng, BOTAN_CHECK_KEY_EXPENSIVE_TESTS))
+       {
+               DBG1(DBG_LIB, "public key failed key checks");
+               botan_pubkey_destroy(pubkey);
+               botan_rng_destroy(rng);
+               return NULL;
+       }
+       botan_rng_destroy(rng);
+
+       name = get_algo_name(pubkey);
+       if (!name)
+       {
+               botan_pubkey_destroy(pubkey);
+               return NULL;
+       }
+
+       if (streq(name, "RSA") && (type == KEY_ANY || type == KEY_RSA))
+       {
+               this = (public_key_t*)botan_rsa_public_key_adopt(pubkey);
+       }
+       else if (streq(name, "ECDSA") && (type == KEY_ANY || type == KEY_ECDSA))
+       {
+               this = (public_key_t*)botan_ec_public_key_adopt(pubkey);
+       }
+       else
+       {
+               botan_pubkey_destroy(pubkey);
+       }
+       free(name);
+       return this;
+}
+
+/**
+ * Determine the curve OID from a PKCS#8 structure
+ */
+static int determine_ec_oid(chunk_t pkcs8)
+{
+       int oid = OID_UNKNOWN;
+       chunk_t inner, params = chunk_empty;
+
+       if (asn1_unwrap(&pkcs8, &pkcs8) == ASN1_SEQUENCE &&
+               asn1_unwrap(&pkcs8, &inner) == ASN1_INTEGER &&
+               asn1_parse_integer_uint64(inner) == 0 &&
+               asn1_parse_algorithmIdentifier(pkcs8, 0, &params) == OID_EC_PUBLICKEY &&
+               params.len &&
+               asn1_unwrap(&params, &params) == ASN1_OID)
+       {
+               oid = asn1_known_oid(params);
+       }
+       return oid;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *botan_private_key_load(key_type_t type, va_list args)
+{
+       private_key_t *this = NULL;
+       botan_privkey_t key;
+       botan_pubkey_t pubkey;
+       chunk_t blob = chunk_empty;
+       botan_rng_t rng;
+       char *name;
+       int oid;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+
+       if (botan_rng_init(&rng, "user"))
+       {
+               return NULL;
+       }
+       if (botan_privkey_load(&key, rng, blob.ptr, blob.len, NULL))
+       {
+               botan_rng_destroy(rng);
+               return NULL;
+       }
+       botan_rng_destroy(rng);
+
+       if (botan_privkey_export_pubkey(&pubkey, key))
+       {
+               botan_privkey_destroy(key);
+               return NULL;
+       }
+       name = get_algo_name(pubkey);
+       botan_pubkey_destroy(pubkey);
+       if (!name)
+       {
+               return NULL;
+       }
+       if (streq(name, "RSA") && (type == KEY_ANY || type == KEY_RSA))
+       {
+               this = (private_key_t*)botan_rsa_private_key_adopt(key);
+       }
+       else if (streq(name, "ECDSA") && (type == KEY_ANY || type == KEY_ECDSA))
+       {
+               oid = determine_ec_oid(blob);
+               if (oid != OID_UNKNOWN)
+               {
+                       this = (private_key_t*)botan_ec_private_key_adopt(key, oid);
+               }
+       }
+       if (!this)
+       {
+               botan_privkey_destroy(key);
+       }
+       free(name);
+       return this;
+}
diff --git a/src/libstrongswan/plugins/botan/botan_util_keys.h b/src/libstrongswan/plugins/botan/botan_util_keys.h
new file mode 100644 (file)
index 0000000..f05f7ce
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Helper functions to load public and private keys in a generic way
+ *
+ * @defgroup botan_util_keys botan_util_keys
+ * @{ @ingroup botan_p
+ */
+
+#ifndef BOTAN_UTIL_KEYS_H_
+#define BOTAN_UTIL_KEYS_H_
+
+#include <botan/ffi.h>
+
+#include <credentials/keys/public_key.h>
+#include <credentials/keys/private_key.h>
+
+/**
+ * Load a public key in subjectPublicKeyInfo encoding
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+public_key_t *botan_public_key_load(key_type_t type, va_list args);
+
+/**
+ * Load a private key in PKCS#8 encoding
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+private_key_t *botan_private_key_load(key_type_t type, va_list args);
+
+#endif /** BOTAN_UTIL_KEYS_H_ @}*/