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 \
#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>
/**
* ASN.1 encoded attributes
*/
- chunk_t attributes;
+ pkcs9_t *attributes;
/**
* Linked list of X.509 certificates
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);
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.
*/
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)
{
}
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);
/* 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)
{
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;
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;
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)
);
return this->certs->create_iterator(this->certs, TRUE);
}
+/**
+ * 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)));
}
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 */
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;
}
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);
}
*/
{
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 */
{
/**
* 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;
}
/**
*/
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);
}
}
else if (objectID == PKCS7_INFO_CONTENT)
{
- cInfo->content = object;
+ cInfo->content = chunk_clone(object);
}
objectID++;
}
this->parsed = FALSE;
this->level = 0;
this->data = chunk_empty;
- this->attributes = chunk_empty;
+ this->attributes = NULL;
this->certs = linked_list_create();
/*public functions */
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;
/*
* 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;
+}
#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
*/
/**
* @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
*
* @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 */
--- /dev/null
+/**
+ * @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;
+}
--- /dev/null
+/**
+ * @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 */