diff options
Diffstat (limited to 'src/libstrongswan/crypto/pkcs9.c')
-rw-r--r-- | src/libstrongswan/crypto/pkcs9.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/src/libstrongswan/crypto/pkcs9.c b/src/libstrongswan/crypto/pkcs9.c new file mode 100644 index 000000000..1003c9011 --- /dev/null +++ b/src/libstrongswan/crypto/pkcs9.c @@ -0,0 +1,470 @@ +/** + * @file pkcs9.c + * + * @brief Implementation of pkcs9_t. + * + */ + +/* + * Copyright (C)2008 Andreas Steffen + * + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + * + * RCSID $Id: pkcs7.c 3423 2008-01-22 10:32:37Z andreas $ + */ + +#include <library.h> +#include <debug.h> + +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <utils/linked_list.h> + +#include "pkcs9.h" + +typedef struct private_pkcs9_t private_pkcs9_t; + +/** + * Private data of a pkcs9_t attribute list. + */ +struct private_pkcs9_t { + /** + * Public interface + */ + pkcs9_t public; + + /** + * DER encoding of PKCS#9 attributes + */ + chunk_t encoding; + + /** + * Linked list of PKCS#9 attributes + */ + linked_list_t *attributes; +}; + +typedef struct attribute_t attribute_t; + +/** + * Definition of an attribute_t object. + */ +struct attribute_t { + /** + * Object Identifier (OID) + */ + int oid; + + /** + * Attribute value + */ + chunk_t value; + + /** + * ASN.1 encoding + */ + chunk_t encoding; + + /** + * Destroys the attribute. + * + * @param this attribute to destroy + */ + void (*destroy) (attribute_t *this); + +}; + +/* ASN.1 definition of the X.501 atttribute type */ + +static const asn1Object_t attributesObjects[] = { + { 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */ + { 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */ + { 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */ +}; + +#define ATTRIBUTE_OBJ_TYPE 2 +#define ATTRIBUTE_OBJ_VALUE 4 +#define ATTRIBUTE_OBJ_ROOF 7 + +/** + * PKCS#9 attribute type OIDs + */ +static u_char ASN1_contentType_oid_str[] = { + 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03 +}; + +static u_char ASN1_messageDigest_oid_str[] = { + 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04 +}; + +static u_char ASN1_signingTime_oid_str[] = { + 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05 +}; + +static char ASN1_messageType_oid_str[] = { + 0x06, 0x0A, + 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02 +}; + +static char ASN1_senderNonce_oid_str[] = { + 0x06, 0x0A, + 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05 +}; + +static char ASN1_transId_oid_str[] = { + 0x06, 0x0A, + 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07 +}; + +static const chunk_t ASN1_contentType_oid = + chunk_from_buf(ASN1_contentType_oid_str); +static const chunk_t ASN1_messageDigest_oid = + chunk_from_buf(ASN1_messageDigest_oid_str); +static const chunk_t ASN1_signingTime_oid = + chunk_from_buf(ASN1_signingTime_oid_str); +static const chunk_t ASN1_messageType_oid = + chunk_from_buf(ASN1_messageType_oid_str); +static const chunk_t ASN1_senderNonce_oid = + chunk_from_buf(ASN1_senderNonce_oid_str); +static const chunk_t ASN1_transId_oid = + chunk_from_buf(ASN1_transId_oid_str); + +/** + * return the ASN.1 encoded OID of a PKCS#9 attribute + */ +static chunk_t asn1_attributeIdentifier(int oid) +{ + switch (oid) + { + case OID_PKCS9_CONTENT_TYPE: + return ASN1_contentType_oid; + case OID_PKCS9_MESSAGE_DIGEST: + return ASN1_messageDigest_oid; + case OID_PKCS9_SIGNING_TIME: + return ASN1_signingTime_oid; + case OID_PKI_MESSAGE_TYPE: + return ASN1_messageType_oid; + case OID_PKI_SENDER_NONCE: + return ASN1_senderNonce_oid; + case OID_PKI_TRANS_ID: + return ASN1_transId_oid;; + default: + return chunk_empty; + } +} + +/** + * return the ASN.1 encoding of a PKCS#9 attribute + */ +static asn1_t asn1_attributeType(int oid) +{ + asn1_t type; + + switch (oid) + { + case OID_PKCS9_CONTENT_TYPE: + type = ASN1_OID; + break; + case OID_PKCS9_SIGNING_TIME: + type = ASN1_UTCTIME; + break; + case OID_PKCS9_MESSAGE_DIGEST: + type = ASN1_OCTET_STRING; + break; + case OID_PKI_MESSAGE_TYPE: + type = ASN1_PRINTABLESTRING; + break; + case OID_PKI_STATUS: + type = ASN1_PRINTABLESTRING; + break; + case OID_PKI_FAIL_INFO: + type = ASN1_PRINTABLESTRING; + break; + case OID_PKI_SENDER_NONCE: + type = ASN1_OCTET_STRING; + break; + case OID_PKI_RECIPIENT_NONCE: + type = ASN1_OCTET_STRING; + break; + case OID_PKI_TRANS_ID: + type = ASN1_PRINTABLESTRING; + break; + default: + type = ASN1_EOC; + } + return type; +} + +/** + * Destroy an attribute_t object. + */ +static void attribute_destroy(attribute_t *this) +{ + free(this->value.ptr); + free(this->encoding.ptr); + free(this); +} + +/** + * Create an attribute_t object. + */ +static attribute_t *attribute_create(int oid, chunk_t value) +{ + attribute_t *this = malloc_thing(attribute_t); + + this->oid = oid; + this->value = chunk_clone(value); + this->encoding = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_attributeIdentifier(oid), + asn1_simple_object(ASN1_SET, value)); + this->destroy = (void (*) (attribute_t*))attribute_destroy; + return this; +} + +/** + * Implements pkcs9_t.build_encoding + */ +static void build_encoding(private_pkcs9_t *this) +{ + iterator_t *iterator; + attribute_t *attribute; + u_int attributes_len = 0; + + if (this->encoding.ptr) + { + chunk_free(&this->encoding); + } + if (this->attributes->get_count(this->attributes) == 0) + { + return; + } + + /* compute the total length of the encoded attributes */ + iterator = this->attributes->create_iterator(this->attributes, TRUE); + + while (iterator->iterate(iterator, (void**)&attribute)) + { + attributes_len += attribute->encoding.len; + } + iterator->destroy(iterator); + + /* allocate memory for the attributes and build the encoding */ + { + u_char *pos = build_asn1_object(&this->encoding, ASN1_SET, attributes_len); + + iterator = this->attributes->create_iterator(this->attributes, TRUE); + + while (iterator->iterate(iterator, (void**)&attribute)) + { + memcpy(pos, attribute->encoding.ptr, attribute->encoding.len); + pos += attribute->encoding.len; + } + iterator->destroy(iterator); + } +} + +/** + * Implements pkcs9_t.get_encoding + */ +static chunk_t get_encoding(private_pkcs9_t *this) +{ + if (this->encoding.ptr == NULL) + { + build_encoding(this); + } + return this->encoding; +} + +/** + * Implements pkcs9_t.get_attribute + */ +static chunk_t get_attribute(private_pkcs9_t *this, int oid) +{ + iterator_t *iterator = this->attributes->create_iterator(this->attributes, TRUE); + chunk_t value = chunk_empty; + attribute_t *attribute; + + while (iterator->iterate(iterator, (void**)&attribute)) + { + if (attribute->oid == oid) + { + value = attribute->value; + break; + } + } + iterator->destroy(iterator); + return value; +} + +/** + * Implements pkcs9_t.set_attribute + */ +static void set_attribute(private_pkcs9_t *this, int oid, chunk_t value) +{ + attribute_t *attribute = attribute_create(oid, value); + + this->attributes->insert_last(this->attributes, (void*)attribute); +} + +/** + * Implements pkcs9_t.get_messageDigest + */ +static chunk_t get_messageDigest(private_pkcs9_t *this) +{ + const int oid = OID_PKCS9_MESSAGE_DIGEST; + chunk_t value = get_attribute(this, oid); + + if (value.ptr == NULL) + { + return chunk_empty; + } + if (!parse_asn1_simple_object(&value, asn1_attributeType(oid), 0, oid_names[oid].name)) + { + return chunk_empty; + } + return chunk_clone(value); +} + +/** + * Implements pkcs9_t.set_attribute + */ +static void set_messageDigest(private_pkcs9_t *this, chunk_t value) +{ + const int oid = OID_PKCS9_MESSAGE_DIGEST; + chunk_t messageDigest = asn1_simple_object(asn1_attributeType(oid), value); + + set_attribute(this, oid, messageDigest); + free(messageDigest.ptr); +} + +/** + * Implements pkcs9_t.destroy + */ +static void destroy(private_pkcs9_t *this) +{ + this->attributes->destroy_offset(this->attributes, offsetof(attribute_t, destroy)); + free(this->encoding.ptr); + free(this); +} + +/** + * Generic private constructor + */ +static private_pkcs9_t *pkcs9_create_empty(void) +{ + private_pkcs9_t *this = malloc_thing(private_pkcs9_t); + + /* initialize */ + this->encoding = chunk_empty; + this->attributes = linked_list_create(); + + /*public functions */ + this->public.build_encoding = (void (*) (pkcs9_t*))build_encoding; + this->public.get_encoding = (chunk_t (*) (pkcs9_t*))get_encoding; + this->public.get_attribute = (chunk_t (*) (pkcs9_t*,int))get_attribute; + this->public.set_attribute = (void (*) (pkcs9_t*,int,chunk_t))set_attribute; + this->public.get_messageDigest = (chunk_t (*) (pkcs9_t*))get_messageDigest; + this->public.set_messageDigest = (void (*) (pkcs9_t*,chunk_t))set_messageDigest; + this->public.destroy = (void (*) (pkcs9_t*))destroy; + + return this; +} + +/* + * Described in header. + */ +pkcs9_t *pkcs9_create(void) +{ + private_pkcs9_t *this = pkcs9_create_empty(); + + return &this->public; +} + +/** + * Parse a PKCS#9 attribute list + */ +static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int oid = OID_UNKNOWN; + int objectID = 0; + + asn1_init(&ctx, chunk, level0, FALSE, FALSE); + + while (objectID < ATTRIBUTE_OBJ_ROOF) + { + if (!extract_object(attributesObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + + switch (objectID) + { + case ATTRIBUTE_OBJ_TYPE: + oid = known_oid(object); + break; + case ATTRIBUTE_OBJ_VALUE: + if (oid == OID_UNKNOWN) + { + break; + } + /* add the attribute to a linked list */ + { + attribute_t *attribute = attribute_create(oid, object); + + this->attributes->insert_last(this->attributes, (void*)attribute); + } + /* parse known attributes */ + { + asn1_t type = asn1_attributeType(oid); + + if (type != ASN1_EOC) + { + if (!parse_asn1_simple_object(&object, type, level+1, oid_names[oid].name)) + { + return FALSE; + } + } + } + } + objectID++; + } + return TRUE; +} + + + /* + * Described in header. + */ +pkcs9_t *pkcs9_create_from_chunk(chunk_t chunk, u_int level) +{ + private_pkcs9_t *this = pkcs9_create_empty(); + + this->encoding = chunk_clone(chunk); + + if (!parse_attributes(chunk, level, this)) + { + destroy(this); + return NULL; + } + return &this->public; +} |