From 8e48e0009aa9cb64348f910fbda5f66d0a4d901e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 11 Apr 2013 16:19:16 +0200 Subject: [PATCH] Add support for PKCS#7/CMS encrypted-data --- .../credentials/containers/container.c | 3 +- .../credentials/containers/container.h | 13 +- src/libstrongswan/plugins/pkcs7/Makefile.am | 1 + .../plugins/pkcs7/pkcs7_encrypted_data.c | 216 ++++++++++++++++++ .../plugins/pkcs7/pkcs7_encrypted_data.h | 36 +++ .../plugins/pkcs7/pkcs7_generic.c | 3 + 6 files changed, 267 insertions(+), 5 deletions(-) create mode 100644 src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.c create mode 100644 src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.h diff --git a/src/libstrongswan/credentials/containers/container.c b/src/libstrongswan/credentials/containers/container.c index d1e67b21b..9f01f559d 100644 --- a/src/libstrongswan/credentials/containers/container.c +++ b/src/libstrongswan/credentials/containers/container.c @@ -15,9 +15,10 @@ #include "container.h" -ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS7_ENVELOPED_DATA, +ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS7_ENCRYPTED_DATA, "PKCS7", "PKCS7_DATA", "PKCS7_SIGNED_DATA", "PKCS7_ENVELOPED_DATA", + "PKCS7_ENCRYPTED_DATA", ); diff --git a/src/libstrongswan/credentials/containers/container.h b/src/libstrongswan/credentials/containers/container.h index fc5c09041..ff1d1e1a2 100644 --- a/src/libstrongswan/credentials/containers/container.h +++ b/src/libstrongswan/credentials/containers/container.h @@ -1,4 +1,7 @@ /* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2012 Martin Willi * Copyright (C) 2012 revosec AG * @@ -31,14 +34,16 @@ typedef enum container_type_t container_type_t; * Type of the container. */ enum container_type_t { - /** Any kind of PKCS7/CMS container */ + /** Any kind of PKCS#7/CMS container */ CONTAINER_PKCS7, - /** PKCS7/CMS plain "data" */ + /** PKCS#7/CMS plain "data" */ CONTAINER_PKCS7_DATA, - /** PKCS7/CMS "signed-data" */ + /** PKCS#7/CMS "signed-data" */ CONTAINER_PKCS7_SIGNED_DATA, - /** PKCS7/CMS "enveloped-data" */ + /** PKCS#7/CMS "enveloped-data" */ CONTAINER_PKCS7_ENVELOPED_DATA, + /** PKCS#7/CMS "encrypted-data" */ + CONTAINER_PKCS7_ENCRYPTED_DATA, }; /** diff --git a/src/libstrongswan/plugins/pkcs7/Makefile.am b/src/libstrongswan/plugins/pkcs7/Makefile.am index 6310daece..000bde23e 100644 --- a/src/libstrongswan/plugins/pkcs7/Makefile.am +++ b/src/libstrongswan/plugins/pkcs7/Makefile.am @@ -12,6 +12,7 @@ endif libstrongswan_pkcs7_la_SOURCES = \ pkcs7_generic.h pkcs7_generic.c \ pkcs7_signed_data.h pkcs7_signed_data.c \ + pkcs7_encrypted_data.h pkcs7_encrypted_data.c \ pkcs7_enveloped_data.h pkcs7_enveloped_data.c \ pkcs7_data.h pkcs7_data.c \ pkcs7_attributes.h pkcs7_attributes.c \ diff --git a/src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.c b/src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.c new file mode 100644 index 000000000..2c414c391 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.c @@ -0,0 +1,216 @@ +/* + * 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 "pkcs7_encrypted_data.h" + +#include +#include +#include +#include +#include + +typedef struct private_pkcs7_encrypted_data_t private_pkcs7_encrypted_data_t; + +/** + * Private data of a PKCS#7 signed-data container. + */ +struct private_pkcs7_encrypted_data_t { + + /** + * Implements pkcs7_t. + */ + pkcs7_t public; + + /** + * Decrypted content + */ + chunk_t content; + + /** + * Encrypted and encoded PKCS#7 encrypted-data + */ + chunk_t encoding; +}; + +/** + * Decrypt encrypted-data with available passwords + */ +static bool decrypt(pkcs5_t *pkcs5, chunk_t data, chunk_t *decrypted) +{ + enumerator_t *enumerator; + shared_key_t *shared; + bool success = FALSE; + + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_PRIVATE_KEY_PASS, NULL, NULL); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) + { + if (pkcs5->decrypt(pkcs5, shared->get_key(shared), data, decrypted)) + { + success = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return success; +} + +/** + * ASN.1 definition of the PKCS#7 encrypted-data type + */ +static const asn1Object_t encryptedDataObjects[] = { + { 0, "encryptedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 2 */ + { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 3 */ + { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 4 */ + { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 5 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_VERSION 1 +#define PKCS7_CONTENT_TYPE 3 +#define PKCS7_CONTENT_ENC_ALGORITHM 4 +#define PKCS7_ENCRYPTED_CONTENT 5 + +/** + * Parse and decrypt encrypted-data + */ +static bool parse(private_pkcs7_encrypted_data_t *this, chunk_t content) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID, version; + bool success = FALSE; + chunk_t encrypted = chunk_empty; + pkcs5_t *pkcs5 = NULL; + + parser = asn1_parser_create(encryptedDataObjects, content); + + while (parser->iterate(parser, &objectID, &object)) + { + int level = parser->get_level(parser); + + switch (objectID) + { + case PKCS7_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + if (version != 0) + { + DBG1(DBG_LIB, "encryptedData version is not 0"); + goto end; + } + break; + case PKCS7_CONTENT_TYPE: + if (asn1_known_oid(object) != OID_PKCS7_DATA) + { + DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); + goto end; + } + break; + case PKCS7_CONTENT_ENC_ALGORITHM: + pkcs5 = pkcs5_from_algorithmIdentifier(object, level + 1); + if (!pkcs5) + { + DBG1(DBG_LIB, "failed to detect PKCS#5 scheme"); + goto end; + } + break; + case PKCS7_ENCRYPTED_CONTENT: + encrypted = object; + break; + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + success = success && decrypt(pkcs5, encrypted, &this->content); + DESTROY_IF(pkcs5); + return success; +} + +METHOD(container_t, get_type, container_type_t, + private_pkcs7_encrypted_data_t *this) +{ + return CONTAINER_PKCS7_ENCRYPTED_DATA; +} + +METHOD(container_t, get_data, bool, + private_pkcs7_encrypted_data_t *this, chunk_t *data) +{ + if (this->content.len) + { + *data = chunk_clone(this->content); + return TRUE; + } + return FALSE; +} + +METHOD(container_t, get_encoding, bool, + private_pkcs7_encrypted_data_t *this, chunk_t *data) +{ + *data = chunk_clone(this->encoding); + return TRUE; +} + +METHOD(container_t, destroy, void, + private_pkcs7_encrypted_data_t *this) +{ + free(this->content.ptr); + free(this->encoding.ptr); + free(this); +} + +/** + * Generic constructor + */ +static private_pkcs7_encrypted_data_t* create_empty() +{ + private_pkcs7_encrypted_data_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 = (void*)enumerator_create_empty, + .get_attribute = (void*)return_false, + }, + ); + + return this; +} + +/** + * See header. + */ +pkcs7_t *pkcs7_encrypted_data_load(chunk_t encoding, chunk_t content) +{ + private_pkcs7_encrypted_data_t *this = create_empty(); + + this->encoding = chunk_clone(encoding); + if (!parse(this, content)) + { + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.h b/src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.h new file mode 100644 index 000000000..b685557fc --- /dev/null +++ b/src/libstrongswan/plugins/pkcs7/pkcs7_encrypted_data.h @@ -0,0 +1,36 @@ +/* + * 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 pkcs7_encrypted_data pkcs7_encrypted_data + * @{ @ingroup pkcs7p + */ + +#ifndef PKCS7_ENCRYPTED_DATA_H_ +#define PKCS7_ENCRYPTED_DATA_H_ + +#include +#include + +/** + * Parse a PKCS#7 encrypted-data container. + * + * @param encoding full contentInfo encoding + * @param content DER encoded content from contentInfo + * @return CONTAINER_PKCS7_ENCRYPTED_DATA container, NULL on failure + */ +pkcs7_t *pkcs7_encrypted_data_load(chunk_t encoding, chunk_t content); + +#endif /** PKCS7_ENCRYPTED_DATA_H_ @}*/ diff --git a/src/libstrongswan/plugins/pkcs7/pkcs7_generic.c b/src/libstrongswan/plugins/pkcs7/pkcs7_generic.c index 35d8d11a7..24d7cd848 100644 --- a/src/libstrongswan/plugins/pkcs7/pkcs7_generic.c +++ b/src/libstrongswan/plugins/pkcs7/pkcs7_generic.c @@ -20,6 +20,7 @@ #include "pkcs7_generic.h" #include "pkcs7_data.h" #include "pkcs7_signed_data.h" +#include "pkcs7_encrypted_data.h" #include "pkcs7_enveloped_data.h" #include @@ -85,6 +86,8 @@ end: return pkcs7_signed_data_load(blob, content); case OID_PKCS7_ENVELOPED_DATA: return pkcs7_enveloped_data_load(blob, content); + case OID_PKCS7_ENCRYPTED_DATA: + return pkcs7_encrypted_data_load(blob, content); default: DBG1(DBG_ASN, "pkcs7 content type %d not supported", type); return NULL;