diff --git a/configure.in b/configure.in index c51146a12..c858a294c 100644 --- a/configure.in +++ b/configure.in @@ -129,6 +129,7 @@ ARG_DISBL_SET([pubkey], [disable RAW public key support plugin.]) ARG_DISBL_SET([pkcs1], [disable PKCS1 key decoding plugin.]) ARG_DISBL_SET([pkcs7], [disable PKCS7 container support plugin.]) ARG_DISBL_SET([pkcs8], [disable PKCS8 private key decoding plugin.]) +ARG_DISBL_SET([pkcs12], [disable PKCS12 container support plugin.]) ARG_DISBL_SET([pgp], [disable PGP key decoding plugin.]) ARG_DISBL_SET([dnskey], [disable DNS RR key decoding plugin.]) ARG_DISBL_SET([sshkey], [disable SSH key decoding plugin.]) @@ -966,8 +967,9 @@ ADD_PLUGIN([revocation], [s charon nm cmd]) ADD_PLUGIN([constraints], [s charon nm cmd]) ADD_PLUGIN([pubkey], [s charon cmd]) ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) -ADD_PLUGIN([pkcs7], [s scepclient pki]) +ADD_PLUGIN([pkcs7], [s scepclient pki scripts]) ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) +ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts]) ADD_PLUGIN([pgp], [s charon]) ADD_PLUGIN([dnskey], [s charon]) ADD_PLUGIN([sshkey], [s charon nm cmd]) @@ -1100,6 +1102,7 @@ AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue) AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue) AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue) AM_CONDITIONAL(USE_PKCS8, test x$pkcs8 = xtrue) +AM_CONDITIONAL(USE_PKCS12, test x$pkcs12 = xtrue) AM_CONDITIONAL(USE_PGP, test x$pgp = xtrue) AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue) AM_CONDITIONAL(USE_SSHKEY, test x$sshkey = xtrue) @@ -1296,6 +1299,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/pkcs1/Makefile src/libstrongswan/plugins/pkcs7/Makefile src/libstrongswan/plugins/pkcs8/Makefile + src/libstrongswan/plugins/pkcs12/Makefile src/libstrongswan/plugins/pgp/Makefile src/libstrongswan/plugins/dnskey/Makefile src/libstrongswan/plugins/sshkey/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index db1f8cf33..2465fb09d 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -309,6 +309,13 @@ if MONOLITHIC endif endif +if USE_PKCS12 + SUBDIRS += plugins/pkcs12 +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/pkcs12/libstrongswan-pkcs12.la +endif +endif + if USE_PGP SUBDIRS += plugins/pgp if MONOLITHIC diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index 8cbd07e4b..6030aa111 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -121,6 +121,9 @@ 0x08 "unstructuredAddress" OID_UNSTRUCTURED_ADDRESS 0x0E "extensionRequest" OID_EXTENSION_REQUEST 0x0F "S/MIME Capabilities" + 0x16 "certTypes" + 0x01 "X.509" OID_X509_CERTIFICATE + 0x02 "SDSI" 0x0c "PKCS-12" 0x01 "pbeIds" 0x01 "pbeWithSHAAnd128BitRC4" OID_PBE_SHA1_RC4_128 @@ -129,6 +132,14 @@ 0x04 "pbeWithSHAAnd2-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_2KEY_CBC 0x05 "pbeWithSHAAnd128BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_128 0x06 "pbeWithSHAAnd40BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_40 + 0x0a "PKCS-12v1" + 0x01 "bagIds" + 0x01 "keyBag" OID_P12_KEY_BAG + 0x02 "pkcs8ShroudedKeyBag" OID_P12_PKCS8_KEY_BAG + 0x03 "certBag" OID_P12_CERT_BAG + 0x04 "crlBag" OID_P12_CRL_BAG + 0x05 "secretBag" + 0x06 "safeContentsBag" 0x02 "digestAlgorithm" 0x02 "md2" OID_MD2 0x05 "md5" OID_MD5 diff --git a/src/libstrongswan/credentials/containers/container.c b/src/libstrongswan/credentials/containers/container.c index 9f01f559d..7456d43db 100644 --- a/src/libstrongswan/credentials/containers/container.c +++ b/src/libstrongswan/credentials/containers/container.c @@ -15,10 +15,11 @@ #include "container.h" -ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS7_ENCRYPTED_DATA, +ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS12, "PKCS7", "PKCS7_DATA", "PKCS7_SIGNED_DATA", "PKCS7_ENVELOPED_DATA", "PKCS7_ENCRYPTED_DATA", + "PKCS12", ); diff --git a/src/libstrongswan/credentials/containers/container.h b/src/libstrongswan/credentials/containers/container.h index ff1d1e1a2..ee329881d 100644 --- a/src/libstrongswan/credentials/containers/container.h +++ b/src/libstrongswan/credentials/containers/container.h @@ -44,6 +44,8 @@ enum container_type_t { CONTAINER_PKCS7_ENVELOPED_DATA, /** PKCS#7/CMS "encrypted-data" */ CONTAINER_PKCS7_ENCRYPTED_DATA, + /** A PKCS#12 container */ + CONTAINER_PKCS12, }; /** diff --git a/src/libstrongswan/credentials/containers/pkcs12.h b/src/libstrongswan/credentials/containers/pkcs12.h index a6c9746ef..f22ef045a 100644 --- a/src/libstrongswan/credentials/containers/pkcs12.h +++ b/src/libstrongswan/credentials/containers/pkcs12.h @@ -21,9 +21,11 @@ #ifndef PKCS12_H_ #define PKCS12_H_ +#include #include typedef enum pkcs12_key_type_t pkcs12_key_type_t; +typedef struct pkcs12_t pkcs12_t; /** * The types of password based keys used by PKCS#12. @@ -34,6 +36,31 @@ enum pkcs12_key_type_t { PKCS12_KEY_MAC = 3, }; +/** + * PKCS#12/PFX container type. + */ +struct pkcs12_t { + + /** + * Implements container_t. + */ + container_t container; + + /** + * Create an enumerator over extracted certificates. + * + * @return enumerator over certificate_t + */ + enumerator_t* (*create_cert_enumerator)(pkcs12_t *this); + + /** + * Create an enumerator over extracted private keys. + * + * @return enumerator over private_key_t + */ + enumerator_t* (*create_key_enumerator)(pkcs12_t *this); +}; + /** * Derive the keys used in PKCS#12 for password integrity/privacy mode. * diff --git a/src/libstrongswan/plugins/pkcs12/Makefile.am b/src/libstrongswan/plugins/pkcs12/Makefile.am new file mode 100644 index 000000000..1f703bd6c --- /dev/null +++ b/src/libstrongswan/plugins/pkcs12/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-pkcs12.la +else +plugin_LTLIBRARIES = libstrongswan-pkcs12.la +endif + +libstrongswan_pkcs12_la_SOURCES = \ + pkcs12_plugin.h pkcs12_plugin.c \ + pkcs12_decode.h pkcs12_decode.c + +libstrongswan_pkcs12_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c b/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c new file mode 100644 index 000000000..379f24796 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * 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 "pkcs12_decode.h" + +#include +#include +#include +#include +#include + +typedef struct private_pkcs12_t private_pkcs12_t; + +/** + * Private data of a pkcs12_t object + */ +struct private_pkcs12_t { + + /** + * Public interface + */ + pkcs12_t public; + + /** + * Contained credentials + */ + mem_cred_t *creds; +}; + +METHOD(container_t, get_type, container_type_t, + private_pkcs12_t *this) +{ + return CONTAINER_PKCS12; +} + +METHOD(container_t, get_data, bool, + private_pkcs12_t *this, chunk_t *data) +{ + /* we could return the content of the outer-most PKCS#7 container (authSafe) + * don't really see the point though */ + return FALSE; +} + +METHOD(container_t, get_encoding, bool, + private_pkcs12_t *this, chunk_t *encoding) +{ + /* similar to get_data() we don't have any use for it at the moment */ + return FALSE; +} + +METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*, + private_pkcs12_t *this) +{ + return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY, + KEY_ANY, NULL, FALSE); +} + +METHOD(pkcs12_t, create_key_enumerator, enumerator_t*, + private_pkcs12_t *this) +{ + return this->creds->set.create_private_enumerator(&this->creds->set, + KEY_ANY, NULL); +} + +METHOD(container_t, destroy, void, + private_pkcs12_t *this) +{ + this->creds->destroy(this->creds); + free(this); +} + +static private_pkcs12_t *pkcs12_create() +{ + private_pkcs12_t *this; + + INIT(this, + .public = { + .container = { + .get_type = _get_type, + .create_signature_enumerator = (void*)enumerator_create_empty, + .get_data = _get_data, + .get_encoding = _get_encoding, + .destroy = _destroy, + }, + .create_cert_enumerator = _create_cert_enumerator, + .create_key_enumerator = _create_key_enumerator, + }, + .creds = mem_cred_create(), + ); + return this; +} + +/** + * ASN.1 definition of an CertBag structure + */ +static const asn1Object_t certBagObjects[] = { + { 0, "CertBag", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ + { 1, "certId", ASN1_OID, ASN1_BODY }, /* 1 */ + { 1, "certValue", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define CERT_BAG_ID 1 +#define CERT_BAG_VALUE 2 + +/** + * Parse a CertBag structure and extract certificate + */ +static bool add_certificate(private_pkcs12_t *this, int level0, chunk_t blob) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + int oid = OID_UNKNOWN; + bool success = FALSE; + + parser = asn1_parser_create(certBagObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case CERT_BAG_ID: + oid = asn1_known_oid(object); + break; + case CERT_BAG_VALUE: + { + if (oid == OID_X509_CERTIFICATE && + asn1_parse_simple_object(&object, ASN1_OCTET_STRING, + parser->get_level(parser)+1, "x509Certificate")) + { + certificate_t *cert; + + DBG2(DBG_ASN, "-- > parsing certificate from PKCS#12"); + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert) + { + this->creds->add_cert(this->creds, FALSE, cert); + DBG2(DBG_ASN, "-- < --"); + } + else + { + DBG2(DBG_ASN, "-- < failed parsing certificate from " + "PKCS#12"); + } + } + break; + } + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * ASN.1 definition of an AuthenticatedSafe structure + */ +static const asn1Object_t safeContentsObjects[] = { + { 0, "SafeContents", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "SafeBag", ASN1_SEQUENCE, ASN1_BODY }, /* 1 */ + { 2, "bagId", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "bagValue", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 3 */ + { 2, "bagAttr", ASN1_SET, ASN1_OPT|ASN1_RAW }, /* 4 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define SAFE_BAG_ID 2 +#define SAFE_BAG_VALUE 3 + +/** + * Parse a SafeContents structure and extract credentials + */ +static bool parse_safe_contents(private_pkcs12_t *this, int level0, + chunk_t blob) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + int oid = OID_UNKNOWN; + bool success = FALSE; + + parser = asn1_parser_create(safeContentsObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case SAFE_BAG_ID: + oid = asn1_known_oid(object); + break; + case SAFE_BAG_VALUE: + { + switch (oid) + { + case OID_P12_CERT_BAG: + { + add_certificate(this, parser->get_level(parser)+1, + object); + break; + } + case OID_P12_KEY_BAG: + case OID_P12_PKCS8_KEY_BAG: + { + private_key_t *key; + + DBG2(DBG_ASN, "-- > parsing private key from PKCS#12"); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + KEY_ANY, BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (key) + { + this->creds->add_key(this->creds, key); + DBG2(DBG_ASN, "-- < --"); + } + else + { + DBG2(DBG_ASN, "-- < failed parsing private key " + "from PKCS#12"); + } + } + default: + break; + } + break; + } + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * ASN.1 definition of an AuthenticatedSafe structure + */ +static const asn1Object_t authenticatedSafeObjects[] = { + { 0, "AuthenticatedSafe", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "ContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define AUTHENTICATED_SAFE_DATA 1 + +/** + * Parse an AuthenticatedSafe structure + */ +static bool parse_authenticated_safe(private_pkcs12_t *this, chunk_t blob) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success = FALSE; + + parser = asn1_parser_create(authenticatedSafeObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case AUTHENTICATED_SAFE_DATA: + { + container_t *container; + chunk_t data; + + container = lib->creds->create(lib->creds, CRED_CONTAINER, + CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER, + object, BUILD_END); + if (!container) + { + goto end; + } + switch (container->get_type(container)) + { + case CONTAINER_PKCS7_DATA: + case CONTAINER_PKCS7_ENCRYPTED_DATA: + case CONTAINER_PKCS7_ENVELOPED_DATA: + if (container->get_data(container, &data)) + { + break; + } + /* fall-through */ + default: + container->destroy(container); + goto end; + } + container->destroy(container); + + if (!parse_safe_contents(this, parser->get_level(parser)+1, + data)) + { + chunk_free(&data); + goto end; + } + chunk_free(&data); + break; + } + } + } + success = parser->success(parser); +end: + parser->destroy(parser); + return success; +} + +/** + * Verify the given MAC with available passwords. + */ +static bool verify_mac(hash_algorithm_t hash, chunk_t salt, + u_int64_t iterations, chunk_t data, chunk_t mac) +{ + integrity_algorithm_t integ; + enumerator_t *enumerator; + shared_key_t *shared; + signer_t *signer; + chunk_t key, calculated; + bool success = FALSE; + + integ = hasher_algorithm_to_integrity(hash, mac.len); + signer = lib->crypto->create_signer(lib->crypto, integ); + if (!signer) + { + return FALSE; + } + key = chunk_alloca(signer->get_key_size(signer)); + calculated = chunk_alloca(signer->get_block_size(signer)); + + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_PRIVATE_KEY_PASS, NULL, NULL); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) + { + if (!pkcs12_derive_key(hash, shared->get_key(shared), salt, iterations, + PKCS12_KEY_MAC, key)) + { + break; + } + if (!signer->set_key(signer, key) || + !signer->get_signature(signer, data, calculated.ptr)) + { + break; + } + if (chunk_equals(mac, calculated)) + { + success = TRUE; + break; + } + } + enumerator->destroy(enumerator); + signer->destroy(signer); + return success; +} + +/** + * ASN.1 definition of digestInfo + */ +static const asn1Object_t digestInfoObjects[] = { + { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define DIGEST_INFO_ALGORITHM 1 +#define DIGEST_INFO_DIGEST 2 + +/** + * Parse a digestInfo structure + */ +static bool parse_digest_info(chunk_t blob, int level0, hash_algorithm_t *hash, + chunk_t *digest) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success; + + parser = asn1_parser_create(digestInfoObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + + { + case DIGEST_INFO_ALGORITHM: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser)+1, NULL); + + *hash = hasher_algorithm_from_oid(oid); + break; + } + case DIGEST_INFO_DIGEST: + { + *digest = object; + break; + } + default: + break; + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * ASN.1 definition of a PFX structure + */ +static const asn1Object_t PFXObjects[] = { + { 0, "PFX", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "authSafe", ASN1_SEQUENCE, ASN1_OBJ }, /* 2 */ + { 1, "macData", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 3 */ + { 2, "mac", ASN1_SEQUENCE, ASN1_RAW }, /* 4 */ + { 2, "macSalt", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ + { 2, "iterations", ASN1_INTEGER, ASN1_DEF|ASN1_BODY }, /* 6 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PFX_AUTH_SAFE 2 +#define PFX_MAC 4 +#define PFX_SALT 5 +#define PFX_ITERATIONS 6 + +/** + * Parse an ASN.1 encoded PFX structure + */ +static bool parse_PFX(private_pkcs12_t *this, chunk_t blob) +{ + asn1_parser_t *parser; + int objectID; + chunk_t object, auth_safe, digest = chunk_empty, salt = chunk_empty, + data = chunk_empty; + hash_algorithm_t hash = HASH_UNKNOWN; + container_t *container = NULL; + u_int64_t iterations = 0; + bool success = FALSE; + + parser = asn1_parser_create(PFXObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PFX_AUTH_SAFE: + { + auth_safe = object; + break; + } + case PFX_MAC: + { + if (!parse_digest_info(object, parser->get_level(parser)+1, + &hash, &digest)) + { + goto end_parse; + } + break; + } + case PFX_SALT: + { + salt = object; + break; + } + case PFX_ITERATIONS: + { + iterations = object.len ? asn1_parse_integer_uint64(object) : 1; + break; + } + } + } + success = parser->success(parser); + +end_parse: + parser->destroy(parser); + if (!success) + { + return FALSE; + } + + success = FALSE; + DBG2(DBG_ASN, "-- > --"); + container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7, + BUILD_BLOB_ASN1_DER, auth_safe, BUILD_END); + if (container && container->get_data(container, &data)) + { + if (hash != HASH_UNKNOWN) + { + if (container->get_type(container) != CONTAINER_PKCS7_DATA) + { + goto end; + } + if (!verify_mac(hash, salt, iterations, data, digest)) + { + DBG1(DBG_ASN, " MAC verification of PKCS#12 container failed"); + goto end; + } + } + else + { + enumerator_t *enumerator; + auth_cfg_t *auth; + + if (container->get_type(container) != CONTAINER_PKCS7_SIGNED_DATA) + { + goto end; + } + enumerator = container->create_signature_enumerator(container); + if (!enumerator->enumerate(enumerator, &auth)) + { + DBG1(DBG_ASN, " signature verification of PKCS#12 container " + "failed"); + enumerator->destroy(enumerator); + goto end; + } + enumerator->destroy(enumerator); + } + success = parse_authenticated_safe(this, data); + } +end: + DBG2(DBG_ASN, "-- < --"); + DESTROY_IF(container); + chunk_free(&data); + return success; +} + +/** + * See header. + */ +pkcs12_t *pkcs12_decode(container_type_t type, va_list args) +{ + private_pkcs12_t *this; + chunk_t blob = 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_END: + break; + default: + return NULL; + } + break; + } + if (blob.len) + { + if (blob.len >= 2 && + blob.ptr[0] == ASN1_SEQUENCE && blob.ptr[1] == 0x80) + { /* looks like infinite length BER encoding, but we can't handle it. + */ + return NULL; + } + this = pkcs12_create(); + if (parse_PFX(this, blob)) + { + return &this->public; + } + destroy(this); + } + return NULL; +} diff --git a/src/libstrongswan/plugins/pkcs12/pkcs12_decode.h b/src/libstrongswan/plugins/pkcs12/pkcs12_decode.h new file mode 100644 index 000000000..e2998968f --- /dev/null +++ b/src/libstrongswan/plugins/pkcs12/pkcs12_decode.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * 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 pkcs12_decode pkcs12_decode + * @{ @ingroup pkcs12 + */ + +#ifndef PKCS12_DECODE_H_ +#define PKCS12_DECODE_H_ + +#include +#include + +/** + * Load a PKCS#12 container. + * + * The argument list must contain a single BUILD_BLOB_ASN1_DER argument. + * + * @param type type of the container, CONTAINER_PKCS12 + * @param args builder_part_t argument list + * @return container, NULL on failure + */ +pkcs12_t *pkcs12_decode(container_type_t type, va_list args); + +#endif /** PKCS12_DECODE_H_ @}*/ diff --git a/src/libstrongswan/plugins/pkcs12/pkcs12_plugin.c b/src/libstrongswan/plugins/pkcs12/pkcs12_plugin.c new file mode 100644 index 000000000..ae0fb9093 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs12/pkcs12_plugin.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * 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 "pkcs12_plugin.h" + +#include + +#include "pkcs12_decode.h" + +typedef struct private_pkcs12_plugin_t private_pkcs12_plugin_t; + +/** + * private data of pkcs12_plugin + */ +struct private_pkcs12_plugin_t { + + /** + * public functions + */ + pkcs12_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_pkcs12_plugin_t *this) +{ + return "pkcs12"; +} + +METHOD(plugin_t, get_features, int, + private_pkcs12_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_REGISTER(CONTAINER_DECODE, pkcs12_decode, FALSE), + PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS12), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_pkcs12_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *pkcs12_plugin_create() +{ + private_pkcs12_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/pkcs12/pkcs12_plugin.h b/src/libstrongswan/plugins/pkcs12/pkcs12_plugin.h new file mode 100644 index 000000000..3bd7f2df3 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs12/pkcs12_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * 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 PURPSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pkcs12 pkcs12 + * @ingroup plugins + * + * @defgroup pkcs12_plugin pkcs12_plugin + * @{ @ingroup pkcs12 + */ + +#ifndef PKCS12_PLUGIN_H_ +#define PKCS12_PLUGIN_H_ + +#include + +typedef struct pkcs12_plugin_t pkcs12_plugin_t; + +/** + * Plugin providing PKCS#12 decoding functions + */ +struct pkcs12_plugin_t { + + /** + * Implements plugin interface. + */ + plugin_t plugin; +}; + +#endif /** PKCS12_PLUGIN_H_ @}*/