From 1e0f69373a4e55050eb2ebee211681326e647fae Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 14 Aug 2009 16:48:40 +0200 Subject: [PATCH] implemented a pkcs1 plugin providing PKCS#1 key parsing builders --- configure.in | 17 + src/libstrongswan/Makefile.am | 4 + src/libstrongswan/credentials/builder.c | 8 + src/libstrongswan/credentials/builder.h | 16 + .../credentials/credential_factory.c | 8 + src/libstrongswan/plugins/pkcs1/Makefile.am | 12 + .../plugins/pkcs1/pkcs1_builder.c | 377 ++++++++++++++++++ .../plugins/pkcs1/pkcs1_builder.h | 42 ++ .../plugins/pkcs1/pkcs1_plugin.c | 64 +++ .../plugins/pkcs1/pkcs1_plugin.h | 47 +++ 10 files changed, 595 insertions(+) create mode 100644 src/libstrongswan/plugins/pkcs1/Makefile.am create mode 100644 src/libstrongswan/plugins/pkcs1/pkcs1_builder.c create mode 100644 src/libstrongswan/plugins/pkcs1/pkcs1_builder.h create mode 100644 src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c create mode 100644 src/libstrongswan/plugins/pkcs1/pkcs1_plugin.h diff --git a/configure.in b/configure.in index 97bd331b1..73941db43 100644 --- a/configure.in +++ b/configure.in @@ -287,6 +287,17 @@ AC_ARG_ENABLE( pubkey=true ) +AC_ARG_ENABLE( + [pkcs1], + AS_HELP_STRING([--disable-pkcs],[disable PKCS1 key decoding plugin. (default is NO).]), + [if test x$enableval = xyes; then + pkcs1=true + else + pkcs1=false + fi], + pkcs1=true +) + AC_ARG_ENABLE( [pem], AS_HELP_STRING([--disable-pem],[disable PEM decoding plugin. (default is NO).]), @@ -1192,6 +1203,10 @@ if test x$pubkey = xtrue; then libstrongswan_plugins=${libstrongswan_plugins}" pubkey" pluto_plugins=${pluto_plugins}" pubkey" fi +if test x$pkcs1 = xtrue; then + libstrongswan_plugins=${libstrongswan_plugins}" pkcs1" + pluto_plugins=${pluto_plugins}" pkcs1" +fi if test x$pem = xtrue; then libstrongswan_plugins=${libstrongswan_plugins}" pem" pluto_plugins=${pluto_plugins}" pem" @@ -1252,6 +1267,7 @@ AM_CONDITIONAL(USE_GMP, test x$gmp = xtrue) AM_CONDITIONAL(USE_RANDOM, test x$random = xtrue) AM_CONDITIONAL(USE_X509, test x$x509 = xtrue) AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue) +AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue) AM_CONDITIONAL(USE_PEM, test x$pem = xtrue) AM_CONDITIONAL(USE_HMAC, test x$hmac = xtrue) AM_CONDITIONAL(USE_XCBC, test x$xcbc = xtrue) @@ -1347,6 +1363,7 @@ AC_OUTPUT( src/libstrongswan/plugins/xcbc/Makefile src/libstrongswan/plugins/x509/Makefile src/libstrongswan/plugins/pubkey/Makefile + src/libstrongswan/plugins/pkcs1/Makefile src/libstrongswan/plugins/pem/Makefile src/libstrongswan/plugins/curl/Makefile src/libstrongswan/plugins/ldap/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 9dabcfa9b..e3585cf99 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -161,6 +161,10 @@ if USE_PUBKEY SUBDIRS += plugins/pubkey endif +if USE_PKCS1 + SUBDIRS += plugins/pkcs1 +endif + if USE_PEM SUBDIRS += plugins/pem endif diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index 8a799d3cd..8151f14b3 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -41,6 +41,14 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END, "BUILD_X509_FLAG", "BUILD_SMARTCARD_KEYID", "BUILD_SMARTCARD_PIN", + "BUILD_RSA_MODULUS", + "BUILD_RSA_PUB_EXP", + "BUILD_RSA_PRIV_EXP", + "BUILD_RSA_PRIME1", + "BUILD_RSA_PRIME2", + "BUILD_RSA_EXP1", + "BUILD_RSA_EXP2", + "BUILD_RSA_COEFF", "BUILD_END", ); diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 9c73f6e7c..17fc77680 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -90,6 +90,22 @@ enum builder_part_t { BUILD_SMARTCARD_KEYID, /** pin to access a key on a smartcard, null terminated char* */ BUILD_SMARTCARD_PIN, + /** modulus (n) of a RSA key, chunk_t */ + BUILD_RSA_MODULUS, + /** public exponent (e) of a RSA key, chunk_t */ + BUILD_RSA_PUB_EXP, + /** private exponent (d) of a RSA key, chunk_t */ + BUILD_RSA_PRIV_EXP, + /** prime 1 (p) of a RSA key, chunk_t */ + BUILD_RSA_PRIME1, + /** prime 2 (q) of a RSA key, chunk_t */ + BUILD_RSA_PRIME2, + /** exponent 1 (exp1) of a RSA key, chunk_t */ + BUILD_RSA_EXP1, + /** exponent 2 (exp1) of a RSA key, chunk_t */ + BUILD_RSA_EXP2, + /** coefficient (coeff) of a RSA key, chunk_t */ + BUILD_RSA_COEFF, /** 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 bce9c7d9e..7574a0b7a 100644 --- a/src/libstrongswan/credentials/credential_factory.c +++ b/src/libstrongswan/credentials/credential_factory.c @@ -169,6 +169,14 @@ static void* create(private_credential_factory_t *this, credential_type_t type, case BUILD_BLOB_RFC_3110: case BUILD_PASSPHRASE: case BUILD_SERIAL: + case BUILD_RSA_MODULUS: + case BUILD_RSA_PUB_EXP: + case BUILD_RSA_PRIV_EXP: + case BUILD_RSA_PRIME1: + case BUILD_RSA_PRIME2: + case BUILD_RSA_EXP1: + case BUILD_RSA_EXP2: + case BUILD_RSA_COEFF: builder->add(builder, part, va_arg(args, chunk_t)); continue; case BUILD_X509_FLAG: diff --git a/src/libstrongswan/plugins/pkcs1/Makefile.am b/src/libstrongswan/plugins/pkcs1/Makefile.am new file mode 100644 index 000000000..d50b9184b --- /dev/null +++ b/src/libstrongswan/plugins/pkcs1/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-pkcs1.la + +libstrongswan_pkcs1_la_SOURCES = pkcs1_plugin.h pkcs1_plugin.c \ + pkcs1_builder.h pkcs1_builder.c + +libstrongswan_pkcs1_la_LDFLAGS = -module -avoid-version + diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c new file mode 100644 index 000000000..abb6c0c0b --- /dev/null +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2008-2009 Martin Willi + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2000-2008 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pkcs1_builder.h" + +#include +#include +#include +#include +#include + +/** + * ASN.1 definition of a subjectPublicKeyInfo structure + */ +static const asn1Object_t pkinfoObjects[] = { + { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM 1 +#define PKINFO_SUBJECT_PUBLIC_KEY 2 + +/** + * Load a generic public key from an ASN.1 encoded blob + */ +static public_key_t *parse_public_key(chunk_t blob) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + public_key_t *key = NULL; + key_type_t type = KEY_ANY; + + parser = asn1_parser_create(pkinfoObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser)+1, NULL); + + if (oid == OID_RSA_ENCRYPTION) + { + type = KEY_RSA; + } + else if (oid == OID_EC_PUBLICKEY) + { + /* we need the whole subjectPublicKeyInfo for EC public keys */ + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, + KEY_ECDSA, BUILD_BLOB_ASN1_DER, blob, BUILD_END); + goto end; + } + else + { + /* key type not supported */ + goto end; + } + break; + } + case PKINFO_SUBJECT_PUBLIC_KEY: + if (object.len > 0 && *object.ptr == 0x00) + { + /* skip initial bit string octet defining 0 unused bits */ + object = chunk_skip(object, 1); + } + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type, + BUILD_BLOB_ASN1_DER, object, BUILD_END); + break; + } + } + +end: + parser->destroy(parser); + return key; +} + +/** + * ASN.1 definition of RSApublicKey + */ +static const asn1Object_t pubkeyObjects[] = { + { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PUB_KEY_RSA_PUBLIC_KEY 0 +#define PUB_KEY_MODULUS 1 +#define PUB_KEY_EXPONENT 2 + +/** + * Load a RSA public key from an ASN.1 encoded blob. + */ +static public_key_t *parse_rsa_public_key(chunk_t blob) +{ + chunk_t n, e; + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success = FALSE; + + parser = asn1_parser_create(pubkeyObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PUB_KEY_MODULUS: + n = object; + break; + case PUB_KEY_EXPONENT: + e = object; + break; + } + } + success = parser->success(parser); + parser->destroy(parser); + + if (!success) + { + return NULL; + } + return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END); +} + +/** + * ASN.1 definition of a PKCS#1 RSA private key + */ +static const asn1Object_t privkeyObjects[] = { + { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */ + { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */ + { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */ + { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */ + { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */ + { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 10 */ + { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ + { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */ + { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */ + { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 15 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PRIV_KEY_VERSION 1 +#define PRIV_KEY_MODULUS 2 +#define PRIV_KEY_PUB_EXP 3 +#define PRIV_KEY_PRIV_EXP 4 +#define PRIV_KEY_PRIME1 5 +#define PRIV_KEY_PRIME2 6 +#define PRIV_KEY_EXP1 7 +#define PRIV_KEY_EXP2 8 +#define PRIV_KEY_COEFF 9 + +/** + * Load a RSA private key from a ASN1 encoded blob. + */ +static private_key_t *parse_rsa_private_key(chunk_t blob) +{ + chunk_t n, e, d, p, q, exp1, exp2, coeff; + asn1_parser_t *parser; + chunk_t object; + int objectID ; + bool success = FALSE; + + parser = asn1_parser_create(privkeyObjects, blob); + parser->set_flags(parser, FALSE, TRUE); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PRIV_KEY_VERSION: + if (object.len > 0 && *object.ptr != 0) + { + DBG1("PKCS#1 private key format is not version 1"); + goto end; + } + break; + case PRIV_KEY_MODULUS: + n = object; + break; + case PRIV_KEY_PUB_EXP: + e = object; + break; + case PRIV_KEY_PRIV_EXP: + d = object; + break; + case PRIV_KEY_PRIME1: + p = object; + break; + case PRIV_KEY_PRIME2: + q = object; + break; + case PRIV_KEY_EXP1: + exp1 = object; + break; + case PRIV_KEY_EXP2: + exp2 = object; + break; + case PRIV_KEY_COEFF: + coeff = object; + break; + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (!success) + { + return NULL; + } + return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_RSA_PRIV_EXP, d, + BUILD_RSA_PRIME1, p, BUILD_RSA_PRIME2, q, BUILD_RSA_EXP1, exp1, + BUILD_RSA_EXP2, exp2, BUILD_RSA_COEFF, coeff, BUILD_END); +} + +typedef struct private_builder_t private_builder_t; + +/** + * Builder implementation for private/public key loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** asn1 der encoded data */ + chunk_t blob; + /** type of key to build */ + key_type_t type; +}; + +/** + * Implementation of builder_t.build for public keys + */ +static public_key_t *build_public(private_builder_t *this) +{ + public_key_t *key = NULL; + + switch (this->type) + { + case KEY_ANY: + key = parse_public_key(this->blob); + break; + case KEY_RSA: + key = parse_rsa_public_key(this->blob); + break; + default: + break; + } + free(this); + return key; +} + +/** + * Implementation of builder_t.add for public keys + */ +static void add_public(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->blob = va_arg(args, chunk_t); + va_end(args); + break; + } + default: + builder_cancel(&this->public); + break; + } +} + +/** + * Builder construction function for public keys + */ +builder_t *pkcs1_public_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_ANY && type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->blob = chunk_empty; + this->type = type; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add_public; + this->public.build = (void*(*)(builder_t *this))build_public; + + return &this->public; +} + +/** + * Implementation of builder_t.build for private keys + */ +static private_key_t *build_private(private_builder_t *this) +{ + private_key_t *key; + + key = parse_rsa_private_key(this->blob); + free(this); + return key; +} + +/** + * Implementation of builder_t.add for private keys + */ +static void add_private(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->blob = va_arg(args, chunk_t); + va_end(args); + break; + } + default: + builder_cancel(&this->public); + break; + } +} + +/** + * Builder construction function for private keys + */ +builder_t *pkcs1_private_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->blob = chunk_empty; + this->type = type; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add_private; + this->public.build = (void*(*)(builder_t *this))build_private; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.h b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.h new file mode 100644 index 000000000..fdc802587 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pkcs1_public_key pkcs1_public_key + * @{ @ingroup pkcs1_p + */ + +#ifndef PKCS1_BUILDER_H_ +#define PKCS1_BUILDER_H_ + +#include + +/** + * Create the builder for a generic or an RSA public key. + * + * @param type type of the key, either KEY_ANY or KEY_RSA + * @return builder instance + */ +builder_t *pkcs1_public_key_builder(key_type_t type); + +/** + * Create the builder for a RSA private key. + * + * @param type type of the key, KEY_RSA + * @return builder instance + */ +builder_t *pkcs1_private_key_builder(key_type_t type); + +#endif /** PKCS1_BUILDER_H_ @}*/ diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c b/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c new file mode 100644 index 000000000..453a28d7d --- /dev/null +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pkcs1_plugin.h" + +#include +#include "pkcs1_builder.h" + +typedef struct private_pkcs1_plugin_t private_pkcs1_plugin_t; + +/** + * private data of pkcs1_plugin + */ +struct private_pkcs1_plugin_t { + + /** + * public functions + */ + pkcs1_plugin_t public; +}; + +/** + * Implementation of pkcs1_plugin_t.pkcs1troy + */ +static void destroy(private_pkcs1_plugin_t *this) +{ + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)pkcs1_public_key_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)pkcs1_private_key_builder); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_pkcs1_plugin_t *this = malloc_thing(private_pkcs1_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + (builder_constructor_t)pkcs1_public_key_builder); + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + (builder_constructor_t)pkcs1_public_key_builder); + lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + (builder_constructor_t)pkcs1_private_key_builder); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.h b/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.h new file mode 100644 index 000000000..3b77de179 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pkcs1_p pkcs1 + * @ingroup plugins + * + * @defgroup pkcs1_plugin pkcs1_plugin + * @{ @ingroup pkcs1_p + */ + +#ifndef PKCS1_PLUGIN_H_ +#define PKCS1_PLUGIN_H_ + +#include + +typedef struct pkcs1_plugin_t pkcs1_plugin_t; + +/** + * Plugin providing PKCS#1 private/public key decoding functions + */ +struct pkcs1_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a pkcs1_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /** PKCS1_PLUGIN_H_ @}*/