extended and debugged PKCS#7 signedData support

This commit is contained in:
Andreas Steffen
2008-02-01 14:19:26 +00:00
parent daccbee77e
commit e8bfe74289
5 changed files with 714 additions and 60 deletions
+1
View File
@@ -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 \
+141 -54
View File
@@ -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);
@@ -245,24 +246,6 @@ static const chunk_t ASN1_3des_ede_cbc_oid =
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.
*/
@@ -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)
);
@@ -671,13 +654,35 @@ static iterator_t *create_certificate_iterator(const private_pkcs7_t *this)
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)));
}
@@ -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;
}
+43 -6
View File
@@ -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,11 +118,35 @@ 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
*
@@ -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 */
+424
View File
@@ -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;
}
+105
View File
@@ -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 */