extended and debugged PKCS#7 signedData support
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user