diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs7.c | 195 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs7.h | 49 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs9.c | 424 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs9.h | 105 |
5 files changed, 714 insertions, 60 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index e8859ad4c..fc642c615 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -35,6 +35,7 @@ crypto/hmac.c crypto/hmac.h \ crypto/ietf_attr_list.c crypto/ietf_attr_list.h \ crypto/ocsp.c crypto/ocsp.h \ crypto/pkcs7.c crypto/pkcs7.h \ +crypto/pkcs9.c crypto/pkcs9.h \ crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \ crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \ crypto/prfs/prf.c crypto/prfs/prf.h \ diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c index 820cbd543..e6e26791c 100644 --- a/src/libstrongswan/crypto/pkcs7.c +++ b/src/libstrongswan/crypto/pkcs7.c @@ -32,6 +32,7 @@ #include <asn1/asn1.h> #include <asn1/oid.h> #include <crypto/x509.h> +#include <crypto/pkcs9.h> #include <crypto/hashers/hasher.h> #include <crypto/crypters/crypter.h> #include <crypto/rsa/rsa_public_key.h> @@ -79,7 +80,7 @@ struct private_pkcs7_t { /** * ASN.1 encoded attributes */ - chunk_t attributes; + pkcs9_t *attributes; /** * Linked list of X.509 certificates @@ -214,7 +215,7 @@ static char ASN1_pkcs7_encrypted_data_oid_str[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 }; -static const chunk_t ASN1_pkcs7_data_oid = +const chunk_t ASN1_pkcs7_data_oid = chunk_from_buf(ASN1_pkcs7_data_oid_str); static const chunk_t ASN1_pkcs7_signed_data_oid = chunk_from_buf(ASN1_pkcs7_signed_data_oid_str); @@ -246,24 +247,6 @@ static const chunk_t ASN1_des_cbc_oid = chunk_from_buf(ASN1_des_cbc_oid_str); /** - * PKCS#7 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 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); - -/** * Implements pkcs7_t.is_data. */ static bool is_data(private_pkcs7_t *this) @@ -369,7 +352,7 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert) break; case PKCS7_SIGNED_CERT: { - x509_t *cert = x509_create_from_chunk(object, level+1); + x509_t *cert = x509_create_from_chunk(chunk_clone(object), level+1); if (cert) { @@ -391,8 +374,8 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert) } break; case PKCS7_AUTH_ATTRIBUTES: - this->attributes = object; - *this->attributes.ptr = ASN1_SET; + *object.ptr = ASN1_SET; + this->attributes = pkcs9_create_from_chunk(object, level+1); break; case PKCS7_DIGEST_ALGORITHM: digest_alg = parse_algorithmIdentifier(object, level, NULL); @@ -409,8 +392,8 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert) /* check the signature only if a cacert is available */ if (cacert != NULL) { - rsa_public_key_t *signer = cacert->get_public_key(cacert); hash_algorithm_t algorithm = hasher_algorithm_from_oid(digest_alg); + rsa_public_key_t *signer = cacert->get_public_key(cacert); if (signerInfos == 0) { @@ -422,7 +405,7 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert) DBG1("more than one signerInfo object found"); return FALSE; } - if (this->attributes.ptr == NULL) + if (this->attributes == NULL) { DBG1("no authenticatedAttributes object found"); return FALSE; @@ -433,7 +416,7 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert) return FALSE; } if (signer->verify_emsa_pkcs1_signature(signer, algorithm, - this->attributes, encrypted_digest) != SUCCESS) + this->attributes->get_encoding(this->attributes), encrypted_digest) != SUCCESS) { DBG1("invalid digest signature"); return FALSE; @@ -657,7 +640,7 @@ static chunk_t get_contentInfo(private_pkcs7_t *this) return (this->content.ptr == NULL) ? asn1_simple_object(ASN1_SEQUENCE, content_type) - : asn1_wrap(ASN1_SEQUENCE, "cc", + : asn1_wrap(ASN1_SEQUENCE, "cm", content_type, asn1_simple_object(ASN1_CONTEXT_C_0, this->content) ); @@ -672,12 +655,34 @@ static iterator_t *create_certificate_iterator(const private_pkcs7_t *this) } /** + * Implements pkcs7_t.set_certificate + */ +static void set_certificate(private_pkcs7_t *this, x509_t *cert) +{ + if (cert) + { + /* TODO the certificate is currently not cloned */ + this->certs->insert_last(this->certs, cert); + } +} + +/** + * Implements pkcs7_t.set_attributes + */ +static void set_attributes(private_pkcs7_t *this, pkcs9_t *attributes) +{ + this->attributes = attributes; +} + +/** * build a DER-encoded issuerAndSerialNumber object */ chunk_t pkcs7_build_issuerAndSerialNumber(x509_t *cert) { + identification_t *issuer = cert->get_issuer(cert); + return asn1_wrap(ASN1_SEQUENCE, "cm", - cert->get_issuer(cert), + issuer->get_encoding(issuer), asn1_simple_object(ASN1_INTEGER, cert->get_serialNumber(cert))); } @@ -687,7 +692,7 @@ chunk_t pkcs7_build_issuerAndSerialNumber(x509_t *cert) bool build_envelopedData(private_pkcs7_t *this, x509_t *cert, encryption_algorithm_t alg) { - chunk_t iv, symmetricKey, out, alg_oid; + chunk_t iv, symmetricKey, in, out, alg_oid; crypter_t *crypter; /* select OID of symmetric encryption algorithm */ @@ -700,13 +705,15 @@ bool build_envelopedData(private_pkcs7_t *this, x509_t *cert, alg_oid = ASN1_3des_ede_cbc_oid; break; default: + DBG1(" encryption algorithm %N not supported", + encryption_algorithm_names, alg); return FALSE; } crypter = crypter_create(alg, 0); if (crypter == NULL) { - DBG1("could not create crypter for algorithm %N", + DBG1(" could not create crypter for algorithm %N", encryption_algorithm_names, alg); return FALSE; } @@ -719,11 +726,11 @@ bool build_envelopedData(private_pkcs7_t *this, x509_t *cert, randomizer->allocate_random_bytes(randomizer, crypter->get_key_size(crypter), &symmetricKey); - DBG4("symmetric encryption key: %B", &symmetricKey); + DBG4(" symmetric encryption key: %B", &symmetricKey); randomizer->allocate_pseudo_random_bytes(randomizer, crypter->get_block_size(crypter), &iv); - DBG4("initialization vector: %B", &iv); + DBG4(" initialization vector: %B", &iv); randomizer->destroy(randomizer); } @@ -733,31 +740,27 @@ bool build_envelopedData(private_pkcs7_t *this, x509_t *cert, */ { size_t block_size = crypter->get_block_size(crypter); - size_t padding = this->data.len % block_size; + size_t padding = block_size - this->data.len % block_size; - if (padding == 0) - { - padding += block_size; - } + in.len = this->data.len + padding; + in.ptr = malloc(in.len); - out.len = this->data.len + padding; - out.ptr = malloc(out.len); - - DBG2("padding %d bytes of data to multiple block size of %d bytes", - (int)this->data.len, (int)out.len); + DBG2(" padding %d bytes of data to multiple block size of %d bytes", + (int)this->data.len, (int)in.len); /* copy data */ - memcpy(out.ptr, this->data.ptr, this->data.len); + memcpy(in.ptr, this->data.ptr, this->data.len); /* append padding */ - memset(out.ptr + this->data.len, padding, padding); + memset(in.ptr + this->data.len, padding, padding); } - DBG3("padded unencrypted data: %B", &out); + DBG3(" padded unencrypted data: %B", &in); /* symmetric encryption of data object */ crypter->set_key(crypter, symmetricKey); - crypter->encrypt(crypter, this->data, iv, &out); + crypter->encrypt(crypter, in, iv, &out); crypter->destroy(crypter); - DBG3("encrypted data: %B", &out); + chunk_free_randomized(&in); + DBG3(" encrypted data: %B", &out); /* build pkcs7 enveloped data object */ { @@ -797,10 +800,70 @@ bool build_envelopedData(private_pkcs7_t *this, x509_t *cert, /** * Implements pkcs7_t.build_signedData. */ -bool build_signedData(private_pkcs7_t *this, rsa_private_key_t *key, +bool build_signedData(private_pkcs7_t *this, rsa_private_key_t *private_key, hash_algorithm_t alg) { - return FALSE; + int signature_oid = hasher_signature_algorithm_to_oid(alg); + chunk_t authenticatedAttributes = chunk_empty; + chunk_t encryptedDigest = chunk_empty; + chunk_t signerInfo; + x509_t *cert; + + if (this->certs->get_first(this->certs, (void**)&cert) != SUCCESS) + { + DBG1(" no pkcs7 signer certificate found"); + return FALSE; + } + + if (this->attributes != NULL) + { + chunk_t attributes = this->attributes->get_encoding(this->attributes); + + if (attributes.ptr) + { + private_key->build_emsa_pkcs1_signature(private_key, alg, + attributes, &encryptedDigest); + authenticatedAttributes = chunk_clone(attributes); + *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; + } + } + else if (this->data.ptr != NULL) + { + private_key->build_emsa_pkcs1_signature(private_key, alg, + this->data, &encryptedDigest); + } + if (encryptedDigest.ptr) + { + encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", encryptedDigest); + } + + signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmcmcm", + ASN1_INTEGER_1, + pkcs7_build_issuerAndSerialNumber(cert), + asn1_algorithmIdentifier(signature_oid), + authenticatedAttributes, + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + encryptedDigest); + + if (this->data.ptr != NULL) + { + this->content = asn1_simple_object(ASN1_OCTET_STRING, this->data); + chunk_free(&this->data); + } + this->type = OID_PKCS7_DATA; + this->data = get_contentInfo(this); + chunk_free(&this->content); + + this->type = OID_PKCS7_SIGNED_DATA; + + this->content = asn1_wrap(ASN1_SEQUENCE, "cmcmm", + ASN1_INTEGER_1, + asn1_simple_object(ASN1_SET, asn1_algorithmIdentifier(signature_oid)), + this->data, + asn1_simple_object(ASN1_CONTEXT_C_0, cert->get_certificate(cert)), + asn1_wrap(ASN1_SET, "m", signerInfo)); + + return TRUE; } /** @@ -808,7 +871,9 @@ bool build_signedData(private_pkcs7_t *this, rsa_private_key_t *key, */ static void destroy(private_pkcs7_t *this) { + DESTROY_IF(this->attributes); this->certs->destroy_offset(this->certs, offsetof(x509_t, destroy)); + free(this->content.ptr); free(this->data.ptr); free(this); } @@ -844,7 +909,7 @@ static bool parse_contentInfo(chunk_t blob, u_int level0, private_pkcs7_t *cInfo } else if (objectID == PKCS7_INFO_CONTENT) { - cInfo->content = object; + cInfo->content = chunk_clone(object); } objectID++; } @@ -864,7 +929,7 @@ static private_pkcs7_t *pkcs7_create_empty(void) this->parsed = FALSE; this->level = 0; this->data = chunk_empty; - this->attributes = chunk_empty; + this->attributes = NULL; this->certs = linked_list_create(); /*public functions */ @@ -877,6 +942,8 @@ static private_pkcs7_t *pkcs7_create_empty(void) this->public.get_data = (chunk_t (*) (pkcs7_t*))get_data; this->public.get_contentInfo = (chunk_t (*) (pkcs7_t*))get_contentInfo; this->public.create_certificate_iterator = (iterator_t* (*) (pkcs7_t*))create_certificate_iterator; + this->public.set_certificate = (void (*) (pkcs7_t*,x509_t*))set_certificate; + this->public.set_attributes = (void (*) (pkcs7_t*,pkcs9_t*))set_attributes; this->public.build_envelopedData = (bool (*) (pkcs7_t*,x509_t*,encryption_algorithm_t))build_envelopedData; this->public.build_signedData = (bool (*) (pkcs7_t*,rsa_private_key_t*,hash_algorithm_t))build_signedData; this->public.destroy = (void (*) (pkcs7_t*))destroy; @@ -903,14 +970,34 @@ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level) /* * Described in header. */ -pkcs7_t *pkcs7_create_from_data(chunk_t data, chunk_t attributes, x509_t *cert) +pkcs7_t *pkcs7_create_from_data(chunk_t data) { private_pkcs7_t *this = pkcs7_create_empty(); this->data = chunk_clone(data); - this->attributes = attributes; - this->certs->insert_last(this->certs, cert); this->parsed = TRUE; return &this->public; } + +/* + * Described in header. + */ +pkcs7_t *pkcs7_create_from_file(const char *filename, const char *label) +{ + bool pgp = FALSE; + chunk_t chunk = chunk_empty; + char cert_label[BUF_LEN]; + pkcs7_t *pkcs7; + + snprintf(cert_label, BUF_LEN, "%s pkcs7", label); + + if (!pem_asn1_load_file(filename, NULL, cert_label, &chunk, &pgp)) + { + return NULL; + } + + pkcs7 = pkcs7_create_from_chunk(chunk, 0); + free(chunk.ptr); + return pkcs7; +} diff --git a/src/libstrongswan/crypto/pkcs7.h b/src/libstrongswan/crypto/pkcs7.h index 8e5166d5c..05ddd3a89 100644 --- a/src/libstrongswan/crypto/pkcs7.h +++ b/src/libstrongswan/crypto/pkcs7.h @@ -31,16 +31,19 @@ typedef struct pkcs7_t pkcs7_t; #include <library.h> #include <crypto/x509.h> +#include <crypto/pkcs9.h> #include <crypto/rsa/rsa_private_key.h> #include <crypto/crypters/crypter.h> #include <utils/iterator.h> +extern const chunk_t ASN1_pkcs7_data_oid; + /** * @brief PKCS#7 contentInfo object. * * @b Constructors: * -pkcs7_create_from_chunk() - * -pkcs7_create() + * -pkcs7_create_from_data() * * @ingroup crypto */ @@ -115,12 +118,36 @@ struct pkcs7_t { /** * @brief Create an iterator for the certificates. * - * @param this calling object - * @return iterator for the certificates + * @param this calling object + * @return iterator for the certificates */ iterator_t *(*create_certificate_iterator) (pkcs7_t *this); /** + * @brief Add a certificate. + * + * @param this calling object + * @param cert certificate to be included + */ + void (*set_certificate) (pkcs7_t *this, x509_t *cert); + + /** + * @brief Add authenticated attributes. + * + * @param this calling object + * @param attributes attributes to be included + */ + void (*set_attributes) (pkcs7_t *this, pkcs9_t *attributes); + + /** + * @brief Build a data object + * + * @param this PKCS#7 data to be built + * @return TRUE if build was successful + */ + bool (*build_data) (pkcs7_t *this); + + /** * @brief Build an envelopedData object * * @param this PKCS#7 data object to envelop @@ -163,12 +190,22 @@ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level); * @brief Create a PKCS#7 contentInfo object * * @param chunk chunk containing data - * @param attributes chunk containing attributes - * @param cert certificate to be included in the pkcs7_contentInfo object * @return created pkcs7_contentInfo object. * * @ingroup crypto */ -pkcs7_t *pkcs7_create_from_data(chunk_t data, chunk_t attributes, x509_t *cert); +pkcs7_t *pkcs7_create_from_data(chunk_t data); + +/** + * @brief Read a X.509 certificate from a DER encoded file. + * + * @param filename file containing DER encoded data + * @param label label describing kind of PKCS#7 file + * @return created pkcs7_t object, or NULL if invalid. + * + * @ingroup crypto + */ +pkcs7_t *pkcs7_create_from_file(const char *filename, const char *label); + #endif /* _PKCS7_H */ diff --git a/src/libstrongswan/crypto/pkcs9.c b/src/libstrongswan/crypto/pkcs9.c new file mode 100644 index 000000000..d7aecf329 --- /dev/null +++ b/src/libstrongswan/crypto/pkcs9.c @@ -0,0 +1,424 @@ +/** + * @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) +{ + return chunk_empty; +} + +/** + * 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.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.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; +} diff --git a/src/libstrongswan/crypto/pkcs9.h b/src/libstrongswan/crypto/pkcs9.h new file mode 100644 index 000000000..8dbdb7c45 --- /dev/null +++ b/src/libstrongswan/crypto/pkcs9.h @@ -0,0 +1,105 @@ +/** + * @file pkcs7.h + * + * @brief Interface 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.h 3423 2008-01-22 10:32:37Z andreas $ + */ + +#ifndef _PKCS9_H +#define _PKCS9_H + +typedef struct pkcs9_t pkcs9_t; + +#include <library.h> + +/** + * @brief PKCS#9 . + * + * @b Constructors: + * -pkcs9_create_from_chunk() + * -pkcs9_create() + * + * @ingroup crypto + */ +struct pkcs9_t { + /** + * @brief generate ASN.1 encoding of attribute list + * + * @param this PKCS#9 attribute list to be encoded + */ + void (*build_encoding) (pkcs9_t *this); + + /** + * @brief gets ASN.1 encoding of PKCS#9 attribute list + * + * @param this calling object + * @return ASN.1 encoded PKCSI#9 list + */ + chunk_t (*get_encoding) (pkcs9_t *this); + + /** + * @brief gets a PKCS#9 attribute + * + * @param this calling object + * @param oid OID of the attribute + * @return ASN.1 encoded value of the attribute + */ + chunk_t (*get_attribute) (pkcs9_t *this, int oid); + + /** + * @brief adds a PKCS#9 attribute + * + * @param this calling object + * @param oid OID of the attribute + * @param value ASN.1 encoded value of the attribute + */ + void (*set_attribute) (pkcs9_t *this, int oid, chunk_t value); + + /** + * @brief Destroys the PKCS#9 attribute list. + * + * @param this PKCS#9 attribute list to destroy + */ + void (*destroy) (pkcs9_t *this); +}; + +/** + * @brief Read a PKCS#9 attribute list from a DER encoded chunk. + * + * @param chunk chunk containing DER encoded data + * @param level ASN.1 parsing start level + * @return created pkcs9 attribute list, or NULL if invalid. + * + * @ingroup crypto + */ +pkcs9_t *pkcs9_create_from_chunk(chunk_t chunk, u_int level); + +/** + * @brief Create an empty PKCS#9 attribute list + * + * @param chunk chunk containing data + * @return created pkcs9 attribute list. + * + * @ingroup crypto + */ +pkcs9_t *pkcs9_create(void); + +#endif /* _PKCS9_H */ |