summaryrefslogtreecommitdiff
path: root/src/libstrongswan/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/crypto')
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.c38
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.h21
-rw-r--r--src/libstrongswan/crypto/ocsp.c8
-rw-r--r--src/libstrongswan/crypto/ocsp.h5
-rw-r--r--src/libstrongswan/crypto/pkcs7.c449
-rw-r--r--src/libstrongswan/crypto/pkcs7.h85
-rw-r--r--src/libstrongswan/crypto/pkcs9.c470
-rw-r--r--src/libstrongswan/crypto/pkcs9.h121
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_private_key.c123
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_private_key.h6
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.c117
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.h40
-rwxr-xr-xsrc/libstrongswan/crypto/x509.c94
-rwxr-xr-xsrc/libstrongswan/crypto/x509.h10
14 files changed, 1392 insertions, 195 deletions
diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c
index 14bfb022f..9fa778aa6 100644
--- a/src/libstrongswan/crypto/hashers/hasher.c
+++ b/src/libstrongswan/crypto/hashers/hasher.c
@@ -6,8 +6,9 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
+ * Copyright (C) 2005-2006 Martin Willi
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +21,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: hasher.c 3304 2007-10-12 23:18:42Z andreas $
+ * RCSID $Id: hasher.c 3423 2008-01-22 10:32:37Z andreas $
*/
@@ -110,6 +111,39 @@ hash_algorithm_t hasher_algorithm_from_oid(int oid)
/*
* Described in header.
*/
+int hasher_algorithm_to_oid(hash_algorithm_t alg)
+{
+ int oid;
+
+ switch (alg)
+ {
+ case HASH_MD2:
+ oid = OID_MD2;
+ break;
+ case HASH_MD5:
+ oid = OID_MD5;
+ break;
+ case HASH_SHA1:
+ oid = OID_SHA1;
+ break;
+ case HASH_SHA256:
+ oid = OID_SHA256;
+ break;
+ case HASH_SHA384:
+ oid = OID_SHA384;
+ break;
+ case HASH_SHA512:
+ oid = OID_SHA512;
+ break;
+ default:
+ oid = OID_UNKNOWN;
+ }
+ return oid;
+}
+
+/*
+ * Described in header.
+ */
int hasher_signature_algorithm_to_oid(hash_algorithm_t alg)
{
int oid;
diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h
index 48b904576..e73de7f01 100644
--- a/src/libstrongswan/crypto/hashers/hasher.h
+++ b/src/libstrongswan/crypto/hashers/hasher.h
@@ -6,8 +6,9 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
+ * Copyright (C) 2005-2006 Martin Willi
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +21,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: hasher.h 3307 2007-10-17 02:56:24Z andreas $
+ * RCSID $Id: hasher.h 3423 2008-01-22 10:32:37Z andreas $
*/
#ifndef HASHER_H_
@@ -171,11 +172,23 @@ hasher_t *hasher_create(hash_algorithm_t hash_algorithm);
hash_algorithm_t hasher_algorithm_from_oid(int oid);
/**
- * @brief Conversion of hash signature algorithm ASN.1 OID.
+ * @brief Conversion of hash algorithm into ASN.1 OID.
+ *
+ * @param alg hash algorithm
+ * @return
+ * - ASN.1 hash OID if known hash algorithm
+ * - OID_UNKNOW
+ *
+ * @ingroup hashers
+ */
+int hasher_algorithm_to_oid(hash_algorithm_t alg);
+
+/**
+ * @brief Conversion of hash signature algorithm into ASN.1 OID.
*
* @param alg hash algorithm
* @return
- * - ASN.1 OID if known hash algorithm
+ * - ASN.1 signature OID if known hash algorithm
* - OID_UNKNOW
*
* @ingroup hashers
diff --git a/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c
index e4d907188..4bbec31de 100644
--- a/src/libstrongswan/crypto/ocsp.c
+++ b/src/libstrongswan/crypto/ocsp.c
@@ -6,8 +6,11 @@
*/
/* Support of the Online Certificate Status Protocol (OCSP)
+ *
* Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
- * Zuercher Hochschule Winterthur
+ * Copyright (C) 2007 Andreas Steffen
+ *
+ * Hochschule für Technik Rapperswil
*
* 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
@@ -19,6 +22,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
+ * RCSID $Id$
*/
#include <unistd.h>
@@ -325,7 +329,7 @@ static chunk_t build_request(private_ocsp_t *this, certinfo_t *certinfo)
chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm",
- ASN1_sha1_id,
+ asn1_algorithmIdentifier(OID_SHA1),
asn1_simple_object(ASN1_OCTET_STRING, this->authNameID),
asn1_simple_object(ASN1_OCTET_STRING, this->authKeyID),
asn1_simple_object(ASN1_INTEGER, serialNumber));
diff --git a/src/libstrongswan/crypto/ocsp.h b/src/libstrongswan/crypto/ocsp.h
index 42059e1c6..e468bb8be 100644
--- a/src/libstrongswan/crypto/ocsp.h
+++ b/src/libstrongswan/crypto/ocsp.h
@@ -6,9 +6,11 @@
*/
/* Support of the Online Certificate Status Protocol (OCSP) Support
+ *
* Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
* Copyright (C) 2007 Andreas Steffen
- * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * 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
@@ -20,6 +22,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
+ * RCSID $Id$
*/
#ifndef OCSP_H_
diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c
index 70510471a..48d3e2d78 100644
--- a/src/libstrongswan/crypto/pkcs7.c
+++ b/src/libstrongswan/crypto/pkcs7.c
@@ -7,7 +7,8 @@
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
- * Copyright (C) 2002-2005 Andreas Steffen
+ * Copyright (C) 2002-2008 Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil, Switzerland
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +21,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: pkcs7.c 3302 2007-10-12 21:57:20Z andreas $
+ * RCSID $Id: pkcs7.c 3438 2008-02-02 00:29:03Z andreas $
*/
#include <stdlib.h>
@@ -32,8 +33,11 @@
#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>
+#include <utils/randomizer.h>
#include <utils/linked_list.h>
#include "pkcs7.h"
@@ -77,7 +81,7 @@ struct private_pkcs7_t {
/**
* ASN.1 encoded attributes
*/
- chunk_t attributes;
+ pkcs9_t *attributes;
/**
* Linked list of X.509 certificates
@@ -244,25 +248,7 @@ 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_signedData.
+ * Implements pkcs7_t.is_data.
*/
static bool is_data(private_pkcs7_t *this)
{
@@ -278,7 +264,7 @@ static bool is_signedData(private_pkcs7_t *this)
}
/**
- * Implements pkcs7_t.is_signedData.
+ * Implements pkcs7_t.is_envelopedData.
*/
static bool is_envelopedData(private_pkcs7_t *this)
{
@@ -316,6 +302,11 @@ static bool parse_data(private_pkcs7_t *this)
{
return FALSE;
}
+ if (data.len == 0)
+ {
+ this->data = chunk_empty;
+ return TRUE;
+ }
if (parse_asn1_simple_object(&data, ASN1_OCTET_STRING, this->level, "data"))
{
this->data = chunk_clone(data);
@@ -328,7 +319,7 @@ static bool parse_data(private_pkcs7_t *this)
}
/**
- * Parse PKCS#7 signedData content
+ * Implements pkcs7_t.parse_signedData.
*/
static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
{
@@ -363,11 +354,27 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
digest_alg = parse_algorithmIdentifier(object, level, NULL);
break;
case PKCS7_SIGNED_CONTENT_INFO:
- this->data = chunk_clone(object);
+ {
+ chunk_t pureData;
+ pkcs7_t *data = pkcs7_create_from_chunk(object, level+1);
+
+ if (data == NULL)
+ {
+ return FALSE;
+ }
+ if (!data->parse_data(data))
+ {
+ data->destroy(data);
+ return FALSE;
+ }
+ pureData = data->get_data(data);
+ this->data = (pureData.len)? chunk_clone(pureData) : chunk_empty;
+ data->destroy(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)
{
@@ -389,8 +396,9 @@ 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);
+ *object.ptr = ASN1_CONTEXT_C_0;
break;
case PKCS7_DIGEST_ALGORITHM:
digest_alg = parse_algorithmIdentifier(object, level, NULL);
@@ -407,8 +415,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)
{
@@ -420,7 +428,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;
@@ -431,7 +439,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;
@@ -440,6 +448,39 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
{
DBG2("digest signature is valid");
}
+ if (this->data.ptr != NULL)
+ {
+ chunk_t messageDigest = this->attributes->get_messageDigest(this->attributes);
+
+ if (messageDigest.ptr == NULL)
+ {
+ DBG1("messageDigest attribute not found");
+ return FALSE;
+ }
+ else
+ {
+ hasher_t *hasher = hasher_create(algorithm);
+ chunk_t hash;
+ bool valid;
+
+ hasher->allocate_hash(hasher, this->data, &hash);
+ hasher->destroy(hasher);
+ DBG3("hash: %B", &hash);
+
+ valid = chunk_equals(messageDigest, hash);
+ free(messageDigest.ptr);
+ free(hash.ptr);
+ if (valid)
+ {
+ DBG2("messageDigest is valid");
+ }
+ else
+ {
+ DBG1("invalid messageDigest");
+ return FALSE;
+ }
+ }
+ }
}
return TRUE;
}
@@ -574,8 +615,9 @@ static bool parse_envelopedData(private_pkcs7_t *this, chunk_t serialNumber,
}
/* decrypt the content */
+ crypter->set_key(crypter, symmetric_key);
crypter->decrypt(crypter, encrypted_content, iv, &this->data);
- DBG4("decrypted content with padding: %B", &this->data);
+ DBG3("decrypted content with padding: %B", &this->data);
/* remove the padding */
{
@@ -611,7 +653,7 @@ failed:
}
/**
- * Implements pkcs7_t.get_data
+ * Implements pkcs7_t.get_data.
*/
static chunk_t get_data(private_pkcs7_t *this)
{
@@ -619,7 +661,49 @@ static chunk_t get_data(private_pkcs7_t *this)
}
/**
- * Implements pkcs_t.create_crluri_iterator
+ * Implements pkcs7_t.get_contentInfo.
+ */
+static chunk_t get_contentInfo(private_pkcs7_t *this)
+{
+ chunk_t content_type;
+
+ /* select DER-encoded OID for pkcs7_contentInfo type */
+ switch(this->type)
+ {
+ case OID_PKCS7_DATA:
+ content_type = ASN1_pkcs7_data_oid;
+ break;
+ case OID_PKCS7_SIGNED_DATA:
+ content_type = ASN1_pkcs7_signed_data_oid;
+ break;
+ case OID_PKCS7_ENVELOPED_DATA:
+ content_type = ASN1_pkcs7_enveloped_data_oid;
+ break;
+ case OID_PKCS7_SIGNED_ENVELOPED_DATA:
+ content_type = ASN1_pkcs7_signed_enveloped_data_oid;
+ break;
+ case OID_PKCS7_DIGESTED_DATA:
+ content_type = ASN1_pkcs7_digested_data_oid;
+ break;
+ case OID_PKCS7_ENCRYPTED_DATA:
+ content_type = ASN1_pkcs7_encrypted_data_oid;
+ break;
+ case OID_UNKNOWN:
+ default:
+ DBG1("invalid pkcs7 contentInfo type");
+ return chunk_empty;
+ }
+
+ return (this->content.ptr == NULL)
+ ? asn1_simple_object(ASN1_SEQUENCE, content_type)
+ : asn1_wrap(ASN1_SEQUENCE, "cm",
+ content_type,
+ asn1_simple_object(ASN1_CONTEXT_C_0, this->content)
+ );
+}
+
+/**
+ * Implements pkcs7_t.create_certificate_iterator
*/
static iterator_t *create_certificate_iterator(const private_pkcs7_t *this)
{
@@ -627,11 +711,243 @@ 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",
+ issuer->get_encoding(issuer),
+ asn1_simple_object(ASN1_INTEGER, cert->get_serialNumber(cert)));
+}
+
+/**
+ * Implements pkcs7_t.build_envelopedData.
+ */
+bool build_envelopedData(private_pkcs7_t *this, x509_t *cert,
+ encryption_algorithm_t alg)
+{
+ chunk_t iv, symmetricKey, in, out, alg_oid;
+ crypter_t *crypter;
+
+ /* select OID of symmetric encryption algorithm */
+ switch (alg)
+ {
+ case ENCR_DES:
+ alg_oid = ASN1_des_cbc_oid;
+ break;
+ case ENCR_3DES:
+ 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",
+ encryption_algorithm_names, alg);
+ return FALSE;
+ }
+
+ /* generate a true random symmetric encryption key
+ * and a pseudo-random iv
+ */
+ {
+ randomizer_t *randomizer = randomizer_create();
+
+ randomizer->allocate_random_bytes(randomizer,
+ crypter->get_key_size(crypter), &symmetricKey);
+ DBG4(" symmetric encryption key: %B", &symmetricKey);
+
+ randomizer->allocate_pseudo_random_bytes(randomizer,
+ crypter->get_block_size(crypter), &iv);
+ DBG4(" initialization vector: %B", &iv);
+
+ randomizer->destroy(randomizer);
+ }
+
+ /* pad the data so that the total length becomes
+ * a multiple of the block size
+ */
+ {
+ size_t block_size = crypter->get_block_size(crypter);
+ size_t padding = block_size - this->data.len % block_size;
+
+ in.len = this->data.len + padding;
+ in.ptr = malloc(in.len);
+
+ DBG2(" padding %d bytes of data to multiple block size of %d bytes",
+ (int)this->data.len, (int)in.len);
+
+ /* copy data */
+ memcpy(in.ptr, this->data.ptr, this->data.len);
+ /* append padding */
+ memset(in.ptr + this->data.len, padding, padding);
+ }
+ DBG3(" padded unencrypted data: %B", &in);
+
+ /* symmetric encryption of data object */
+ crypter->set_key(crypter, symmetricKey);
+ crypter->encrypt(crypter, in, iv, &out);
+ crypter->destroy(crypter);
+ chunk_free_randomized(&in);
+ DBG3(" encrypted data: %B", &out);
+
+ /* build pkcs7 enveloped data object */
+ {
+ chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "cm",
+ alg_oid,
+ asn1_wrap(ASN1_OCTET_STRING, "m", iv));
+
+ chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "cmm",
+ ASN1_pkcs7_data_oid,
+ contentEncryptionAlgorithm,
+ asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
+
+ chunk_t wrappedKey, encryptedKey, recipientInfo;
+
+ rsa_public_key_t *public_key = cert->get_public_key(cert);
+
+ public_key->pkcs1_encrypt(public_key, symmetricKey, &wrappedKey);
+ chunk_free_randomized(&symmetricKey);
+
+ encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m", wrappedKey);
+
+ recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm",
+ ASN1_INTEGER_0,
+ pkcs7_build_issuerAndSerialNumber(cert),
+ asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
+ encryptedKey);
+
+ this->content = asn1_wrap(ASN1_SEQUENCE, "cmm",
+ ASN1_INTEGER_0,
+ asn1_wrap(ASN1_SET, "m", recipientInfo),
+ encryptedContentInfo);
+ this->type = OID_PKCS7_ENVELOPED_DATA;
+ }
+ return TRUE;
+}
+
+/**
+ * Implements pkcs7_t.build_signedData.
+ */
+bool build_signedData(private_pkcs7_t *this, rsa_private_key_t *private_key,
+ hash_algorithm_t alg)
+{
+ 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)
+ {
+ if (this->data.ptr != NULL)
+ {
+ /* take the current time as signingTime */
+ time_t now = time(NULL);
+ chunk_t signingTime = timetoasn1(&now, ASN1_UTCTIME);
+
+ chunk_t messageDigest, attributes;
+ hasher_t *hasher = hasher_create(alg);
+
+ hasher->allocate_hash(hasher, this->data, &messageDigest);
+ hasher->destroy(hasher);
+ this->attributes->set_attribute(this->attributes,
+ OID_PKCS9_CONTENT_TYPE, ASN1_pkcs7_data_oid);
+ this->attributes->set_messageDigest(this->attributes,
+ messageDigest);
+ this->attributes->set_attribute(this->attributes,
+ OID_PKCS9_SIGNING_TIME, signingTime);
+ attributes = this->attributes->get_encoding(this->attributes);
+
+ free(messageDigest.ptr);
+ free(signingTime.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;
+}
+
+/**
* Implements pkcs7_t.destroy
*/
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);
}
@@ -665,19 +981,19 @@ static bool parse_contentInfo(chunk_t blob, u_int level0, private_pkcs7_t *cInfo
return FALSE;
}
}
- else if (objectID == PKCS7_INFO_CONTENT)
+ else if (objectID == PKCS7_INFO_CONTENT && object.len > 0)
{
- cInfo->content = object;
+ cInfo->content = chunk_clone(object);
}
objectID++;
}
return TRUE;
}
-/*
- * Described in header.
+/**
+ * Generic private constructor
*/
-pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
+static private_pkcs7_t *pkcs7_create_empty(void)
{
private_pkcs7_t *this = malloc_thing(private_pkcs7_t);
@@ -685,9 +1001,9 @@ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
this->type = OID_UNKNOWN;
this->content = chunk_empty;
this->parsed = FALSE;
- this->level = level + 2;
+ this->level = 0;
this->data = chunk_empty;
- this->attributes = chunk_empty;
+ this->attributes = NULL;
this->certs = linked_list_create();
/*public functions */
@@ -698,9 +1014,25 @@ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
this->public.parse_signedData = (bool (*) (pkcs7_t*,x509_t*))parse_signedData;
this->public.parse_envelopedData = (bool (*) (pkcs7_t*,chunk_t,rsa_private_key_t*))parse_envelopedData;
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;
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
+{
+ private_pkcs7_t *this = pkcs7_create_empty();
+
+ this->level = level + 2;
if (!parse_contentInfo(chunk, level, this))
{
destroy(this);
@@ -708,3 +1040,38 @@ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
}
return &this->public;
}
+
+/*
+ * Described in header.
+ */
+pkcs7_t *pkcs7_create_from_data(chunk_t data)
+{
+ private_pkcs7_t *this = pkcs7_create_empty();
+
+ this->data = chunk_clone(data);
+ 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 c8434225a..74bd25361 100644
--- a/src/libstrongswan/crypto/pkcs7.h
+++ b/src/libstrongswan/crypto/pkcs7.h
@@ -7,7 +7,7 @@
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
- * Copyright (C) 2002-2007 Andreas Steffen
+ * Copyright (C) 2002-2008 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil, Switzerland
*
@@ -21,7 +21,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: pkcs7.h 3302 2007-10-12 21:57:20Z andreas $
+ * RCSID $Id: pkcs7.h 3437 2008-02-01 22:26:01Z andreas $
*/
#ifndef _PKCS7_H
@@ -31,7 +31,9 @@ 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>
/**
@@ -39,6 +41,7 @@ typedef struct pkcs7_t pkcs7_t;
*
* @b Constructors:
* -pkcs7_create_from_chunk()
+ * -pkcs7_create_from_data()
*
* @ingroup crypto
*/
@@ -103,14 +106,66 @@ struct pkcs7_t {
chunk_t (*get_data) (pkcs7_t *this);
/**
+ * @brief Returns the a DER-encoded contentInfo object
+ *
+ * @param this calling object
+ * @return chunk containing the contentInfo object
+ */
+ chunk_t (*get_contentInfo) (pkcs7_t *this);
+
+ /**
* @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
+ * @param cert receivers's certificate
+ * @param alg encryption algorithm
+ * @return TRUE if build was successful
+ */
+ bool (*build_envelopedData) (pkcs7_t *this, x509_t *cert, encryption_algorithm_t alg);
+
+ /**
+ * @brief Build an signedData object
+ *
+ * @param this PKCS#7 data object to sign
+ * @param key signer's RSA private key
+ * @param alg digest algorithm used for signature
+ * @return TRUE if build was successful
+ */
+ bool (*build_signedData) (pkcs7_t *this, rsa_private_key_t *key, hash_algorithm_t alg);
+
+ /**
* @brief Destroys the contentInfo object.
*
* @param this PKCS#7 contentInfo object to destroy
@@ -129,4 +184,26 @@ struct pkcs7_t {
*/
pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level);
+/**
+ * @brief Create a PKCS#7 contentInfo object
+ *
+ * @param chunk chunk containing data
+ * @return created pkcs7_contentInfo object.
+ *
+ * @ingroup crypto
+ */
+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..1003c9011
--- /dev/null
+++ b/src/libstrongswan/crypto/pkcs9.c
@@ -0,0 +1,470 @@
+/**
+ * @file pkcs9.c
+ *
+ * @brief Implementation of pkcs9_t.
+ *
+ */
+
+/*
+ * Copyright (C)2008 Andreas Steffen
+ *
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pkcs7.c 3423 2008-01-22 10:32:37Z andreas $
+ */
+
+#include <library.h>
+#include <debug.h>
+
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <utils/linked_list.h>
+
+#include "pkcs9.h"
+
+typedef struct private_pkcs9_t private_pkcs9_t;
+
+/**
+ * Private data of a pkcs9_t attribute list.
+ */
+struct private_pkcs9_t {
+ /**
+ * Public interface
+ */
+ pkcs9_t public;
+
+ /**
+ * DER encoding of PKCS#9 attributes
+ */
+ chunk_t encoding;
+
+ /**
+ * Linked list of PKCS#9 attributes
+ */
+ linked_list_t *attributes;
+};
+
+typedef struct attribute_t attribute_t;
+
+/**
+ * Definition of an attribute_t object.
+ */
+struct attribute_t {
+ /**
+ * Object Identifier (OID)
+ */
+ int oid;
+
+ /**
+ * Attribute value
+ */
+ chunk_t value;
+
+ /**
+ * ASN.1 encoding
+ */
+ chunk_t encoding;
+
+ /**
+ * Destroys the attribute.
+ *
+ * @param this attribute to destroy
+ */
+ void (*destroy) (attribute_t *this);
+
+};
+
+/* ASN.1 definition of the X.501 atttribute type */
+
+static const asn1Object_t attributesObjects[] = {
+ { 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
+ { 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
+ { 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
+ { 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
+ { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
+};
+
+#define ATTRIBUTE_OBJ_TYPE 2
+#define ATTRIBUTE_OBJ_VALUE 4
+#define ATTRIBUTE_OBJ_ROOF 7
+
+/**
+ * PKCS#9 attribute type OIDs
+ */
+static u_char ASN1_contentType_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
+};
+
+static u_char ASN1_messageDigest_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
+};
+
+static u_char ASN1_signingTime_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05
+};
+
+static char ASN1_messageType_oid_str[] = {
+ 0x06, 0x0A,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02
+};
+
+static char ASN1_senderNonce_oid_str[] = {
+ 0x06, 0x0A,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05
+};
+
+static char ASN1_transId_oid_str[] = {
+ 0x06, 0x0A,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07
+};
+
+static const chunk_t ASN1_contentType_oid =
+ chunk_from_buf(ASN1_contentType_oid_str);
+static const chunk_t ASN1_messageDigest_oid =
+ chunk_from_buf(ASN1_messageDigest_oid_str);
+static const chunk_t ASN1_signingTime_oid =
+ chunk_from_buf(ASN1_signingTime_oid_str);
+static const chunk_t ASN1_messageType_oid =
+ chunk_from_buf(ASN1_messageType_oid_str);
+static const chunk_t ASN1_senderNonce_oid =
+ chunk_from_buf(ASN1_senderNonce_oid_str);
+static const chunk_t ASN1_transId_oid =
+ chunk_from_buf(ASN1_transId_oid_str);
+
+/**
+ * return the ASN.1 encoded OID of a PKCS#9 attribute
+ */
+static chunk_t asn1_attributeIdentifier(int oid)
+{
+ switch (oid)
+ {
+ case OID_PKCS9_CONTENT_TYPE:
+ return ASN1_contentType_oid;
+ case OID_PKCS9_MESSAGE_DIGEST:
+ return ASN1_messageDigest_oid;
+ case OID_PKCS9_SIGNING_TIME:
+ return ASN1_signingTime_oid;
+ case OID_PKI_MESSAGE_TYPE:
+ return ASN1_messageType_oid;
+ case OID_PKI_SENDER_NONCE:
+ return ASN1_senderNonce_oid;
+ case OID_PKI_TRANS_ID:
+ return ASN1_transId_oid;;
+ default:
+ return chunk_empty;
+ }
+}
+
+/**
+ * return the ASN.1 encoding of a PKCS#9 attribute
+ */
+static asn1_t asn1_attributeType(int oid)
+{
+ asn1_t type;
+
+ switch (oid)
+ {
+ case OID_PKCS9_CONTENT_TYPE:
+ type = ASN1_OID;
+ break;
+ case OID_PKCS9_SIGNING_TIME:
+ type = ASN1_UTCTIME;
+ break;
+ case OID_PKCS9_MESSAGE_DIGEST:
+ type = ASN1_OCTET_STRING;
+ break;
+ case OID_PKI_MESSAGE_TYPE:
+ type = ASN1_PRINTABLESTRING;
+ break;
+ case OID_PKI_STATUS:
+ type = ASN1_PRINTABLESTRING;
+ break;
+ case OID_PKI_FAIL_INFO:
+ type = ASN1_PRINTABLESTRING;
+ break;
+ case OID_PKI_SENDER_NONCE:
+ type = ASN1_OCTET_STRING;
+ break;
+ case OID_PKI_RECIPIENT_NONCE:
+ type = ASN1_OCTET_STRING;
+ break;
+ case OID_PKI_TRANS_ID:
+ type = ASN1_PRINTABLESTRING;
+ break;
+ default:
+ type = ASN1_EOC;
+ }
+ return type;
+}
+
+/**
+ * Destroy an attribute_t object.
+ */
+static void attribute_destroy(attribute_t *this)
+{
+ free(this->value.ptr);
+ free(this->encoding.ptr);
+ free(this);
+}
+
+/**
+ * Create an attribute_t object.
+ */
+static attribute_t *attribute_create(int oid, chunk_t value)
+{
+ attribute_t *this = malloc_thing(attribute_t);
+
+ this->oid = oid;
+ this->value = chunk_clone(value);
+ this->encoding = asn1_wrap(ASN1_SEQUENCE, "cm",
+ asn1_attributeIdentifier(oid),
+ asn1_simple_object(ASN1_SET, value));
+ this->destroy = (void (*) (attribute_t*))attribute_destroy;
+ return this;
+}
+
+/**
+ * Implements pkcs9_t.build_encoding
+ */
+static void build_encoding(private_pkcs9_t *this)
+{
+ iterator_t *iterator;
+ attribute_t *attribute;
+ u_int attributes_len = 0;
+
+ if (this->encoding.ptr)
+ {
+ chunk_free(&this->encoding);
+ }
+ if (this->attributes->get_count(this->attributes) == 0)
+ {
+ return;
+ }
+
+ /* compute the total length of the encoded attributes */
+ iterator = this->attributes->create_iterator(this->attributes, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&attribute))
+ {
+ attributes_len += attribute->encoding.len;
+ }
+ iterator->destroy(iterator);
+
+ /* allocate memory for the attributes and build the encoding */
+ {
+ u_char *pos = build_asn1_object(&this->encoding, ASN1_SET, attributes_len);
+
+ iterator = this->attributes->create_iterator(this->attributes, TRUE);
+
+ while (iterator->iterate(iterator, (void**)&attribute))
+ {
+ memcpy(pos, attribute->encoding.ptr, attribute->encoding.len);
+ pos += attribute->encoding.len;
+ }
+ iterator->destroy(iterator);
+ }
+}
+
+/**
+ * Implements pkcs9_t.get_encoding
+ */
+static chunk_t get_encoding(private_pkcs9_t *this)
+{
+ if (this->encoding.ptr == NULL)
+ {
+ build_encoding(this);
+ }
+ return this->encoding;
+}
+
+/**
+ * Implements pkcs9_t.get_attribute
+ */
+static chunk_t get_attribute(private_pkcs9_t *this, int oid)
+{
+ iterator_t *iterator = this->attributes->create_iterator(this->attributes, TRUE);
+ chunk_t value = chunk_empty;
+ attribute_t *attribute;
+
+ while (iterator->iterate(iterator, (void**)&attribute))
+ {
+ if (attribute->oid == oid)
+ {
+ value = attribute->value;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return value;
+}
+
+/**
+ * Implements pkcs9_t.set_attribute
+ */
+static void set_attribute(private_pkcs9_t *this, int oid, chunk_t value)
+{
+ attribute_t *attribute = attribute_create(oid, value);
+
+ this->attributes->insert_last(this->attributes, (void*)attribute);
+}
+
+/**
+ * Implements pkcs9_t.get_messageDigest
+ */
+static chunk_t get_messageDigest(private_pkcs9_t *this)
+{
+ const int oid = OID_PKCS9_MESSAGE_DIGEST;
+ chunk_t value = get_attribute(this, oid);
+
+ if (value.ptr == NULL)
+ {
+ return chunk_empty;
+ }
+ if (!parse_asn1_simple_object(&value, asn1_attributeType(oid), 0, oid_names[oid].name))
+ {
+ return chunk_empty;
+ }
+ return chunk_clone(value);
+}
+
+/**
+ * Implements pkcs9_t.set_attribute
+ */
+static void set_messageDigest(private_pkcs9_t *this, chunk_t value)
+{
+ const int oid = OID_PKCS9_MESSAGE_DIGEST;
+ chunk_t messageDigest = asn1_simple_object(asn1_attributeType(oid), value);
+
+ set_attribute(this, oid, messageDigest);
+ free(messageDigest.ptr);
+}
+
+/**
+ * Implements pkcs9_t.destroy
+ */
+static void destroy(private_pkcs9_t *this)
+{
+ this->attributes->destroy_offset(this->attributes, offsetof(attribute_t, destroy));
+ free(this->encoding.ptr);
+ free(this);
+}
+
+/**
+ * Generic private constructor
+ */
+static private_pkcs9_t *pkcs9_create_empty(void)
+{
+ private_pkcs9_t *this = malloc_thing(private_pkcs9_t);
+
+ /* initialize */
+ this->encoding = chunk_empty;
+ this->attributes = linked_list_create();
+
+ /*public functions */
+ this->public.build_encoding = (void (*) (pkcs9_t*))build_encoding;
+ this->public.get_encoding = (chunk_t (*) (pkcs9_t*))get_encoding;
+ this->public.get_attribute = (chunk_t (*) (pkcs9_t*,int))get_attribute;
+ this->public.set_attribute = (void (*) (pkcs9_t*,int,chunk_t))set_attribute;
+ this->public.get_messageDigest = (chunk_t (*) (pkcs9_t*))get_messageDigest;
+ this->public.set_messageDigest = (void (*) (pkcs9_t*,chunk_t))set_messageDigest;
+ this->public.destroy = (void (*) (pkcs9_t*))destroy;
+
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+pkcs9_t *pkcs9_create(void)
+{
+ private_pkcs9_t *this = pkcs9_create_empty();
+
+ return &this->public;
+}
+
+/**
+ * Parse a PKCS#9 attribute list
+ */
+static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int oid = OID_UNKNOWN;
+ int objectID = 0;
+
+ asn1_init(&ctx, chunk, level0, FALSE, FALSE);
+
+ while (objectID < ATTRIBUTE_OBJ_ROOF)
+ {
+ if (!extract_object(attributesObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+
+ switch (objectID)
+ {
+ case ATTRIBUTE_OBJ_TYPE:
+ oid = known_oid(object);
+ break;
+ case ATTRIBUTE_OBJ_VALUE:
+ if (oid == OID_UNKNOWN)
+ {
+ break;
+ }
+ /* add the attribute to a linked list */
+ {
+ attribute_t *attribute = attribute_create(oid, object);
+
+ this->attributes->insert_last(this->attributes, (void*)attribute);
+ }
+ /* parse known attributes */
+ {
+ asn1_t type = asn1_attributeType(oid);
+
+ if (type != ASN1_EOC)
+ {
+ if (!parse_asn1_simple_object(&object, type, level+1, oid_names[oid].name))
+ {
+ return FALSE;
+ }
+ }
+ }
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+
+ /*
+ * Described in header.
+ */
+pkcs9_t *pkcs9_create_from_chunk(chunk_t chunk, u_int level)
+{
+ private_pkcs9_t *this = pkcs9_create_empty();
+
+ this->encoding = chunk_clone(chunk);
+
+ if (!parse_attributes(chunk, level, this))
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
diff --git a/src/libstrongswan/crypto/pkcs9.h b/src/libstrongswan/crypto/pkcs9.h
new file mode 100644
index 000000000..44915720c
--- /dev/null
+++ b/src/libstrongswan/crypto/pkcs9.h
@@ -0,0 +1,121 @@
+/**
+ * @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 gets a PKCS#9 messageDigest attribute
+ *
+ * @param this calling object
+ * @return messageDigest
+ */
+ chunk_t (*get_messageDigest) (pkcs9_t *this);
+
+ /**
+ * @brief add a PKCS#9 messageDigest attribute
+ *
+ * @param this calling object
+ * @param value messageDigest
+ */
+ void (*set_messageDigest) (pkcs9_t *this, 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 */
diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.c b/src/libstrongswan/crypto/rsa/rsa_private_key.c
index ec2f2fc74..1b1499887 100644
--- a/src/libstrongswan/crypto/rsa/rsa_private_key.c
+++ b/src/libstrongswan/crypto/rsa/rsa_private_key.c
@@ -6,8 +6,10 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2007-2008 Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +22,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: rsa_private_key.c 3306 2007-10-17 02:55:53Z andreas $
+ * RCSID $Id: rsa_private_key.c 3429 2008-01-27 20:59:22Z andreas $
*/
#include <gmp.h>
@@ -40,6 +42,7 @@
* defined in rsa_public_key.c
*/
extern chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e);
+extern chunk_t rsa_public_key_id_create(const mpz_t n, const mpz_t e);
/**
* Public exponent to use for key generation.
@@ -111,7 +114,6 @@ struct private_rsa_private_key_t {
* Keyid formed as a SHA-1 hash of a publicKeyInfo object
*/
chunk_t keyid;
-
/**
* @brief Implements the RSADP algorithm specified in PKCS#1.
@@ -129,16 +131,6 @@ struct private_rsa_private_key_t {
* @return processed data
*/
chunk_t (*rsasp1) (private_rsa_private_key_t *this, chunk_t data);
-
- /**
- * @brief Generate a prime value.
- *
- * @param this calling object
- * @param prime_size size of the prime, in bytes
- * @param[out] prime uninitialized mpz
- */
- status_t (*compute_prime) (private_rsa_private_key_t *this, size_t prime_size, mpz_t *prime);
-
};
/* ASN.1 definition of a PKCS#1 RSA private key */
@@ -173,8 +165,6 @@ static const asn1Object_t privkey_objects[] = {
#define PRIV_KEY_COEFF 9
#define PRIV_KEY_ROOF 16
-static private_rsa_private_key_t *rsa_private_key_create_empty(void);
-
/**
* Auxiliary function overwriting private key material with
* pseudo-random bytes before releasing it
@@ -196,9 +186,9 @@ static void mpz_clear_randomized(mpz_t z)
}
/**
- * Implementation of private_rsa_private_key_t.compute_prime.
+ * Generate a random prime number with prime_len bytes
*/
-static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_size, mpz_t *prime)
+static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_len, mpz_t *prime)
{
randomizer_t *randomizer;
chunk_t random_bytes;
@@ -209,7 +199,8 @@ static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_size
do
{
- status = randomizer->allocate_random_bytes(randomizer, prime_size, &random_bytes);
+ DBG1(" generating %d bit prime from %s ...", BITS_PER_BYTE * prime_len, DEV_RANDOM);
+ status = randomizer->allocate_random_bytes(randomizer, prime_len, &random_bytes);
if (status != SUCCESS)
{
randomizer->destroy(randomizer);
@@ -230,7 +221,7 @@ static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_size
chunk_free_randomized(&random_bytes);
}
/* check if it isnt too large */
- while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size);
+ while (((mpz_sizeinbase(*prime, 2) + 7) / BITS_PER_BYTE) > prime_len);
randomizer->destroy(randomizer);
return SUCCESS;
@@ -269,7 +260,7 @@ static chunk_t rsadp(private_rsa_private_key_t *this, chunk_t data)
}
/**
- * Implementation of rsa_private_key_t.eme_pkcs1_decrypt.
+ * Implementation of rsa_private_key_t.pkcs1_decrypt.
*/
static status_t pkcs1_decrypt(private_rsa_private_key_t *this,
chunk_t in, chunk_t *out)
@@ -319,47 +310,14 @@ static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this,
chunk_t data, chunk_t *signature)
{
hasher_t *hasher;
- chunk_t em, digestInfo, hash_id, hash;
-
- /* get oid string prepended to hash */
- switch (hash_algorithm)
- {
- case HASH_MD2:
- {
- hash_id =ASN1_md2_id;
- break;
- }
- case HASH_MD5:
- {
- hash_id = ASN1_md5_id;
- break;
- }
- case HASH_SHA1:
- {
- hash_id = ASN1_sha1_id;
- break;
- }
- case HASH_SHA256:
- {
- hash_id = ASN1_sha256_id;
- break;
- }
- case HASH_SHA384:
- {
- hash_id = ASN1_sha384_id;
- break;
- }
- case HASH_SHA512:
- {
- hash_id = ASN1_sha512_id;
- break;
- }
- default:
- {
- return NOT_SUPPORTED;
- }
+ chunk_t em, digestInfo, hash;
+ int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
+
+ if (hash_oid == OID_UNKNOWN)
+ {
+ return NOT_SUPPORTED;
}
-
+
/* get hasher */
hasher = hasher_create(hash_algorithm);
if (hasher == NULL)
@@ -373,7 +331,7 @@ static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this,
/* build DER-encoded digestInfo */
digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
- hash_id,
+ asn1_algorithmIdentifier(hash_oid),
asn1_simple_object(ASN1_OCTET_STRING, hash)
);
chunk_free(&hash);
@@ -432,7 +390,7 @@ static bool pkcs1_write(private_rsa_private_key_t *this, const char *filename, b
*/
rsa_public_key_t *get_public_key(private_rsa_private_key_t *this)
{
- return NULL;
+ return rsa_public_key_create(this->n, this->e);
}
/**
@@ -455,13 +413,13 @@ static status_t check(private_rsa_private_key_t *this)
/* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
* We actually require more (for security).
*/
- if (this->k < 512/8)
+ if (this->k < 512 / BITS_PER_BYTE)
{
return FAILED;
}
/* we picked a max modulus size to simplify buffer allocation */
- if (this->k > 8192/8)
+ if (this->k > 8192 / BITS_PER_BYTE)
{
return FAILED;
}
@@ -572,7 +530,6 @@ static private_rsa_private_key_t *rsa_private_key_create_empty(void)
/* private functions */
this->rsadp = rsadp;
this->rsasp1 = rsadp; /* same algorithm */
- this->compute_prime = compute_prime;
this->keyid = chunk_empty;
@@ -587,20 +544,17 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
mpz_t p, q, n, e, d, exp1, exp2, coeff;
mpz_t m, q1, t;
private_rsa_private_key_t *this;
-
- this = rsa_private_key_create_empty();
- key_size = key_size / 8;
+ size_t key_len = key_size / BITS_PER_BYTE;
+ size_t prime_len = key_len / 2;
/* Get values of primes p and q */
- if (this->compute_prime(this, key_size/2, &p) != SUCCESS)
+ if (compute_prime(this, prime_len, &p) != SUCCESS)
{
- free(this);
return NULL;
}
- if (this->compute_prime(this, key_size/2, &q) != SUCCESS)
+ if (compute_prime(this, prime_len, &q) != SUCCESS)
{
mpz_clear(p);
- free(this);
return NULL;
}
@@ -648,7 +602,13 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
mpz_clear_randomized(m);
mpz_clear_randomized(t);
- /* apply values */
+ /* determine exact the modulus size in bits */
+ key_size = mpz_sizeinbase(n, 2);
+
+ /* create and fill in rsa_private_key_t object */
+ this = rsa_private_key_create_empty();
+ this->k = (key_size + 7) / BITS_PER_BYTE;
+ this->keyid = rsa_public_key_id_create(n, e);
*(this->p) = *p;
*(this->q) = *q;
*(this->n) = *n;
@@ -657,10 +617,8 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
*(this->exp1) = *exp1;
*(this->exp2) = *exp2;
*(this->coeff) = *coeff;
-
- /* set key size in bytes */
- this->k = key_size;
-
+ DBG1("generated %d bit RSA key with keyid: %#B", key_size, &this->keyid);
+
return &this->public;
}
@@ -733,17 +691,8 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
}
this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
+ this->keyid = rsa_public_key_id_create(this->n, this->e);
- /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
- {
- chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(this->n, this->e);
- hasher_t *hasher = hasher_create(HASH_SHA1);
-
- hasher->allocate_hash(hasher, publicKeyInfo, &this->keyid);
- hasher->destroy(hasher);
- free(publicKeyInfo.ptr);
- }
-
if (check(this) != SUCCESS)
{
destroy(this);
diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.h b/src/libstrongswan/crypto/rsa/rsa_private_key.h
index e5cf49810..8013f03c2 100644
--- a/src/libstrongswan/crypto/rsa/rsa_private_key.h
+++ b/src/libstrongswan/crypto/rsa/rsa_private_key.h
@@ -6,8 +6,10 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2007-2008 Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +22,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: rsa_private_key.h 3296 2007-10-12 15:23:29Z andreas $
+ * RCSID $Id: rsa_private_key.h 3423 2008-01-22 10:32:37Z andreas $
*/
#ifndef RSA_PRIVATE_KEY_H_
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c
index 6f2158d2b..10af0527e 100644
--- a/src/libstrongswan/crypto/rsa/rsa_public_key.c
+++ b/src/libstrongswan/crypto/rsa/rsa_public_key.c
@@ -6,8 +6,10 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2007-2008 Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +22,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: rsa_public_key.c 3303 2007-10-12 22:49:39Z andreas $
+ * RCSID $Id: rsa_public_key.c 3428 2008-01-27 20:58:52Z andreas $
*/
#include <gmp.h>
@@ -32,6 +34,7 @@
#include "rsa_public_key.h"
#include <debug.h>
+#include <utils/randomizer.h>
#include <crypto/hashers/hasher.h>
#include <asn1/asn1.h>
#include <asn1/pem.h>
@@ -110,8 +113,6 @@ struct private_rsa_public_key_t {
chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data);
};
-private_rsa_public_key_t *rsa_public_key_create_empty(void);
-
/**
* Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
*/
@@ -137,6 +138,55 @@ static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data)
}
/**
+ * Implementation of rsa_public_key_t.eme_pkcs1_encrypt.
+ */
+static status_t pkcs1_encrypt(private_rsa_public_key_t *this,
+ chunk_t in, chunk_t *out)
+{
+ chunk_t em;
+ u_char *pos;
+ int padding = this->k - in.len - 3;
+
+ if (padding < 8)
+ {
+ DBG1("rsa padding of %d bytes is too small", padding);
+ return FAILED;
+ }
+ em.len = this->k;
+ em.ptr = pos = malloc(em.len);
+
+ /* add padding according to PKCS#1 7.2.1 1.+2. */
+ *pos++ = 0x00;
+ *pos++ = 0x02;
+
+ /* pad with pseudo random bytes unequal to zero */
+ {
+ randomizer_t *randomizer = randomizer_create();
+
+ /* pad with pseudo random bytes unequal to zero */
+ while (padding--)
+ {
+ randomizer->get_pseudo_random_bytes(randomizer, 1, pos);
+ while (!*pos)
+ {
+ randomizer->get_pseudo_random_bytes(randomizer, 1, pos);
+ }
+ pos++;
+ }
+ randomizer->destroy(randomizer);
+ }
+
+ /* append the padding terminator */
+ *pos++ = 0x00;
+
+ /* now add the data */
+ memcpy(pos, in.ptr, in.len);
+ *out = this->rsaep(this, em);
+ free(em.ptr);
+ return SUCCESS;
+}
+
+/**
* Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
*/
static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this,
@@ -297,19 +347,30 @@ static size_t get_keysize(const private_rsa_public_key_t *this)
*/
chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e)
{
- chunk_t rawKey = asn1_wrap(ASN1_SEQUENCE, "mm",
+ chunk_t publicKey = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_integer_from_mpz(n),
asn1_integer_from_mpz(e));
- chunk_t publicKey;
- u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
+ return asn1_wrap(ASN1_SEQUENCE, "cm",
+ asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
+ asn1_bitstring("m", publicKey));
+}
- *pos++ = 0x00;
- memcpy(pos, rawKey.ptr, rawKey.len);
- free(rawKey.ptr);
+/**
+ * Form the RSA keyid as a SHA-1 hash of a publicKeyInfo object
+ * Also used in rsa_private_key.c.
+ */
+chunk_t rsa_public_key_id_create(mpz_t n, mpz_t e)
+{
+ chunk_t keyid;
+ chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(n, e);
+ hasher_t *hasher = hasher_create(HASH_SHA1);
+
+ hasher->allocate_hash(hasher, publicKeyInfo, &keyid);
+ hasher->destroy(hasher);
+ free(publicKeyInfo.ptr);
- return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id,
- publicKey);
+ return keyid;
}
/**
@@ -328,6 +389,9 @@ static chunk_t get_keyid(const private_rsa_public_key_t *this)
return this->keyid;
}
+/* forward declaration used by rsa_public_key_t.clone */
+private_rsa_public_key_t *rsa_public_key_create_empty(void);
+
/**
* Implementation of rsa_public_key_t.clone.
*/
@@ -362,6 +426,7 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void)
private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t);
/* public functions */
+ this->public.pkcs1_encrypt = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t*))pkcs1_encrypt;
this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,hash_algorithm_t,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus;
this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize;
@@ -380,6 +445,20 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void)
/*
* See header
*/
+rsa_public_key_t *rsa_public_key_create(mpz_t n, mpz_t e)
+{
+ private_rsa_public_key_t *this = rsa_public_key_create_empty();
+
+ mpz_init_set(this->n, n);
+ mpz_init_set(this->e, e);
+
+ this->k = (mpz_sizeinbase(n, 2) + 7) / BITS_PER_BYTE;
+ this->keyid = rsa_public_key_id_create(n, e);
+ return &this->public;
+}
+/*
+ * See header
+ */
rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
{
asn1_ctx_t ctx;
@@ -412,19 +491,9 @@ rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
}
objectID++;
}
-
- this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
-
- /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
- {
- chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(this->n, this->e);
- hasher_t *hasher = hasher_create(HASH_SHA1);
-
- hasher->allocate_hash(hasher, publicKeyInfo, &this->keyid);
- hasher->destroy(hasher);
- free(publicKeyInfo.ptr);
- }
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
+ this->keyid = rsa_public_key_id_create(this->n, this->e);
return &this->public;
}
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.h b/src/libstrongswan/crypto/rsa/rsa_public_key.h
index 0a40c2204..c0bd3e351 100644
--- a/src/libstrongswan/crypto/rsa/rsa_public_key.h
+++ b/src/libstrongswan/crypto/rsa/rsa_public_key.h
@@ -6,8 +6,10 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2007-2008 Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +22,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: rsa_public_key.h 3303 2007-10-12 22:49:39Z andreas $
+ * RCSID $Id: rsa_public_key.h 3423 2008-01-22 10:32:37Z andreas $
*/
#ifndef RSA_PUBLIC_KEY_H_
@@ -40,20 +42,29 @@ typedef struct rsa_public_key_t rsa_public_key_t;
* the EMSA encoding (see PKCS1)
*
* @b Constructors:
+ * - rsa_public_key_create()
* - rsa_public_key_create_from_chunk()
* - rsa_public_key_create_from_file()
- * - rsa_private_key_t.get_public_key()
- *
- * @see rsa_private_key_t
- *
- * @todo Implement getkey() and savekey()
- *
+ *
* @ingroup rsa
*/
struct rsa_public_key_t {
/**
- * @brief Verify a EMSA-PKCS1 encodined signature.
+ * @brief Encrypt a data block using EME-PKCS1 encoding.
+ *
+ *
+ * @param this calling object
+ * @param data plaintext input data
+ * @param out encrypted output data
+ * @return
+ * - SUCCESS
+ * - FAILED if data block is too large
+ */
+ status_t (*pkcs1_encrypt) (rsa_public_key_t *this, chunk_t in, chunk_t *out);
+
+ /**
+ * @brief Verify an EMSA-PKCS1 encoded signature.
*
* Processes the supplied signature with the RSAVP1 function,
* selects the hash algorithm form the resultign ASN1-OID and
@@ -123,6 +134,17 @@ struct rsa_public_key_t {
};
/**
+ * @brief Create a RSA public key from modulus and public exponent.
+ *
+ * @param n modulus
+ * @param e public exponent
+ * @return created rsa_public_key_t
+ *
+ * @ingroup rsa
+ */
+rsa_public_key_t *rsa_public_key_create(mpz_t n, mpz_t e);
+
+/**
* @brief Load an RSA public key from a chunk.
*
* Load a key from a chunk, encoded in the more frequently
diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c
index 6f154b36f..eadf11327 100755
--- a/src/libstrongswan/crypto/x509.c
+++ b/src/libstrongswan/crypto/x509.c
@@ -9,8 +9,8 @@
* Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
* Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
* Copyright (C) 2002 Mario Strasser
- * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- * Copyright (C) 2006 Martin Willi, Andreas Steffen
+ * Copyright (C) 2006 Martin Willi
+ * Copyright (C) 2000-2008 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil
*
@@ -24,7 +24,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: x509.c 3355 2007-11-20 12:06:40Z martin $
+ * RCSID $Id: x509.c 3423 2008-01-22 10:32:37Z andreas $
*/
#include <gmp.h>
@@ -514,7 +514,7 @@ static identification_t *parse_generalName(chunk_t blob, int level0)
id_type = ID_DER_ASN1_DN;
break;
case GN_OBJ_IP_ADDRESS:
- id_type = ID_IPV4_ADDR;
+ id_type = (object.len == 4)? ID_IPV4_ADDR : ID_IPV6_ADDR;
break;
case GN_OBJ_OTHER_NAME:
if (!parse_otherName(object, level + 1))
@@ -1243,6 +1243,22 @@ static void list(private_x509_t *this, FILE *out, bool utc)
}
}
+/**
+ * Implements x509_t.add_subjectAltNames.
+ */
+static void add_subjectAltNames(private_x509_t *this, linked_list_t *subjectAltNames)
+{
+ iterator_t *iterator = subjectAltNames->create_iterator(subjectAltNames, TRUE);
+ identification_t *name = NULL;
+
+ while (iterator->iterate(iterator, (void**)&name))
+ {
+ name = name->clone(name);
+ this->subjectAltNames->insert_last(this->subjectAltNames, (void*)name);
+ }
+ iterator->destroy(iterator);
+}
+
/*
* Defined in header.
*/
@@ -1251,12 +1267,13 @@ chunk_t x509_build_generalNames(linked_list_t *list)
linked_list_t *generalNames = linked_list_create();
iterator_t *iterator = list->create_iterator(list, TRUE);
identification_t *name;
+ chunk_t names = chunk_empty;
size_t len = 0;
while (iterator->iterate(iterator, (void**)&name))
{
asn1_t asn1_type = ASN1_EOC;
- chunk_t *generalName = malloc_thing(chunk_t);
+ chunk_t *generalName;
switch (name->get_type(name))
{
@@ -1273,22 +1290,24 @@ chunk_t x509_build_generalNames(linked_list_t *list)
asn1_type = ASN1_CONTEXT_S_6;
break;
case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
asn1_type = ASN1_CONTEXT_S_7;
break;
default:
continue;
}
+ generalName = malloc_thing(chunk_t);
*generalName = asn1_simple_object(asn1_type, name->get_encoding(name));
len += generalName->len;
- generalNames->insert_last(generalNames, generalName);
+ generalNames->insert_last(generalNames, (void*)generalName);
}
iterator->destroy(iterator);
if (len > 0)
{
iterator_t *iterator = generalNames->create_iterator(generalNames, TRUE);
- chunk_t names, *generalName;
+ chunk_t *generalName;
u_char *pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
while (iterator->iterate(iterator, (void**)&generalName))
@@ -1299,14 +1318,9 @@ chunk_t x509_build_generalNames(linked_list_t *list)
free(generalName);
}
iterator->destroy(iterator);
- generalNames->destroy(generalNames);
-
- return asn1_wrap(ASN1_OCTET_STRING, "m", names);
- }
- else
- {
- return chunk_empty;
}
+ generalNames->destroy(generalNames);
+ return names;
}
/*
@@ -1330,11 +1344,54 @@ chunk_t x509_build_subjectAltNames(linked_list_t *list)
}
/**
+ * Build a to-be-signed X.509 certificate body
+ */
+static chunk_t x509_build_tbs(private_x509_t *this)
+{
+ /* version is always X.509v3 */
+ chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
+
+ chunk_t extensions = chunk_empty;
+
+ if (this->subjectAltNames->get_count(this->subjectAltNames))
+ {
+ extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m",
+ asn1_wrap(ASN1_SEQUENCE, "m",
+ x509_build_subjectAltNames(this->subjectAltNames)));
+ }
+
+ return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
+ version,
+ asn1_simple_object(ASN1_INTEGER, this->serialNumber),
+ asn1_algorithmIdentifier(this->signatureAlgorithm),
+ this->issuer->get_encoding(this->issuer),
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ timetoasn1(&this->notBefore, ASN1_UTCTIME),
+ timetoasn1(&this->notAfter, ASN1_UTCTIME)
+ ),
+ this->subject->get_encoding(this->subject),
+ this->public_key->get_publicKeyInfo(this->public_key),
+ extensions
+ );
+}
+
+/**
* Implementation of x509_t.build_encoding.
*/
static void build_encoding(private_x509_t *this, hash_algorithm_t alg,
rsa_private_key_t *private_key)
{
+ chunk_t signature;
+
+ this->signatureAlgorithm = hasher_signature_algorithm_to_oid(alg);
+ this->tbsCertificate = x509_build_tbs(this);
+ private_key->build_emsa_pkcs1_signature(private_key, alg,
+ this->tbsCertificate, &signature);
+ this->signature = asn1_bitstring("m", signature);
+ this->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm",
+ this->tbsCertificate,
+ asn1_algorithmIdentifier(this->signatureAlgorithm),
+ this->signature);
}
@@ -1408,6 +1465,7 @@ static private_x509_t *x509_create_empty(void)
this->public.create_ocspuri_iterator = (iterator_t* (*) (const x509_t*))create_ocspuri_iterator;
this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify;
this->public.list = (void (*) (x509_t*, FILE *out, bool utc))list;
+ this->public.add_subjectAltNames = (void (*) (x509_t*,linked_list_t*))add_subjectAltNames;
this->public.build_encoding = (void (*) (x509_t*,hash_algorithm_t,rsa_private_key_t*))build_encoding;
this->public.destroy = (void (*) (x509_t*))destroy;
@@ -1417,13 +1475,19 @@ static private_x509_t *x509_create_empty(void)
/*
* Described in header.
*/
-x509_t *x509_create_(chunk_t serialNumber, identification_t *issuer, identification_t *subject)
+x509_t *x509_create(chunk_t serialNumber, identification_t *issuer,
+ time_t notBefore, time_t notAfter,
+ identification_t *subject,
+ rsa_public_key_t *public_key)
{
private_x509_t *this = x509_create_empty();
this->serialNumber = serialNumber;
this->issuer = issuer->clone(issuer);
+ this->notBefore = notBefore;
+ this->notAfter = notAfter;
this->subject = subject->clone(subject);
+ this->public_key = public_key->clone(public_key);
return &this->public;
}
diff --git a/src/libstrongswan/crypto/x509.h b/src/libstrongswan/crypto/x509.h
index 1ab267dac..def45be6b 100755
--- a/src/libstrongswan/crypto/x509.h
+++ b/src/libstrongswan/crypto/x509.h
@@ -9,8 +9,8 @@
* Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
* Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
* Copyright (C) 2002 Mario Strasser
- * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- * Copyright (C) 2006 Martin Willi, Andreas Steffen
+ * Copyright (C) 2006 Martin Willi
+ * Copyright (C) 2000-2008 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil
*
@@ -24,7 +24,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
- * RCSID $Id: x509.h 3301 2007-10-12 21:56:30Z andreas $
+ * RCSID $Id: x509.h 3421 2008-01-22 01:09:19Z andreas $
*/
#ifndef X509_H_
@@ -327,6 +327,7 @@ struct x509_t {
* @param notBefore start date of validity
* @param notAfter end date of validity
* @param subject subject distinguished name
+ * @param public_key public key
*
* @return created x509_t certificate, or NULL if invalid.
*
@@ -334,7 +335,8 @@ struct x509_t {
*/
x509_t *x509_create(chunk_t serialNumber, identification_t *issuer,
time_t notBefore, time_t notAfter,
- identification_t *subject);
+ identification_t *subject,
+ rsa_public_key_t *public_key);
/**
* @brief Read a X.509 certificate from a DER encoded blob.