summaryrefslogtreecommitdiff
path: root/src/libstrongswan/crypto
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2007-10-26 14:10:02 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2007-10-26 14:10:02 +0000
commit49104abddf3d71d5abf5cf75dc7f95fa6c55fa63 (patch)
tree28f7a72e5dec4abf908fd7874bdab776281310bc /src/libstrongswan/crypto
parent7b0305f59ddab9ea026b202a8c569912e5bf9a90 (diff)
downloadvyos-strongswan-49104abddf3d71d5abf5cf75dc7f95fa6c55fa63.tar.gz
vyos-strongswan-49104abddf3d71d5abf5cf75dc7f95fa6c55fa63.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.1.8)
Diffstat (limited to 'src/libstrongswan/crypto')
-rw-r--r--src/libstrongswan/crypto/ac.c239
-rw-r--r--src/libstrongswan/crypto/ac.h37
-rwxr-xr-xsrc/libstrongswan/crypto/crl.c19
-rwxr-xr-xsrc/libstrongswan/crypto/crl.h2
-rw-r--r--src/libstrongswan/crypto/diffie_hellman.c293
-rw-r--r--src/libstrongswan/crypto/diffie_hellman.h69
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.c79
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.h44
-rw-r--r--src/libstrongswan/crypto/hmac.h2
-rw-r--r--src/libstrongswan/crypto/ietf_attr_list.c405
-rw-r--r--src/libstrongswan/crypto/ietf_attr_list.h89
-rw-r--r--src/libstrongswan/crypto/ocsp.c16
-rw-r--r--src/libstrongswan/crypto/pkcs7.c710
-rw-r--r--src/libstrongswan/crypto/pkcs7.h132
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_private_key.c307
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_private_key.h67
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.c326
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.h43
-rw-r--r--src/libstrongswan/crypto/signers/hmac_signer.c45
-rw-r--r--src/libstrongswan/crypto/signers/signer.h6
-rwxr-xr-xsrc/libstrongswan/crypto/x509.c225
-rwxr-xr-xsrc/libstrongswan/crypto/x509.h76
22 files changed, 2402 insertions, 829 deletions
diff --git a/src/libstrongswan/crypto/ac.c b/src/libstrongswan/crypto/ac.c
index 47605e9e1..1367494f8 100644
--- a/src/libstrongswan/crypto/ac.c
+++ b/src/libstrongswan/crypto/ac.c
@@ -19,17 +19,28 @@
* 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: ac.c 3300 2007-10-12 21:53:18Z andreas $
*/
+#include <string.h>
+#include <stdio.h>
+
#include <library.h>
#include <debug.h>
#include <asn1/asn1.h>
+#include <asn1/pem.h>
+#include <crypto/x509.h>
+#include <crypto/ietf_attr_list.h>
#include <utils/identification.h>
#include <utils/linked_list.h>
+#include <utils/lexparser.h>
#include "ac.h"
+#define ACERT_WARNING_INTERVAL 1 /* day */
+
typedef struct private_x509ac_t private_x509ac_t;
/**
@@ -138,92 +149,6 @@ struct private_x509ac_t {
};
/**
- * definition of ietfAttribute kinds
- */
-typedef enum {
- IETF_ATTRIBUTE_OCTETS = 0,
- IETF_ATTRIBUTE_OID = 1,
- IETF_ATTRIBUTE_STRING = 2
-} ietfAttribute_t;
-
-/**
- * access structure for an ietfAttribute
- */
-typedef struct ietfAttr_t ietfAttr_t;
-
-struct ietfAttr_t {
- /**
- * IETF attribute kind
- */
- ietfAttribute_t kind;
-
- /**
- * IETF attribute valuse
- */
- chunk_t value;
-
- /**
- * Destroys the ietfAttr_t object.
- *
- * @param this ietfAttr_t to destroy
- */
- void (*destroy) (ietfAttr_t *this);
-};
-
-/**
- * Destroys an ietfAttr_t object
- */
-static void ietfAttr_destroy(ietfAttr_t *this)
-{
- free(this->value.ptr);
- free(this);
-}
-
-/**
- * Creates an ietfAttr_t object.
- */
-ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value)
-{
- ietfAttr_t *this = malloc_thing(ietfAttr_t);
-
- /* initialize */
- this->kind = kind;
- this->value = chunk_clone(value);
-
- /* function */
- this->destroy = ietfAttr_destroy;
-
- return this;
-}
-
-/**
- * ASN.1 definition of ietfAttrSyntax
- */
-static const asn1Object_t ietfAttrSyntaxObjects[] =
-{
- { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
- ASN1_BODY }, /* 1 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
- { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
- { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
- ASN1_BODY }, /* 4 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
- { 2, "oid", ASN1_OID, ASN1_OPT |
- ASN1_BODY }, /* 6 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
- { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
- ASN1_BODY }, /* 8 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
- { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
-};
-
-#define IETF_ATTR_OCTETS 4
-#define IETF_ATTR_OID 6
-#define IETF_ATTR_STRING 8
-#define IETF_ATTR_ROOF 11
-
-/**
* ASN.1 definition of roleSyntax
*/
static const asn1Object_t roleSyntaxObjects[] =
@@ -357,6 +282,23 @@ static err_t is_valid(const private_x509ac_t *this, time_t *until)
}
/**
+ * Implements x509ac_t.is_newer
+ */
+static bool is_newer(const private_x509ac_t *this, const private_x509ac_t *other)
+{
+ return this->notBefore > other->notBefore;
+}
+
+/**
+ * Implements x509ac_t.equals_holder.
+ */
+static bool equals_holder(const private_x509ac_t *this, const private_x509ac_t *other)
+{
+ return this->holderIssuer->equals(this->holderIssuer, other->holderIssuer)
+ && chunk_equals(this->holderSerial, other->holderSerial);
+}
+
+/**
* parses a directoryName
*/
static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name)
@@ -364,7 +306,7 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi
bool has_directoryName;
linked_list_t *list = linked_list_create();
- parse_generalNames(blob, level, implicit, list);
+ x509_parse_generalNames(blob, level, implicit, list);
has_directoryName = list->get_count(list) > 0;
if (has_directoryName)
@@ -398,43 +340,6 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi
}
/**
- * parses ietfAttrSyntax
- */
-static void parse_ietfAttrSyntax(chunk_t blob, int level0, linked_list_t *list)
-{
- asn1_ctx_t ctx;
- chunk_t object;
- u_int level;
- int objectID = 0;
-
- asn1_init(&ctx, blob, level0, FALSE, FALSE);
-
- while (objectID < IETF_ATTR_ROOF)
- {
- if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
- {
- return;
- }
-
- switch (objectID)
- {
- case IETF_ATTR_OCTETS:
- case IETF_ATTR_OID:
- case IETF_ATTR_STRING:
- {
- ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2;
- ietfAttr_t *attr = ietfAttr_create(kind, object);
- list->insert_last(list, (void *)attr);
- }
- break;
- default:
- break;
- }
- objectID++;
- }
-}
-
-/**
* parses roleSyntax
*/
static void parse_roleSyntax(chunk_t blob, int level0)
@@ -470,9 +375,9 @@ static bool parse_certificate(chunk_t blob, private_x509ac_t *this)
bool critical;
chunk_t object;
u_int level;
- u_int type = OID_UNKNOWN;
- u_int extn_oid = OID_UNKNOWN;
int objectID = 0;
+ int type = OID_UNKNOWN;
+ int extn_oid = OID_UNKNOWN;
asn1_init(&ctx, blob, 0, FALSE, FALSE);
while (objectID < AC_OBJ_ROOF)
@@ -549,10 +454,10 @@ static bool parse_certificate(chunk_t blob, private_x509ac_t *this)
DBG2(" need to parse accessIdentity");
break;
case OID_CHARGING_IDENTITY:
- parse_ietfAttrSyntax(object, level, this->charging);
+ ietfAttr_list_create_from_chunk(object, this->charging, level);
break;
case OID_GROUP:
- parse_ietfAttrSyntax(object, level, this->groups);
+ ietfAttr_list_create_from_chunk(object, this->groups, level);
break;
case OID_ROLE:
parse_roleSyntax(object, level);
@@ -577,7 +482,7 @@ static bool parse_certificate(chunk_t blob, private_x509ac_t *this)
DBG2(" need to parse crlDistributionPoints");
break;
case OID_AUTHORITY_KEY_ID:
- parse_authorityKeyIdentifier(object, level,
+ x509_parse_authorityKeyIdentifier(object, level,
&this->authKeyID, &this->authKeySerialNumber);
break;
case OID_TARGET_INFORMATION:
@@ -603,7 +508,72 @@ static bool parse_certificate(chunk_t blob, private_x509ac_t *this)
objectID++;
}
this->installed = time(NULL);
- return FALSE;
+ return TRUE;
+}
+
+/**
+ * Implementation of x509ac_t.list.
+ */
+static void list(const private_x509ac_t *this, FILE *out, bool utc)
+{
+ time_t now = time(NULL);
+
+ fprintf(out, "%#T\n", &this->installed, utc);
+
+ if (this->entityName)
+ {
+ fprintf(out, " holder: '%D'\n", this->entityName);
+ }
+ if (this->holderIssuer)
+ {
+ fprintf(out, " hissuer: '%D'\n", this->holderIssuer);
+ }
+ if (this->holderSerial.ptr)
+ {
+ fprintf(out, " hserial: %#B\n", &this->holderSerial);
+ }
+
+ /* list all group attributes on a single line */
+ fprintf(out, " groups: ");
+ ietfAttr_list_list(this->groups, out);
+ fprintf(out, "\n");
+
+ fprintf(out, " issuer: '%D'\n", this->issuerName);
+ fprintf(out, " serial: %#B\n", &this->serialNumber);
+
+ fprintf(out, " validity: not before %#T, ", &this->notBefore, utc);
+ if (now < this->notBefore)
+ {
+ fprintf(out, "not valid yet (valid in %V)\n", &now, &this->notBefore);
+ }
+ else
+ {
+ fprintf(out, "ok\n");
+ }
+
+ fprintf(out, " not after %#T, ", &this->notAfter, utc);
+ if (now > this->notAfter)
+ {
+ fprintf(out, "expired (%V ago)\n", &now, &this->notAfter);
+ }
+ else
+ {
+ fprintf(out, "ok");
+ if (now > this->notAfter - ACERT_WARNING_INTERVAL * 60 * 60 * 24)
+ {
+ fprintf(out, " (expires in %V)", &now, &this->notAfter);
+ }
+ fprintf(out, " \n");
+ }
+
+ if (this->authKeyID.ptr)
+ {
+ fprintf(out, " authkey: %#B\n", &this->authKeyID);
+ }
+ if (this->authKeySerialNumber.ptr)
+ {
+ fprintf(out, " aserial: %#B\n", &this->authKeySerialNumber);
+ }
}
/**
@@ -614,10 +584,8 @@ static void destroy(private_x509ac_t *this)
DESTROY_IF(this->holderIssuer);
DESTROY_IF(this->entityName);
DESTROY_IF(this->issuerName);
- this->charging->destroy_offset(this->charging,
- offsetof(ietfAttr_t, destroy));
- this->groups->destroy_offset(this->groups,
- offsetof(ietfAttr_t, destroy));
+ ietfAttr_list_destroy(this->charging);
+ ietfAttr_list_destroy(this->groups);
free(this->certificate.ptr);
free(this);
}
@@ -638,6 +606,9 @@ x509ac_t *x509ac_create_from_chunk(chunk_t chunk)
/* public functions */
this->public.is_valid = (err_t (*) (const x509ac_t*,time_t*))is_valid;
+ this->public.is_newer = (bool (*) (const x509ac_t*,const x509ac_t*))is_newer;
+ this->public.equals_holder = (bool (*) (const x509ac_t*,const x509ac_t*))equals_holder;
+ this->public.list = (void (*) (const x509ac_t*,FILE*,bool))list;
this->public.destroy = (void (*) (x509ac_t*))destroy;
if (!parse_certificate(chunk, this))
diff --git a/src/libstrongswan/crypto/ac.h b/src/libstrongswan/crypto/ac.h
index b7fd26c94..8a4ccbd4c 100644
--- a/src/libstrongswan/crypto/ac.h
+++ b/src/libstrongswan/crypto/ac.h
@@ -21,11 +21,15 @@
* 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: ac.h 3300 2007-10-12 21:53:18Z andreas $
*/
#ifndef AC_H_
#define AC_H_
+#include <library.h>
+
typedef struct x509ac_t x509ac_t;
/**
@@ -48,6 +52,32 @@ struct x509ac_t {
*/
err_t (*is_valid) (const x509ac_t *this, time_t *until);
+ /** @brief Checks if this attr cert is newer than the other attr cert
+ *
+ * @param this calling object
+ * @param other other attr cert object
+ * @return TRUE if this was issued more recently than other
+ */
+ bool (*is_newer) (const x509ac_t *this, const x509ac_t *other);
+
+ /**
+ * @brief Checks if two attribute certificates belong to the same holder
+ *
+ * @param this calling attribute certificate
+ * @param that other attribute certificate
+ * @return TRUE if same holder
+ */
+ bool (*equals_holder) (const x509ac_t *this, const x509ac_t *other);
+
+ /**
+ * @brief Log the attribute certificate info to out.
+ *
+ * @param this calling object
+ * @param out stream to write to
+ * @param utc TRUE for UTC times, FALSE for local time
+ */
+ void (*list)(const x509ac_t *this, FILE *out, bool utc);
+
/**
* @brief Destroys the attribute certificate.
*
@@ -68,14 +98,13 @@ x509ac_t *x509ac_create_from_chunk(chunk_t chunk);
/**
* @brief Read a x509 attribute certificate from a DER encoded file.
- *
+ *
* @param filename file containing DER encoded data
- * @return created x509ac_t certificate, or NULL if invalid.
- *
+ * @return created x509ac_t certificate, or NULL if invalid.
+ *
* @ingroup crypto
*/
x509ac_t *x509ac_create_from_file(const char *filename);
-
#endif /* AC_H_ */
diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c
index b4ae37b2e..d52078ea9 100755
--- a/src/libstrongswan/crypto/crl.c
+++ b/src/libstrongswan/crypto/crl.c
@@ -18,6 +18,8 @@
* 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: crl.c 3300 2007-10-12 21:53:18Z andreas $
*/
#include <sys/stat.h>
@@ -290,7 +292,8 @@ bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl)
}
else if (extn_oid == OID_AUTHORITY_KEY_ID)
{
- parse_authorityKeyIdentifier(object, level, &crl->authKeyID, &crl->authKeySerialNumber);
+ x509_parse_authorityKeyIdentifier(object, level,
+ &crl->authKeyID, &crl->authKeySerialNumber);
}
else if (extn_oid == OID_CRL_NUMBER)
{
@@ -304,6 +307,11 @@ bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl)
break;
case CRL_OBJ_ALGORITHM:
crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ if (crl->algorithm != crl->sigAlg)
+ {
+ DBG1(" signature algorithms do not agree");
+ return FALSE;
+ }
break;
case CRL_OBJ_SIGNATURE:
crl->signature = object;
@@ -374,7 +382,14 @@ static bool is_newer(const private_crl_t *this, const private_crl_t *other)
*/
static bool verify(const private_crl_t *this, const rsa_public_key_t *signer)
{
- return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature) == SUCCESS;
+ hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->algorithm);
+
+ if (algorithm == HASH_UNKNOWN)
+ {
+ DBG1(" unknown signature algorithm");
+ return FALSE;
+ }
+ return signer->verify_emsa_pkcs1_signature(signer, algorithm, this->tbsCertList, this->signature) == SUCCESS;
}
/**
diff --git a/src/libstrongswan/crypto/crl.h b/src/libstrongswan/crypto/crl.h
index a367c3aff..bcf031dd4 100755
--- a/src/libstrongswan/crypto/crl.h
+++ b/src/libstrongswan/crypto/crl.h
@@ -18,6 +18,8 @@
* 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: crl.h 3300 2007-10-12 21:53:18Z andreas $
*/
#ifndef CRL_H_
diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c
index e4062066c..605892e87 100644
--- a/src/libstrongswan/crypto/diffie_hellman.c
+++ b/src/libstrongswan/crypto/diffie_hellman.c
@@ -8,7 +8,7 @@
/*
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -24,11 +24,11 @@
*/
#include <gmp.h>
-#include <stdio.h>
#include "diffie_hellman.h"
#include <utils/randomizer.h>
+#include <debug.h>
ENUM_BEGIN(diffie_hellman_group_names, MODP_NONE, MODP_1024_BIT,
"MODP_NONE",
@@ -302,12 +302,12 @@ static u_int8_t group18_modulus[] = {
0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
-typedef struct modulus_info_entry_t modulus_info_entry_t;
+typedef struct modulus_entry_t modulus_entry_t;
/**
* Entry of the modulus list.
*/
-struct modulus_info_entry_t {
+struct modulus_entry_t {
/**
* Group number as it is defined in file transform_substructure.h.
*/
@@ -321,7 +321,7 @@ struct modulus_info_entry_t {
/*
* Length of modulus in bytes.
*/
- size_t modulus_length;
+ size_t modulus_len;
/*
* Generator value.
@@ -329,19 +329,18 @@ struct modulus_info_entry_t {
u_int16_t generator;
};
-
/**
* All supported modulus values.
*/
-static modulus_info_entry_t modulus_info_entries[] = {
- {MODP_768_BIT,group1_modulus,sizeof(group1_modulus),2},
- {MODP_1024_BIT,group2_modulus,sizeof(group2_modulus),2},
- {MODP_1536_BIT,group5_modulus,sizeof(group5_modulus),2},
- {MODP_2048_BIT,group14_modulus,sizeof(group14_modulus),2},
- {MODP_3072_BIT,group15_modulus,sizeof(group15_modulus),2},
- {MODP_4096_BIT,group16_modulus,sizeof(group16_modulus),2},
- {MODP_6144_BIT,group17_modulus,sizeof(group17_modulus),2},
- {MODP_8192_BIT,group18_modulus,sizeof(group18_modulus),2},
+static modulus_entry_t modulus_entries[] = {
+ {MODP_768_BIT, group1_modulus, sizeof(group1_modulus), 2},
+ {MODP_1024_BIT, group2_modulus, sizeof(group2_modulus), 2},
+ {MODP_1536_BIT, group5_modulus, sizeof(group5_modulus), 2},
+ {MODP_2048_BIT, group14_modulus, sizeof(group14_modulus), 2},
+ {MODP_3072_BIT, group15_modulus, sizeof(group15_modulus), 2},
+ {MODP_4096_BIT, group16_modulus, sizeof(group16_modulus), 2},
+ {MODP_6144_BIT, group17_modulus, sizeof(group17_modulus), 2},
+ {MODP_8192_BIT, group18_modulus, sizeof(group18_modulus), 2},
};
typedef struct private_diffie_hellman_t private_diffie_hellman_t;
@@ -359,170 +358,133 @@ struct private_diffie_hellman_t {
/**
* Diffie Hellman group number.
*/
- u_int16_t dh_group_number;
-
- /**
- * Modulus.
- */
- mpz_t modulus;
-
- /**
- * Modulus length.
- */
- size_t modulus_length;
+ u_int16_t group;
/*
* Generator value.
*/
- u_int16_t generator;
+ mpz_t g;
/**
- * My private value .
+ * My private value.
*/
- mpz_t my_private_value;
+ mpz_t xa;
/**
* My public value.
*/
- mpz_t my_public_value;
+ mpz_t ya;
/**
* Other public value.
*/
- mpz_t other_public_value;
+ mpz_t yb;
/**
* Shared secret.
*/
- mpz_t shared_secret;
+ mpz_t zz;
/**
- * True if shared secret is computed and stored in my_public_value.
- */
- bool shared_secret_is_computed;
-
- /**
- * Sets the modulus for a specific diffie hellman group.
- *
- * @param this calling object
- * @return
- * SUCCESS if modulus could be found
- * NOT_FOUND if modulus not supported
+ * Modulus.
*/
- status_t (*set_modulus) (private_diffie_hellman_t *this);
+ mpz_t p;
/**
- * Makes sure my public value is computed.
- *
- * @param this calling object
+ * Modulus length.
*/
- void (*compute_public_value) (private_diffie_hellman_t *this);
+ size_t p_len;
/**
- * Computes shared secret (other public value must be available).
- *
- * @param this calling object
+ * True if shared secret is computed and stored in my_public_value.
*/
- void (*compute_shared_secret) (private_diffie_hellman_t *this);
+ bool computed;
};
/**
- * Implementation of private_diffie_hellman_t.set_modulus.
+ * Implementation of diffie_hellman_t.set_other_public_value.
*/
-static status_t set_modulus(private_diffie_hellman_t *this)
+static void set_other_public_value(private_diffie_hellman_t *this, chunk_t value)
{
- int i;
- status_t status = NOT_FOUND;
+ mpz_t p_min_1;
+
+ mpz_init(p_min_1);
+ mpz_sub_ui(p_min_1, this->p, 1);
+
+ mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr);
- for (i = 0; i < (sizeof(modulus_info_entries) / sizeof(modulus_info_entry_t)); i++)
+ /* check public value:
+ * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1
+ * 2. a public value larger or equal the modulus is invalid */
+ if (mpz_cmp_ui(this->yb, 1) > 0 ||
+ mpz_cmp(this->yb, p_min_1) < 0)
{
- if (modulus_info_entries[i].group == this->dh_group_number)
+#ifdef EXTENDED_DH_TEST
+ /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */
+ mpz_t q, one;
+
+ mpz_init(q);
+ mpz_init(one);
+ mpz_fdiv_q_2exp(q, p_min_1, 1);
+ mpz_powm(one, this->yb, q, this->p);
+ mpz_clear(q);
+ if (mpz_cmp_ui(one, 1) == 0)
{
- chunk_t modulus_chunk;
- modulus_chunk.ptr = modulus_info_entries[i].modulus;
- modulus_chunk.len = modulus_info_entries[i].modulus_length;
- mpz_import(this->modulus, modulus_chunk.len, 1, 1, 1, 0, modulus_chunk.ptr);
- this->modulus_length = modulus_chunk.len;
- this->generator = modulus_info_entries[i].generator;
- status = SUCCESS;
- break;
+ mpz_powm(this->zz, this->yb, this->xa, this->p);
+ this->computed = TRUE;
+ }
+ else
+ {
+ DBG1("public DH value verification failed: y ^ q mod p != 1");
}
+ mpz_clear(one);
+#else
+ mpz_powm(this->zz, this->yb, this->xa, this->p);
+ this->computed = TRUE;
+#endif
}
- return status;
-}
-
-/**
- * Implementation of diffie_hellman_t.set_other_public_value.
- */
-static void set_other_public_value(private_diffie_hellman_t *this,chunk_t public_value)
-{
- mpz_import(this->other_public_value, public_value.len, 1, 1, 1, 0, public_value.ptr);
- this->compute_shared_secret(this);
+ else
+ {
+ DBG1("public DH value verification failed: y < 2 || y > p - 1 ");
+ }
+ mpz_clear(p_min_1);
}
/**
* Implementation of diffie_hellman_t.get_other_public_value.
*/
-static status_t get_other_public_value(private_diffie_hellman_t *this,chunk_t *public_value)
+static status_t get_other_public_value(private_diffie_hellman_t *this,
+ chunk_t *value)
{
- if (!this->shared_secret_is_computed)
+ if (!this->computed)
{
return FAILED;
}
- public_value->len = this->modulus_length;
- public_value->ptr = mpz_export(NULL, NULL, 1, public_value->len, 1, 0, this->other_public_value);
+ value->len = this->p_len;
+ value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->yb);
return SUCCESS;
}
/**
- * Implementation of private_diffie_hellman_t.compute_shared_secret.
- */
-static void compute_shared_secret (private_diffie_hellman_t *this)
-{
- /* initialize my public value */
- mpz_init(this->shared_secret);
- /* calculate my public value */
- mpz_powm(this->shared_secret,this->other_public_value,this->my_private_value,this->modulus);
-
- this->shared_secret_is_computed = TRUE;
-}
-
-/**
- * Implementation of private_diffie_hellman_t.compute_public_value.
- */
-static void compute_public_value (private_diffie_hellman_t *this)
-{
- mpz_t generator;
- /* initialize generator and set it*/
- mpz_init_set_ui (generator,this->generator);
- /* initialize my public value */
- mpz_init(this->my_public_value);
- /* calculate my public value */
- mpz_powm(this->my_public_value,generator,this->my_private_value,this->modulus);
- /* generator not used anymore */
- mpz_clear(generator);
-}
-
-/**
* Implementation of diffie_hellman_t.get_my_public_value.
*/
-static void get_my_public_value(private_diffie_hellman_t *this,chunk_t *public_value)
+static void get_my_public_value(private_diffie_hellman_t *this,chunk_t *value)
{
- public_value->len = this->modulus_length;
- public_value->ptr = mpz_export(NULL, NULL, 1, public_value->len, 1, 0, this->my_public_value);
+ value->len = this->p_len;
+ value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya);
}
/**
* Implementation of diffie_hellman_t.get_shared_secret.
*/
-static status_t get_shared_secret(private_diffie_hellman_t *this,chunk_t *secret)
+static status_t get_shared_secret(private_diffie_hellman_t *this, chunk_t *secret)
{
- if (!this->shared_secret_is_computed)
+ if (!this->computed)
{
return FAILED;
}
- secret->len = this->modulus_length;
- secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->shared_secret);
+ secret->len = this->p_len;
+ secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz);
return SUCCESS;
}
@@ -531,35 +493,57 @@ static status_t get_shared_secret(private_diffie_hellman_t *this,chunk_t *secret
*/
static diffie_hellman_group_t get_dh_group(private_diffie_hellman_t *this)
{
- return this->dh_group_number;
+ return this->group;
}
/**
- * Implementation of diffie_hellman_t.destroy.
+ * Lookup the modulus in modulo table
*/
-static void destroy(private_diffie_hellman_t *this)
+static status_t set_modulus(private_diffie_hellman_t *this)
{
- mpz_clear(this->modulus);
- mpz_clear(this->my_private_value);
- mpz_clear(this->my_public_value);
- mpz_clear(this->other_public_value);
-
- if (this->shared_secret_is_computed)
+ int i;
+ status_t status = NOT_FOUND;
+
+ for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++)
{
- /* other public value gets initialized together with shared secret */
- mpz_clear(this->shared_secret);
+ if (modulus_entries[i].group == this->group)
+ {
+ chunk_t chunk;
+ chunk.ptr = modulus_entries[i].modulus;
+ chunk.len = modulus_entries[i].modulus_len;
+ mpz_import(this->p, chunk.len, 1, 1, 1, 0, chunk.ptr);
+ this->p_len = chunk.len;
+ mpz_set_ui(this->g, modulus_entries[i].generator);
+ status = SUCCESS;
+ break;
+ }
}
+ return status;
+}
+
+/**
+ * Implementation of diffie_hellman_t.destroy.
+ */
+static void destroy(private_diffie_hellman_t *this)
+{
+ mpz_clear(this->p);
+ mpz_clear(this->xa);
+ mpz_clear(this->ya);
+ mpz_clear(this->yb);
+ mpz_clear(this->zz);
+ mpz_clear(this->g);
free(this);
}
/*
* Described in header.
*/
-diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number)
+diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t group)
{
private_diffie_hellman_t *this = malloc_thing(private_diffie_hellman_t);
randomizer_t *randomizer;
- chunk_t random_bytes;
+ chunk_t random;
+ status_t status;
/* public functions */
this->public.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret;
@@ -569,44 +553,37 @@ diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number)
this->public.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group;
this->public.destroy = (void (*)(diffie_hellman_t *)) destroy;
- /* private functions */
- this->set_modulus = set_modulus;
- this->compute_public_value = compute_public_value;
- this->compute_shared_secret = compute_shared_secret;
-
/* private variables */
- this->dh_group_number = dh_group_number;
- mpz_init(this->modulus);
- mpz_init(this->other_public_value);
- mpz_init(this->my_private_value);
+ this->group = group;
+ mpz_init(this->p);
+ mpz_init(this->yb);
+ mpz_init(this->ya);
+ mpz_init(this->xa);
+ mpz_init(this->zz);
+ mpz_init(this->g);
+
+ this->computed = FALSE;
- /* set this->modulus */
- if (this->set_modulus(this) != SUCCESS)
+ /* find a modulus according to group */
+ if (set_modulus(this) != SUCCESS)
{
- free(this);
+ destroy(this);
return NULL;
}
randomizer = randomizer_create();
- if (randomizer == NULL)
- {
- free(this);
- return NULL;
- }
- if (randomizer->allocate_pseudo_random_bytes(randomizer, this->modulus_length, &random_bytes) != SUCCESS)
+ status = randomizer->allocate_pseudo_random_bytes(
+ randomizer, this->p_len, &random);
+ randomizer->destroy(randomizer);
+ if (status != SUCCESS)
{
- randomizer->destroy(randomizer);
- free(this);
+ destroy(this);
return NULL;
}
+ mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr);
+ chunk_free(&random);
- mpz_import(this->my_private_value, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr);
- chunk_free(&random_bytes);
+ mpz_powm(this->ya, this->g, this->xa, this->p);
- randomizer->destroy(randomizer);
-
- this->compute_public_value(this);
-
- this->shared_secret_is_computed = FALSE;
-
- return &(this->public);
+ return &this->public;
}
+
diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h
index 29a2ab45b..8cd06d60e 100644
--- a/src/libstrongswan/crypto/diffie_hellman.h
+++ b/src/libstrongswan/crypto/diffie_hellman.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -36,7 +36,7 @@ typedef struct diffie_hellman_t diffie_hellman_t;
*
* See IKEv2 RFC 3.3.2 and RFC 3526.
*
- * @ingroup transforms
+ * @ingroup crypto
*/
enum diffie_hellman_group_t {
MODP_NONE = 0,
@@ -56,76 +56,74 @@ enum diffie_hellman_group_t {
extern enum_name_t *diffie_hellman_group_names;
/**
- * @brief Implementation of the widely used Diffie-Hellman algorithm.
+ * @brief Implementation of the Diffie-Hellman algorithm, as in RFC2631.
*
* @b Constructors:
* - diffie_hellman_create()
*
- * @ingroup transforms
+ * @ingroup crypto
*/
struct diffie_hellman_t {
/**
* @brief Returns the shared secret of this diffie hellman exchange.
*
- * @warning Space for returned secret is allocated and must be
+ * Space for returned secret is allocated and must be
* freed by the caller.
*
- * @param this calling diffie_hellman_t object
- * @param[out] secret shared secret will be written into this chunk
+ * @param this calling object
+ * @param secret shared secret will be written into this chunk
* @return
- * - SUCCESS
- * - FAILED if not both DH values are set
+ * - SUCCESS
+ * - FAILED if not both DH values are set
*/
status_t (*get_shared_secret) (diffie_hellman_t *this, chunk_t *secret);
/**
* @brief Sets the public value of partner.
*
- * chunk gets cloned and can be destroyed afterwards.
+ * Chunk gets cloned and can be destroyed afterwards.
*
- * @param this calling diffie_hellman_t object
- * @param public_value public value of partner
+ * @param this calling object
+ * @param value public value of partner
*/
- void (*set_other_public_value) (diffie_hellman_t *this, chunk_t public_value);
+ void (*set_other_public_value) (diffie_hellman_t *this, chunk_t value);
/**
* @brief Gets the public value of partner.
*
- * @warning Space for returned chunk is allocated and must be
- * freed by the caller.
+ * Space for returned chunk is allocated and must be freed by the caller.
*
- * @param this calling diffie_hellman_t object
- * @param[out] public_value public value of partner is stored at this location
+ * @param this calling object
+ * @param value public value of partner is stored at this location
* @return
- * - SUCCESS
- * - FAILED if other public value not set
+ * - SUCCESS
+ * - FAILED if other public value not set
*/
- status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *public_value);
+ status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *value);
/**
- * @brief Gets the public value of caller
+ * @brief Gets the own public value to transmit.
*
- * @warning Space for returned chunk is allocated and must be
- * freed by the caller.
+ * Space for returned chunk is allocated and must be freed by the caller.
*
- * @param this calling diffie_hellman_t object
- * @param[out] public_value public value of caller is stored at this location
+ * @param this calling object
+ * @param value public value of caller is stored at this location
*/
- void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *public_value);
+ void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *value);
/**
* @brief Get the DH group used.
*
- * @param this calling diffie_hellman_t object
- * @return DH group set in construction
+ * @param this calling object
+ * @return DH group set in construction
*/
diffie_hellman_group_t (*get_dh_group) (diffie_hellman_t *this);
/**
* @brief Destroys an diffie_hellman_t object.
*
- * @param this diffie_hellman_t object to destroy
+ * @param this diffie_hellman_t object to destroy
*/
void (*destroy) (diffie_hellman_t *this);
};
@@ -133,15 +131,14 @@ struct diffie_hellman_t {
/**
* @brief Creates a new diffie_hellman_t object.
*
- * The first diffie hellman public value gets automatically created.
- *
- * @param dh_group_number Diffie Hellman group number to use
+ * @param group Diffie Hellman group number to use
* @return
- * - diffie_hellman_t object
- * - NULL if dh group not supported
+ * - diffie_hellman_t object
+ * - NULL if dh group not supported
*
- * @ingroup transforms
+ * @ingroup crypto
*/
-diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number);
+diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t group);
#endif /*DIFFIE_HELLMAN_H_*/
+
diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c
index 7fa6346d6..14bfb022f 100644
--- a/src/libstrongswan/crypto/hashers/hasher.c
+++ b/src/libstrongswan/crypto/hashers/hasher.c
@@ -19,17 +19,21 @@
* 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: hasher.c 3304 2007-10-12 23:18:42Z andreas $
*/
#include "hasher.h"
+#include <asn1/oid.h>
#include <crypto/hashers/sha1_hasher.h>
#include <crypto/hashers/sha2_hasher.h>
#include <crypto/hashers/md5_hasher.h>
-ENUM(hash_algorithm_names, HASH_MD2, HASH_SHA512,
+ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512,
+ "HASH_UNKNOWN",
"HASH_MD2",
"HASH_MD5",
"HASH_SHA1",
@@ -63,3 +67,76 @@ hasher_t *hasher_create(hash_algorithm_t hash_algorithm)
return NULL;
}
}
+
+/*
+ * Described in header.
+ */
+hash_algorithm_t hasher_algorithm_from_oid(int oid)
+{
+ hash_algorithm_t algorithm;
+
+ switch (oid)
+ {
+ case OID_MD2:
+ case OID_MD2_WITH_RSA:
+ algorithm = HASH_MD2;
+ break;
+ case OID_MD5:
+ case OID_MD5_WITH_RSA:
+ algorithm = HASH_MD5;
+ break;
+ case OID_SHA1:
+ case OID_SHA1_WITH_RSA:
+ algorithm = HASH_SHA1;
+ break;
+ case OID_SHA256:
+ case OID_SHA256_WITH_RSA:
+ algorithm = HASH_SHA256;
+ break;
+ case OID_SHA384:
+ case OID_SHA384_WITH_RSA:
+ algorithm = HASH_SHA384;
+ break;
+ case OID_SHA512:
+ case OID_SHA512_WITH_RSA:
+ algorithm = HASH_SHA512;
+ break;
+ default:
+ algorithm = HASH_UNKNOWN;
+ }
+ return algorithm;
+}
+
+/*
+ * Described in header.
+ */
+int hasher_signature_algorithm_to_oid(hash_algorithm_t alg)
+{
+ int oid;
+
+ switch (alg)
+ {
+ case HASH_MD2:
+ oid = OID_MD2_WITH_RSA;
+ break;
+ case HASH_MD5:
+ oid = OID_MD5_WITH_RSA;
+ break;
+ case HASH_SHA1:
+ oid = OID_SHA1_WITH_RSA;
+ break;
+ case HASH_SHA256:
+ oid = OID_SHA256_WITH_RSA;
+ break;
+ case HASH_SHA384:
+ oid = OID_SHA384_WITH_RSA;
+ break;
+ case HASH_SHA512:
+ oid = OID_SHA512_WITH_RSA;
+ break;
+ default:
+ oid = OID_UNKNOWN;
+ }
+ return oid;
+}
+
diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h
index 6c17f892d..48b904576 100644
--- a/src/libstrongswan/crypto/hashers/hasher.h
+++ b/src/libstrongswan/crypto/hashers/hasher.h
@@ -19,6 +19,8 @@
* 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: hasher.h 3307 2007-10-17 02:56:24Z andreas $
*/
#ifndef HASHER_H_
@@ -42,17 +44,18 @@ typedef struct hasher_t hasher_t;
* @ingroup hashers
*/
enum hash_algorithm_t {
- HASH_MD2 = 0,
+ HASH_UNKNOWN = 0,
+ HASH_MD2 = 1,
/** Implemented in class md5_hasher_t */
- HASH_MD5 = 1,
+ HASH_MD5 = 2,
/** Implemented in class sha1_hasher_t */
- HASH_SHA1 = 2,
+ HASH_SHA1 = 3,
/** Implemented in class sha2_hasher_t */
- HASH_SHA256 = 3,
+ HASH_SHA256 = 4,
/** Implemented in class sha2_hasher_t */
- HASH_SHA384 = 4,
+ HASH_SHA384 = 5,
/** Implemented in class sha2_hasher_t */
- HASH_SHA512 = 5,
+ HASH_SHA512 = 6,
};
#define HASH_SIZE_MD2 16
@@ -68,7 +71,6 @@ enum hash_algorithm_t {
*/
extern enum_name_t *hash_algorithm_names;
-
/**
* @brief Generic interface for all hash functions.
*
@@ -82,7 +84,7 @@ struct hasher_t {
* @brief Hash data and write it in the buffer.
*
* If the parameter hash is NULL, no result is written back
- * an more data can be appended to already hashed data.
+ * and more data can be appended to already hashed data.
* If not, the result is written back and the hasher is reset.
*
* The hash output parameter must hold at least
@@ -98,7 +100,7 @@ struct hasher_t {
* @brief Hash data and allocate space for the hash.
*
* If the parameter hash is NULL, no result is written back
- * an more data can be appended to already hashed data.
+ * and more data can be appended to already hashed data.
* If not, the result is written back and the hasher is reset.
*
* @param this calling object
@@ -156,4 +158,28 @@ struct hasher_t {
*/
hasher_t *hasher_create(hash_algorithm_t hash_algorithm);
+/**
+ * @brief Conversion of ASN.1 OID to hash algorithm.
+ *
+ * @param oid ASN.1 OID
+ * @return
+ * - hash algorithm
+ * - HASH_UNKNOWN if OID unsuported
+ *
+ * @ingroup hashers
+ */
+hash_algorithm_t hasher_algorithm_from_oid(int oid);
+
+/**
+ * @brief Conversion of hash signature algorithm ASN.1 OID.
+ *
+ * @param alg hash algorithm
+ * @return
+ * - ASN.1 OID if known hash algorithm
+ * - OID_UNKNOW
+ *
+ * @ingroup hashers
+ */
+int hasher_signature_algorithm_to_oid(hash_algorithm_t alg);
+
#endif /* HASHER_H_ */
diff --git a/src/libstrongswan/crypto/hmac.h b/src/libstrongswan/crypto/hmac.h
index d320bc5aa..06b75aaf9 100644
--- a/src/libstrongswan/crypto/hmac.h
+++ b/src/libstrongswan/crypto/hmac.h
@@ -42,7 +42,7 @@ typedef struct hmac_t hmac_t;
* @b Constructors:
* - hmac_create()
*
- * @ingroup transforms
+ * @ingroup crypto
*/
struct hmac_t {
/**
diff --git a/src/libstrongswan/crypto/ietf_attr_list.c b/src/libstrongswan/crypto/ietf_attr_list.c
new file mode 100644
index 000000000..1ecadf679
--- /dev/null
+++ b/src/libstrongswan/crypto/ietf_attr_list.c
@@ -0,0 +1,405 @@
+/**
+ * @file ietf_attr.c
+ *
+ * @brief Implementation of ietfAttr_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Andreas Steffen, Hochschule fuer 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
+ * 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <asn1/asn1.h>
+#include <utils/lexparser.h>
+
+#include "ietf_attr_list.h"
+
+/**
+ * Private definition of ietfAttribute kinds
+ */
+typedef enum {
+ IETF_ATTRIBUTE_OCTETS = 0,
+ IETF_ATTRIBUTE_OID = 1,
+ IETF_ATTRIBUTE_STRING = 2
+} ietfAttribute_t;
+
+typedef struct ietfAttr_t ietfAttr_t;
+
+/**
+ * Private definition of an ietfAttribute
+ */
+struct ietfAttr_t {
+ /**
+ * IETF attribute kind
+ */
+ ietfAttribute_t kind;
+
+ /**
+ * IETF attribute valuse
+ */
+ chunk_t value;
+
+ /**
+ * Compares two ietfAttributes
+ *
+ * return -1 if this is earlier in the alphabet than other
+ * return 0 if this equals other
+ * return +1 if this is later in the alphabet than other
+ *
+ * @param this calling object
+ * @param other other object
+ */
+ int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other);
+
+ /**
+ * Destroys the ietfAttr_t object.
+ *
+ * @param this ietfAttr_t to destroy
+ */
+ void (*destroy) (ietfAttr_t *this);
+};
+
+/**
+ * Implements ietfAttr_t.compare.
+ */
+static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other)
+{
+ int cmp_len, len, cmp_value;
+
+ /* OID attributes are appended after STRING and OCTETS attributes */
+ if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID)
+ {
+ return -1;
+ }
+ if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID)
+ {
+ return 1;
+ }
+
+ cmp_len = this->value.len - other->value.len;
+ len = (cmp_len < 0)? this->value.len : other->value.len;
+ cmp_value = memcmp(this->value.ptr, other->value.ptr, len);
+
+ return (cmp_value == 0)? cmp_len : cmp_value;
+}
+
+/**
+ * Implements ietfAttr_t.destroy.
+ */
+static void ietfAttr_destroy(ietfAttr_t *this)
+{
+ free(this->value.ptr);
+ free(this);
+}
+
+/**
+ * Creates an ietfAttr_t object.
+ */
+static ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value)
+{
+ ietfAttr_t *this = malloc_thing(ietfAttr_t);
+
+ /* initialize */
+ this->kind = kind;
+ this->value = chunk_clone(value);
+
+ /* function */
+ this->compare = ietfAttr_compare;
+ this->destroy = ietfAttr_destroy;
+
+ return this;
+}
+
+/**
+ * Adds an ietfAttr_t object to a sorted linked list
+ */
+static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr)
+{
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+ ietfAttr_t *current_attr;
+ bool found = FALSE;
+
+ while (iterator->iterate(iterator, (void **)&current_attr))
+ {
+ int cmp = attr->compare(attr, current_attr);
+
+ if (cmp > 0)
+ {
+ continue;
+ }
+ if (cmp == 0)
+ {
+ attr->destroy(attr);
+ }
+ else
+ {
+ iterator->insert_before(iterator, attr);
+ }
+ found = TRUE;
+ break;
+ }
+ iterator->destroy(iterator);
+ if (!found)
+ {
+ list->insert_last(list, attr);
+ }
+}
+
+/*
+ * Described in header.
+ */
+bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b)
+{
+ bool result = TRUE;
+
+ /* lists must have the same number of attributes */
+ if (list_a->get_count(list_a) != list_b->get_count(list_b))
+ {
+ return FALSE;
+ }
+ /* empty lists - no attributes */
+ if (list_a->get_count(list_a) == 0)
+ {
+ return TRUE;
+ }
+
+ /* compare two alphabetically-sorted lists */
+ {
+ iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE);
+ iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE);
+ ietfAttr_t *attr_a, *attr_b;
+
+ while (iterator_a->iterate(iterator_a, (void **)&attr_a) &&
+ iterator_b->iterate(iterator_b, (void **)&attr_b))
+ {
+ if (attr_a->compare(attr_a, attr_b) != 0)
+ {
+ /* we have a mismatch */
+ result = FALSE;
+ break;
+ }
+ }
+ iterator_a->destroy(iterator_a);
+ iterator_b->destroy(iterator_b);
+ }
+ return result;
+}
+
+/*
+ * Described in header.
+ */
+void ietfAttr_list_list(linked_list_t *list, FILE *out)
+{
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+ ietfAttr_t *attr;
+ bool first = TRUE;
+
+ while (iterator->iterate(iterator, (void **)&attr))
+ {
+ if (first)
+ {
+ first = FALSE;
+ }
+ else
+ {
+ fprintf(out, ", ");
+ }
+
+ switch (attr->kind)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ case IETF_ATTRIBUTE_STRING:
+ fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr);
+ break;
+ case IETF_ATTRIBUTE_OID:
+ {
+ int oid = known_oid(attr->value);
+
+ if (oid == OID_UNKNOWN)
+ {
+ fprintf(out, "0x#B", &attr->value);
+ }
+ else
+ {
+ fprintf(out, "%s", oid_names[oid]);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/*
+ * Described in header.
+ */
+void ietfAttr_list_create_from_string(char *msg, linked_list_t *list)
+{
+ chunk_t line = { msg, strlen(msg) };
+
+ while (eat_whitespace(&line))
+ {
+ chunk_t group;
+
+ /* extract the next comma-separated group attribute */
+ if (!extract_token(&group, ',', &line))
+ {
+ group = line;
+ line.len = 0;
+ }
+
+ /* remove any trailing spaces */
+ while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
+ {
+ group.len--;
+ }
+
+ /* add the group attribute to the list */
+ if (group.len > 0)
+ {
+ ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group);
+
+ ietfAttr_add(list, attr);
+ }
+ }
+}
+
+/**
+ * ASN.1 definition of ietfAttrSyntax
+ */
+static const asn1Object_t ietfAttrSyntaxObjects[] =
+{
+ { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 1 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
+ { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
+ { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
+ ASN1_BODY }, /* 4 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
+ { 2, "oid", ASN1_OID, ASN1_OPT |
+ ASN1_BODY }, /* 6 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 2, "string", ASN1_UTF8STRING, ASN1_OPT |
+ ASN1_BODY }, /* 8 */
+ { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
+};
+
+#define IETF_ATTR_OCTETS 4
+#define IETF_ATTR_OID 6
+#define IETF_ATTR_STRING 8
+#define IETF_ATTR_ROOF 11
+
+/*
+ * Described in header.
+ */
+void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, chunk, level0, FALSE, FALSE);
+
+ while (objectID < IETF_ATTR_ROOF)
+ {
+ if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
+ {
+ return;
+ }
+
+ switch (objectID)
+ {
+ case IETF_ATTR_OCTETS:
+ case IETF_ATTR_OID:
+ case IETF_ATTR_STRING:
+ {
+ ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2;
+ ietfAttr_t *attr = ietfAttr_create(kind, object);
+ ietfAttr_add(list, attr);
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
+}
+
+/*
+ * Described in header.
+ */
+chunk_t ietfAttr_list_encode(linked_list_t *list)
+{
+ chunk_t ietfAttributes;
+ size_t size = 0;
+ u_char *pos;
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+ ietfAttr_t *attr;
+
+ /* precalculate the total size of all values */
+ while (iterator->iterate(iterator, (void **)&attr))
+ {
+ size_t len = attr->value.len;
+
+ size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
+ }
+ iterator->destroy(iterator);
+
+ pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
+
+ iterator = list->create_iterator(list, TRUE);
+ while (iterator->iterate(iterator, (void **)&attr))
+ {
+ chunk_t ietfAttribute;
+ asn1_t type = ASN1_NULL;
+
+ switch (attr->kind)
+ {
+ case IETF_ATTRIBUTE_OCTETS:
+ type = ASN1_OCTET_STRING;
+ break;
+ case IETF_ATTRIBUTE_STRING:
+ type = ASN1_UTF8STRING;
+ break;
+ case IETF_ATTRIBUTE_OID:
+ type = ASN1_OID;
+ break;
+ }
+ ietfAttribute = asn1_simple_object(type, attr->value);
+
+ /* copy ietfAttribute into ietfAttributes chunk */
+ memcpy(pos, ietfAttribute.ptr, ietfAttribute.len);
+ pos += ietfAttribute.len;
+ free(ietfAttribute.ptr);
+ }
+ iterator->destroy(iterator);
+
+ return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
+}
+
+/*
+ * Described in header.
+ */
+void ietfAttr_list_destroy(linked_list_t *list)
+{
+ list->destroy_offset(list, offsetof(ietfAttr_t, destroy));
+}
diff --git a/src/libstrongswan/crypto/ietf_attr_list.h b/src/libstrongswan/crypto/ietf_attr_list.h
new file mode 100644
index 000000000..75407bbf6
--- /dev/null
+++ b/src/libstrongswan/crypto/ietf_attr_list.h
@@ -0,0 +1,89 @@
+/**
+ * @file ietf_attr_list.h
+ *
+ * @brief Handling of ietfAttr_t linked lists
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Andreas Steffen
+ *
+ * Hochschule fuer 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
+ * 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.
+ */
+
+#ifndef IETF_ATTR_LIST_H_
+#define IETF_ATTR_LIST_H_
+
+#include <library.h>
+#include <utils/linked_list.h>
+
+
+/**
+ * @brief Compare two linked lists of ietfAttr_t objects for equality
+ *
+ * @param list_a first alphabetically-sorted list
+ * @param list_b second alphabetically-sorted list
+ * @return TRUE if equal
+ *
+ * @ingroup crypto
+ */
+bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b);
+
+/**
+ * @brief Lists a linked list of ietfAttr_t objects
+ *
+ * @param list alphabetically-sorted linked list of attributes
+ @param out output file
+ *
+ * @ingroup crypto
+ */
+void ietfAttr_list_list(linked_list_t *list, FILE *out);
+
+/**
+ * @brief Create a linked list of ietfAttr_t objects from a string
+ *
+ * @param msg string with comma-separated group names
+ * @param list alphabetically-sorted linked list of attributes
+ *
+ * @ingroup crypto
+ */
+void ietfAttr_list_create_from_string(char *msg, linked_list_t *list);
+
+/**
+ * @brief Create a linked list of ietfAttr_t objects from an ASN.1-coded chunk
+ *
+ * @param chunk chunk containing ASN.1-coded attributes
+ * @param list alphabetically-sorted linked list of attributes
+ * @param level0 parsing level
+ */
+void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0);
+
+/**
+ * @brief Encode a linked list of ietfAttr_t objects into an ASN.1-coded chunk
+ *
+ * @param list alphabetically-sorted linked list of attributes
+ * @return chunk containing ASN.1-coded attributes
+ */
+chunk_t ietfAttr_list_encode(linked_list_t *list);
+
+/**
+ * @brief Destroys a linked list of ietfAttr_t objects
+ *
+ * @param list list to be destroyed
+ *
+ * @ingroup crypto
+ */
+void ietfAttr_list_destroy(linked_list_t *list);
+
+#endif /* IETF_ATTR_LIST_H_ */
+
diff --git a/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c
index 0d8093e4a..e4d907188 100644
--- a/src/libstrongswan/crypto/ocsp.c
+++ b/src/libstrongswan/crypto/ocsp.c
@@ -466,11 +466,11 @@ static chunk_t ocsp_build_request(private_ocsp_t *this)
static bool ocsp_parse_basic_response(chunk_t blob, int level0, response_t *res)
{
u_int level, version;
- u_int extn_oid = OID_UNKNOWN;
asn1_ctx_t ctx;
bool critical;
chunk_t object;
int objectID = 0;
+ int extn_oid = OID_UNKNOWN;
asn1_init(&ctx, blob, level0, FALSE, FALSE);
@@ -546,9 +546,8 @@ static response_status ocsp_parse_response(response_t *res)
chunk_t object;
u_int level;
int objectID = 0;
-
+ int ocspResponseType = OID_UNKNOWN;
response_status rStatus = STATUS_INTERNALERROR;
- u_int ocspResponseType = OID_UNKNOWN;
asn1_init(&ctx, res->chunk, 0, FALSE, FALSE);
@@ -615,6 +614,13 @@ static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert)
rsa_public_key_t *public_key;
time_t until = UNDEFINED_TIME;
err_t ugh;
+ hash_algorithm_t algorithm = hasher_algorithm_from_oid(res->algorithm);
+
+ if (algorithm == HASH_UNKNOWN)
+ {
+ DBG1("unknown signature algorithm");
+ return FALSE;
+ }
DBG2("verifying ocsp response signature:");
DBG2("signer: '%D'", ocsp_cert->get_subject(ocsp_cert));
@@ -627,8 +633,8 @@ static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert)
return FALSE;
}
public_key = ocsp_cert->get_public_key(ocsp_cert);
-
- return public_key->verify_emsa_pkcs1_signature(public_key, res->tbs, res->signature) == SUCCESS;
+
+ return public_key->verify_emsa_pkcs1_signature(public_key, algorithm, res->tbs, res->signature) == SUCCESS;
}
/**
diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c
new file mode 100644
index 000000000..70510471a
--- /dev/null
+++ b/src/libstrongswan/crypto/pkcs7.c
@@ -0,0 +1,710 @@
+/**
+ * @file pkcs7.c
+ *
+ * @brief Implementation of pkcs7_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2005 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 3302 2007-10-12 21:57:20Z andreas $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <library.h>
+#include "debug.h"
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <crypto/x509.h>
+#include <crypto/hashers/hasher.h>
+#include <crypto/crypters/crypter.h>
+#include <utils/linked_list.h>
+
+#include "pkcs7.h"
+
+typedef struct private_pkcs7_t private_pkcs7_t;
+
+/**
+ * Private data of a pkcs7_t object.
+ */
+struct private_pkcs7_t {
+ /**
+ * Public interface for this certificate.
+ */
+ pkcs7_t public;
+
+ /**
+ * contentInfo type
+ */
+ int type;
+
+ /**
+ * ASN.1 encoded content
+ */
+ chunk_t content;
+
+ /**
+ * Has the content already been parsed?
+ */
+ bool parsed;
+
+ /**
+ * ASN.1 parsing start level
+ */
+ u_int level;
+
+ /**
+ * retrieved data
+ */
+ chunk_t data;
+
+ /**
+ * ASN.1 encoded attributes
+ */
+ chunk_t attributes;
+
+ /**
+ * Linked list of X.509 certificates
+ */
+ linked_list_t *certs;
+};
+
+/**
+ * ASN.1 definition of the PKCS#7 ContentInfo type
+ */
+static const asn1Object_t contentInfoObjects[] = {
+ { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_BODY }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
+};
+
+#define PKCS7_INFO_TYPE 1
+#define PKCS7_INFO_CONTENT 2
+#define PKCS7_INFO_ROOF 4
+
+/**
+ * ASN.1 definition of the PKCS#7 signedData type
+ */
+static const asn1Object_t signedDataObjects[] = {
+ { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
+ { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
+ { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
+ { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_LOOP }, /* 6 */
+ { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
+ { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
+ ASN1_LOOP }, /* 9 */
+ { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
+ { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
+ { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
+ { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
+ { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
+ { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
+ ASN1_OBJ }, /* 19 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
+ { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
+ { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
+ { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
+ { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
+ { 1, "end loop", ASN1_EOC, ASN1_END } /* 25 */
+};
+
+#define PKCS7_DIGEST_ALG 3
+#define PKCS7_SIGNED_CONTENT_INFO 5
+#define PKCS7_SIGNED_CERT 7
+#define PKCS7_SIGNER_INFO 13
+#define PKCS7_SIGNED_ISSUER 16
+#define PKCS7_SIGNED_SERIAL_NUMBER 17
+#define PKCS7_DIGEST_ALGORITHM 18
+#define PKCS7_AUTH_ATTRIBUTES 19
+#define PKCS7_DIGEST_ENC_ALGORITHM 21
+#define PKCS7_ENCRYPTED_DIGEST 22
+#define PKCS7_SIGNED_ROOF 26
+
+/**
+ * ASN.1 definition of the PKCS#7 envelopedData type
+ */
+static const asn1Object_t envelopedDataObjects[] = {
+ { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */
+ { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
+ { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
+ { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */
+ { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */
+ { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
+ { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
+ { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */
+ { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */
+ { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY } /* 14 */
+};
+
+#define PKCS7_ENVELOPED_VERSION 1
+#define PKCS7_RECIPIENT_INFO_VERSION 4
+#define PKCS7_ISSUER 6
+#define PKCS7_SERIAL_NUMBER 7
+#define PKCS7_ENCRYPTION_ALG 8
+#define PKCS7_ENCRYPTED_KEY 9
+#define PKCS7_CONTENT_TYPE 12
+#define PKCS7_CONTENT_ENC_ALGORITHM 13
+#define PKCS7_ENCRYPTED_CONTENT 14
+#define PKCS7_ENVELOPED_ROOF 15
+
+/**
+ * PKCS7 contentInfo OIDs
+ */
+static u_char ASN1_pkcs7_data_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01
+};
+
+static u_char ASN1_pkcs7_signed_data_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
+};
+
+static u_char ASN1_pkcs7_enveloped_data_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03
+};
+
+static u_char ASN1_pkcs7_signed_enveloped_data_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04
+};
+
+static u_char ASN1_pkcs7_digested_data_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05
+};
+
+static char ASN1_pkcs7_encrypted_data_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06
+};
+
+static const chunk_t ASN1_pkcs7_data_oid =
+ chunk_from_buf(ASN1_pkcs7_data_oid_str);
+static const chunk_t ASN1_pkcs7_signed_data_oid =
+ chunk_from_buf(ASN1_pkcs7_signed_data_oid_str);
+static const chunk_t ASN1_pkcs7_enveloped_data_oid =
+ chunk_from_buf(ASN1_pkcs7_enveloped_data_oid_str);
+static const chunk_t ASN1_pkcs7_signed_enveloped_data_oid =
+ chunk_from_buf(ASN1_pkcs7_signed_enveloped_data_oid_str);
+static const chunk_t ASN1_pkcs7_digested_data_oid =
+ chunk_from_buf(ASN1_pkcs7_digested_data_oid_str);
+static const chunk_t ASN1_pkcs7_encrypted_data_oid =
+ chunk_from_buf(ASN1_pkcs7_encrypted_data_oid_str);
+
+/**
+ * 3DES and DES encryption OIDs
+ */
+static u_char ASN1_3des_ede_cbc_oid_str[] = {
+ 0x06, 0x08,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07
+};
+
+static u_char ASN1_des_cbc_oid_str[] = {
+ 0x06, 0x05,
+ 0x2B, 0x0E, 0x03, 0x02, 0x07
+};
+
+static const chunk_t ASN1_3des_ede_cbc_oid =
+ chunk_from_buf(ASN1_3des_ede_cbc_oid_str);
+static const chunk_t ASN1_des_cbc_oid =
+ chunk_from_buf(ASN1_des_cbc_oid_str);
+
+/**
+ * PKCS#7 attribute type OIDs
+ */
+static u_char ASN1_contentType_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
+};
+
+static u_char ASN1_messageDigest_oid_str[] = {
+ 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
+};
+
+static const chunk_t ASN1_contentType_oid =
+ chunk_from_buf(ASN1_contentType_oid_str);
+static const chunk_t ASN1_messageDigest_oid =
+ chunk_from_buf(ASN1_messageDigest_oid_str);
+
+/**
+ * Implements pkcs7_t.is_signedData.
+ */
+static bool is_data(private_pkcs7_t *this)
+{
+ return this->type == OID_PKCS7_DATA;
+}
+
+/**
+ * Implements pkcs7_t.is_signedData.
+ */
+static bool is_signedData(private_pkcs7_t *this)
+{
+ return this->type == OID_PKCS7_SIGNED_DATA;
+}
+
+/**
+ * Implements pkcs7_t.is_signedData.
+ */
+static bool is_envelopedData(private_pkcs7_t *this)
+{
+ return this->type == OID_PKCS7_ENVELOPED_DATA;
+}
+
+/**
+ * Check whether to abort the requested parsing
+ */
+static bool abort_parsing(private_pkcs7_t *this, int type)
+{
+ if (this->type != type)
+ {
+ DBG1("pkcs7 content to be parsed is not of type '%s'",
+ oid_names[type]);
+ return TRUE;
+ }
+ if (this->parsed)
+ {
+ DBG1("pkcs7 content has already been parsed");
+ return TRUE;
+ }
+ this->parsed = TRUE;
+ return FALSE;
+}
+
+/**
+ * Implements pkcs7_t.parse_data.
+ */
+static bool parse_data(private_pkcs7_t *this)
+{
+ chunk_t data = this->content;
+
+ if (abort_parsing(this, OID_PKCS7_DATA))
+ {
+ return FALSE;
+ }
+ if (parse_asn1_simple_object(&data, ASN1_OCTET_STRING, this->level, "data"))
+ {
+ this->data = chunk_clone(data);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/**
+ * Parse PKCS#7 signedData content
+ */
+static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ int digest_alg = OID_UNKNOWN;
+ int enc_alg = OID_UNKNOWN;
+ int signerInfos = 0;
+
+ chunk_t encrypted_digest = chunk_empty;
+
+ if (abort_parsing(this, OID_PKCS7_SIGNED_DATA))
+ {
+ return FALSE;
+ }
+
+ asn1_init(&ctx, this->content, this->level, FALSE, FALSE);
+
+ while (objectID < PKCS7_SIGNED_ROOF)
+ {
+ if (!extract_object(signedDataObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+
+ switch (objectID)
+ {
+ case PKCS7_DIGEST_ALG:
+ digest_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_SIGNED_CONTENT_INFO:
+ this->data = chunk_clone(object);
+ break;
+ case PKCS7_SIGNED_CERT:
+ {
+ x509_t *cert = x509_create_from_chunk(object, level+1);
+
+ if (cert)
+ {
+ this->certs->insert_last(this->certs, (void*)cert);
+ }
+ }
+ break;
+ case PKCS7_SIGNER_INFO:
+ signerInfos++;
+ DBG2(" signer #%d", signerInfos);
+ break;
+ case PKCS7_SIGNED_ISSUER:
+ {
+ identification_t *issuer;
+
+ issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ DBG2(" '%D'", issuer);
+ issuer->destroy(issuer);
+ }
+ break;
+ case PKCS7_AUTH_ATTRIBUTES:
+ this->attributes = object;
+ *this->attributes.ptr = ASN1_SET;
+ break;
+ case PKCS7_DIGEST_ALGORITHM:
+ digest_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_DIGEST_ENC_ALGORITHM:
+ enc_alg = parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case PKCS7_ENCRYPTED_DIGEST:
+ encrypted_digest = object;
+ }
+ objectID++;
+ }
+
+ /* 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);
+
+ if (signerInfos == 0)
+ {
+ DBG1("no signerInfo object found");
+ return FALSE;
+ }
+ else if (signerInfos > 1)
+ {
+ DBG1("more than one signerInfo object found");
+ return FALSE;
+ }
+ if (this->attributes.ptr == NULL)
+ {
+ DBG1("no authenticatedAttributes object found");
+ return FALSE;
+ }
+ if (enc_alg != OID_RSA_ENCRYPTION)
+ {
+ DBG1("only RSA digest encryption supported");
+ return FALSE;
+ }
+ if (signer->verify_emsa_pkcs1_signature(signer, algorithm,
+ this->attributes, encrypted_digest) != SUCCESS)
+ {
+ DBG1("invalid digest signature");
+ return FALSE;
+ }
+ else
+ {
+ DBG2("digest signature is valid");
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Parse PKCS#7 envelopedData content
+ */
+static bool parse_envelopedData(private_pkcs7_t *this, chunk_t serialNumber,
+ rsa_private_key_t *key)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ chunk_t iv = chunk_empty;
+ chunk_t symmetric_key = chunk_empty;
+ chunk_t encrypted_content = chunk_empty;
+
+ crypter_t *crypter = NULL;
+
+ if (abort_parsing(this, OID_PKCS7_ENVELOPED_DATA))
+ {
+ return FALSE;
+ }
+
+ asn1_init(&ctx, this->content, this->level, FALSE, FALSE);
+
+ while (objectID < PKCS7_ENVELOPED_ROOF)
+ {
+ if (!extract_object(envelopedDataObjects, &objectID, &object, &level, &ctx))
+ {
+ goto failed;
+ }
+
+ switch (objectID)
+ {
+ case PKCS7_ENVELOPED_VERSION:
+ if (*object.ptr != 0)
+ {
+ DBG1("envelopedData version is not 0");
+ goto failed;
+ }
+ break;
+ case PKCS7_RECIPIENT_INFO_VERSION:
+ if (*object.ptr != 0)
+ {
+ DBG1("recipient info version is not 0");
+ goto failed;
+ }
+ break;
+ case PKCS7_ISSUER:
+ {
+ identification_t *issuer;
+
+ issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
+ DBG2(" '%D'", issuer);
+ issuer->destroy(issuer);
+ }
+ break;
+ case PKCS7_SERIAL_NUMBER:
+ if (!chunk_equals(serialNumber, object))
+ {
+ DBG1("serial numbers do not match");
+ goto failed;
+ }
+ break;
+ case PKCS7_ENCRYPTION_ALG:
+ {
+ int alg = parse_algorithmIdentifier(object, level, NULL);
+
+ if (alg != OID_RSA_ENCRYPTION)
+ {
+ DBG1("only rsa encryption supported");
+ goto failed;
+ }
+ }
+ break;
+ case PKCS7_ENCRYPTED_KEY:
+ if (key->pkcs1_decrypt(key, object, &symmetric_key) != SUCCESS)
+ {
+ DBG1("symmetric key could not be decrypted with rsa");
+ goto failed;
+ }
+ DBG4("symmetric key : %B", &symmetric_key);
+ break;
+ case PKCS7_CONTENT_TYPE:
+ if (known_oid(object) != OID_PKCS7_DATA)
+ {
+ DBG1("encrypted content not of type pkcs7 data");
+ goto failed;
+ }
+ break;
+ case PKCS7_CONTENT_ENC_ALGORITHM:
+ {
+ int alg = parse_algorithmIdentifier(object, level, &iv);
+
+ switch (alg)
+ {
+ case OID_DES_CBC:
+ crypter = crypter_create(ENCR_DES, 0);
+ break;
+ case OID_3DES_EDE_CBC:
+ crypter = crypter_create(ENCR_3DES, 0);
+ break;
+ default:
+ DBG1("Only DES and 3DES supported for symmetric encryption");
+ goto failed;
+ }
+ if (symmetric_key.len != crypter->get_key_size(crypter))
+ {
+ DBG1("symmetric key has wrong length");
+ goto failed;
+ }
+ if (!parse_asn1_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV"))
+ {
+ DBG1("IV could not be parsed");
+ goto failed;
+ }
+ if (iv.len != crypter->get_block_size(crypter))
+ {
+ DBG1("IV has wrong length");
+ goto failed;
+ }
+ }
+ break;
+ case PKCS7_ENCRYPTED_CONTENT:
+ encrypted_content = object;
+ break;
+ }
+ objectID++;
+ }
+
+ /* decrypt the content */
+ crypter->decrypt(crypter, encrypted_content, iv, &this->data);
+ DBG4("decrypted content with padding: %B", &this->data);
+
+ /* remove the padding */
+ {
+ u_char *pos = this->data.ptr + this->data.len - 1;
+ u_char pattern = *pos;
+ size_t padding = pattern;
+
+ if (padding > this->data.len)
+ {
+ DBG1("padding greater than data length");
+ goto failed;
+ }
+ this->data.len -= padding;
+
+ while (padding-- > 0)
+ {
+ if (*pos-- != pattern)
+ {
+ DBG1("wrong padding pattern");
+ goto failed;
+ }
+ }
+ }
+ crypter->destroy(crypter);
+ free(symmetric_key.ptr);
+ return TRUE;
+
+failed:
+ DESTROY_IF(crypter);
+ free(symmetric_key.ptr);
+ chunk_free(&this->data);
+ return FALSE;
+}
+
+/**
+ * Implements pkcs7_t.get_data
+ */
+static chunk_t get_data(private_pkcs7_t *this)
+{
+ return this->data;
+}
+
+/**
+ * Implements pkcs_t.create_crluri_iterator
+ */
+static iterator_t *create_certificate_iterator(const private_pkcs7_t *this)
+{
+ return this->certs->create_iterator(this->certs, TRUE);
+}
+
+/**
+ * Implements pkcs7_t.destroy
+ */
+static void destroy(private_pkcs7_t *this)
+{
+ this->certs->destroy_offset(this->certs, offsetof(x509_t, destroy));
+ free(this->data.ptr);
+ free(this);
+}
+
+/**
+ * Parse PKCS#7 contentInfo object
+ */
+static bool parse_contentInfo(chunk_t blob, u_int level0, private_pkcs7_t *cInfo)
+{
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+
+ asn1_init(&ctx, blob, level0, FALSE, FALSE);
+
+ while (objectID < PKCS7_INFO_ROOF)
+ {
+ if (!extract_object(contentInfoObjects, &objectID, &object, &level, &ctx))
+ {
+ return FALSE;
+ }
+
+ if (objectID == PKCS7_INFO_TYPE)
+ {
+ cInfo->type = known_oid(object);
+ if (cInfo->type < OID_PKCS7_DATA
+ || cInfo->type > OID_PKCS7_ENCRYPTED_DATA)
+ {
+ DBG1("unknown pkcs7 content type");
+ return FALSE;
+ }
+ }
+ else if (objectID == PKCS7_INFO_CONTENT)
+ {
+ cInfo->content = object;
+ }
+ objectID++;
+ }
+ return TRUE;
+}
+
+/*
+ * Described in header.
+ */
+pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
+{
+ private_pkcs7_t *this = malloc_thing(private_pkcs7_t);
+
+ /* initialize */
+ this->type = OID_UNKNOWN;
+ this->content = chunk_empty;
+ this->parsed = FALSE;
+ this->level = level + 2;
+ this->data = chunk_empty;
+ this->attributes = chunk_empty;
+ this->certs = linked_list_create();
+
+ /*public functions */
+ this->public.is_data = (bool (*) (pkcs7_t*))is_data;
+ this->public.is_signedData = (bool (*) (pkcs7_t*))is_signedData;
+ this->public.is_envelopedData = (bool (*) (pkcs7_t*))is_envelopedData;
+ this->public.parse_data = (bool (*) (pkcs7_t*))parse_data;
+ 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.create_certificate_iterator = (iterator_t* (*) (pkcs7_t*))create_certificate_iterator;
+ this->public.destroy = (void (*) (pkcs7_t*))destroy;
+
+ if (!parse_contentInfo(chunk, level, this))
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
diff --git a/src/libstrongswan/crypto/pkcs7.h b/src/libstrongswan/crypto/pkcs7.h
new file mode 100644
index 000000000..c8434225a
--- /dev/null
+++ b/src/libstrongswan/crypto/pkcs7.h
@@ -0,0 +1,132 @@
+/**
+ * @file pkcs7.h
+ *
+ * @brief Interface of pkcs7_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Copyright (C) 2002-2007 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 3302 2007-10-12 21:57:20Z andreas $
+ */
+
+#ifndef _PKCS7_H
+#define _PKCS7_H
+
+typedef struct pkcs7_t pkcs7_t;
+
+#include <library.h>
+#include <crypto/x509.h>
+#include <crypto/rsa/rsa_private_key.h>
+#include <utils/iterator.h>
+
+/**
+ * @brief PKCS#7 contentInfo object.
+ *
+ * @b Constructors:
+ * -pkcs7_create_from_chunk()
+ *
+ * @ingroup crypto
+ */
+struct pkcs7_t {
+ /**
+ * @brief Check if the PKCS#7 contentType is data
+ *
+ * @param this calling object
+ * @return TRUE if the contentType is data
+ */
+ bool (*is_data) (pkcs7_t *this);
+
+ /**
+ * @brief Check if the PKCS#7 contentType is signedData
+ *
+ * @param this calling object
+ * @return TRUE if the contentType is signedData
+ */
+ bool (*is_signedData) (pkcs7_t *this);
+
+ /**
+ * @brief Check if the PKCS#7 contentType is envelopedData
+ *
+ * @param this calling object
+ * @return TRUE if the contentType is envelopedData
+ */
+ bool (*is_envelopedData) (pkcs7_t *this);
+
+ /**
+ * @brief Parse a PKCS#7 data content.
+ *
+ * @param this calling object
+ * @return TRUE if parsing was successful
+ */
+ bool (*parse_data) (pkcs7_t *this);
+
+ /**
+ * @brief Parse a PKCS#7 signedData content.
+ *
+ * @param this calling object
+ * @param cacert cacert used to verify the signature
+ * @return TRUE if parsing was successful
+ */
+ bool (*parse_signedData) (pkcs7_t *this, x509_t *cacert);
+
+ /**
+ * @brief Parse a PKCS#7 envelopedData content.
+ *
+ * @param this calling object
+ * @param serialNumber serialNumber of the request
+ * @param key RSA private key used to decrypt the symmetric key
+ * @return TRUE if parsing was successful
+ */
+ bool (*parse_envelopedData) (pkcs7_t *this, chunk_t serialNumber, rsa_private_key_t *key);
+
+ /**
+ * @brief Returns the parsed data object
+ *
+ * @param this calling object
+ * @return chunk containing the data object
+ */
+ chunk_t (*get_data) (pkcs7_t *this);
+
+ /**
+ * @brief Create an iterator for the certificates.
+ *
+ * @param this calling object
+ * @return iterator for the certificates
+ */
+ iterator_t *(*create_certificate_iterator) (pkcs7_t *this);
+
+ /**
+ * @brief Destroys the contentInfo object.
+ *
+ * @param this PKCS#7 contentInfo object to destroy
+ */
+ void (*destroy) (pkcs7_t *this);
+};
+
+/**
+ * @brief Read a PKCS#7 contentInfo object from a DER encoded chunk.
+ *
+ * @param chunk chunk containing DER encoded data
+ * @param level ASN.1 parsing start level
+ * @return created pkcs7_contentInfo object, or NULL if invalid.
+ *
+ * @ingroup crypto
+ */
+pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level);
+
+#endif /* _PKCS7_H */
diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.c b/src/libstrongswan/crypto/rsa/rsa_private_key.c
index 5b1647965..ec2f2fc74 100644
--- a/src/libstrongswan/crypto/rsa/rsa_private_key.c
+++ b/src/libstrongswan/crypto/rsa/rsa_private_key.c
@@ -19,6 +19,8 @@
* 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: rsa_private_key.c 3306 2007-10-17 02:55:53Z andreas $
*/
#include <gmp.h>
@@ -29,33 +31,21 @@
#include "rsa_public_key.h"
#include "rsa_private_key.h"
+#include <debug.h>
#include <asn1/asn1.h>
#include <asn1/pem.h>
#include <utils/randomizer.h>
/**
- * OIDs for hash algorithms are defined in rsa_public_key.c.
- */
-extern u_int8_t md2_oid[18];
-extern u_int8_t md5_oid[18];
-extern u_int8_t sha1_oid[15];
-extern u_int8_t sha256_oid[19];
-extern u_int8_t sha384_oid[19];
-extern u_int8_t sha512_oid[19];
-
-
-/**
* defined in rsa_public_key.c
*/
extern chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e);
-
/**
* Public exponent to use for key generation.
*/
#define PUBLIC_EXPONENT 0x10001
-
typedef struct private_rsa_private_key_t private_rsa_private_key_t;
/**
@@ -153,23 +143,23 @@ struct private_rsa_private_key_t {
/* ASN.1 definition of a PKCS#1 RSA private key */
static const asn1Object_t privkey_objects[] = {
- { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
- { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
- { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
- { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
- { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
- { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
- { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
- { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
- { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
- { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
- ASN1_LOOP }, /* 10 */
- { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
- { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
- { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
- { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
- { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */
+ { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
+ { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
+ { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
+ { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
+ { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
+ { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
+ ASN1_LOOP }, /* 10 */
+ { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
+ { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
+ { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
+ { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
+ { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */
};
#define PRIV_KEY_VERSION 1
@@ -186,6 +176,26 @@ static const asn1Object_t privkey_objects[] = {
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
+ */
+static void mpz_clear_randomized(mpz_t z)
+{
+ size_t len = mpz_size(z) * GMP_LIMB_BITS / BITS_PER_BYTE;
+ u_int8_t *random_bytes = alloca(len);
+
+ randomizer_t *randomizer = randomizer_create();
+
+ randomizer->get_pseudo_random_bytes(randomizer, len, random_bytes);
+
+ /* overwrite mpz_t with pseudo-random bytes before clearing it */
+ mpz_import(z, len, 1, 1, 1, 0, random_bytes);
+ mpz_clear(z);
+
+ randomizer->destroy(randomizer);
+}
+
+/**
* Implementation of private_rsa_private_key_t.compute_prime.
*/
static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_size, mpz_t *prime)
@@ -216,7 +226,8 @@ static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_size
/* get next prime */
mpz_nextprime (*prime, *prime);
- free(random_bytes.ptr);
+ /* free the random_bytes after overwriting them with a pseudo-random sequence */
+ chunk_free_randomized(&random_bytes);
}
/* check if it isnt too large */
while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size);
@@ -251,59 +262,96 @@ static chunk_t rsadp(private_rsa_private_key_t *this, chunk_t data)
decrypted.len = this->k;
decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1);
- mpz_clear(t1);
- mpz_clear(t2);
+ mpz_clear_randomized(t1);
+ mpz_clear_randomized(t2);
return decrypted;
}
/**
- * Implementation of rsa_private_key.build_emsa_signature.
+ * Implementation of rsa_private_key_t.eme_pkcs1_decrypt.
*/
-static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this, hash_algorithm_t hash_algorithm, chunk_t data, chunk_t *signature)
+static status_t pkcs1_decrypt(private_rsa_private_key_t *this,
+ chunk_t in, chunk_t *out)
+{
+ status_t status = FAILED;
+ chunk_t em, em_ori;
+
+ /* decrypt the input data */
+ em = em_ori = this->rsadp(this, in);
+
+ /* PKCS#1 v1.5 EME encryption formatting
+ * EM = 00 || 02 || PS || 00 || M
+ * PS = pseudo-random nonzero octets
+ */
+
+ /* check for magic bytes */
+ if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x02)
+ {
+ DBG1("incorrect padding - probably wrong RSA key");
+ goto end;
+ }
+ em.ptr += 2;
+ em.len -= 2;
+
+ /* the plaintext data starts after first 0x00 byte */
+ while (em.len-- > 0 && *em.ptr++ != 0x00);
+
+ if (em.len == 0)
+ {
+ DBG1("no plaintext data found");
+ goto end;
+ }
+
+ *out = chunk_clone(em);
+ status = SUCCESS;
+
+end:
+ free(em_ori.ptr);
+ return status;
+}
+
+/**
+ * Implementation of rsa_private_key_t.build_emsa_pkcs1_signature.
+ */
+static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this,
+ hash_algorithm_t hash_algorithm,
+ chunk_t data, chunk_t *signature)
{
hasher_t *hasher;
- chunk_t hash;
- chunk_t em;
- chunk_t oid;
+ chunk_t em, digestInfo, hash_id, hash;
/* get oid string prepended to hash */
switch (hash_algorithm)
{
case HASH_MD2:
{
- oid.ptr = md2_oid;
- oid.len = sizeof(md2_oid);
+ hash_id =ASN1_md2_id;
break;
}
case HASH_MD5:
{
- oid.ptr = md5_oid;
- oid.len = sizeof(md5_oid);
+ hash_id = ASN1_md5_id;
break;
}
case HASH_SHA1:
{
- oid.ptr = sha1_oid;
- oid.len = sizeof(sha1_oid);
+ hash_id = ASN1_sha1_id;
break;
}
case HASH_SHA256:
{
- oid.ptr = sha256_oid;
- oid.len = sizeof(sha256_oid);
+ hash_id = ASN1_sha256_id;
break;
}
case HASH_SHA384:
{
- oid.ptr = sha384_oid;
- oid.len = sizeof(sha384_oid);
+ hash_id = ASN1_sha384_id;
break;
}
case HASH_SHA512:
{
- oid.ptr = sha512_oid;
- oid.len = sizeof(sha512_oid);
+ hash_id = ASN1_sha512_id;
break;
}
default:
@@ -323,10 +371,17 @@ static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this, hash
hasher->allocate_hash(hasher, data, &hash);
hasher->destroy(hasher);
+ /* build DER-encoded digestInfo */
+ digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
+ hash_id,
+ asn1_simple_object(ASN1_OCTET_STRING, hash)
+ );
+ chunk_free(&hash);
+
/* build chunk to rsa-decrypt:
* EM = 0x00 || 0x01 || PS || 0x00 || T.
* PS = 0xFF padding, with length to fill em
- * T = oid || hash
+ * T = encoded_hash
*/
em.len = this->k;
em.ptr = malloc(em.len);
@@ -336,78 +391,44 @@ static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this, hash
/* set magic bytes */
*(em.ptr) = 0x00;
*(em.ptr+1) = 0x01;
- *(em.ptr + em.len - hash.len - oid.len - 1) = 0x00;
- /* set hash */
- memcpy(em.ptr + em.len - hash.len, hash.ptr, hash.len);
- /* set oid */
- memcpy(em.ptr + em.len - hash.len - oid.len, oid.ptr, oid.len);
-
+ *(em.ptr + em.len - digestInfo.len - 1) = 0x00;
+ /* set DER-encoded hash */
+ memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len);
+
/* build signature */
*signature = this->rsasp1(this, em);
- free(hash.ptr);
+ free(digestInfo.ptr);
free(em.ptr);
return SUCCESS;
}
/**
- * Implementation of rsa_private_key.get_key.
+ * Implementation of rsa_private_key_t.pkcs1_write.
*/
-static status_t get_key(private_rsa_private_key_t *this, chunk_t *key)
-{
- chunk_t n, e, p, q, d, exp1, exp2, coeff;
-
- n.len = this->k;
- n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
- e.len = this->k;
- e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
- p.len = this->k;
- p.ptr = mpz_export(NULL, NULL, 1, p.len, 1, 0, this->p);
- q.len = this->k;
- q.ptr = mpz_export(NULL, NULL, 1, q.len, 1, 0, this->q);
- d.len = this->k;
- d.ptr = mpz_export(NULL, NULL, 1, d.len, 1, 0, this->d);
- exp1.len = this->k;
- exp1.ptr = mpz_export(NULL, NULL, 1, exp1.len, 1, 0, this->exp1);
- exp2.len = this->k;
- exp2.ptr = mpz_export(NULL, NULL, 1, exp2.len, 1, 0, this->exp2);
- coeff.len = this->k;
- coeff.ptr = mpz_export(NULL, NULL, 1, coeff.len, 1, 0, this->coeff);
-
- key->len = this->k * 8;
- key->ptr = malloc(key->len);
- memcpy(key->ptr + this->k * 0, n.ptr , n.len);
- memcpy(key->ptr + this->k * 1, e.ptr, e.len);
- memcpy(key->ptr + this->k * 2, p.ptr, p.len);
- memcpy(key->ptr + this->k * 3, q.ptr, q.len);
- memcpy(key->ptr + this->k * 4, d.ptr, d.len);
- memcpy(key->ptr + this->k * 5, exp1.ptr, exp1.len);
- memcpy(key->ptr + this->k * 6, exp2.ptr, exp2.len);
- memcpy(key->ptr + this->k * 7, coeff.ptr, coeff.len);
-
- free(n.ptr);
- free(e.ptr);
- free(p.ptr);
- free(q.ptr);
- free(d.ptr);
- free(exp1.ptr);
- free(exp2.ptr);
- free(coeff.ptr);
-
- return SUCCESS;
-}
-
-/**
- * Implementation of rsa_private_key.save_key.
- */
-static status_t save_key(private_rsa_private_key_t *this, char *file)
+static bool pkcs1_write(private_rsa_private_key_t *this, const char *filename, bool force)
{
- return NOT_SUPPORTED;
+ bool status;
+
+ chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm",
+ ASN1_INTEGER_0,
+ asn1_integer_from_mpz(this->n),
+ asn1_integer_from_mpz(this->e),
+ asn1_integer_from_mpz(this->d),
+ asn1_integer_from_mpz(this->p),
+ asn1_integer_from_mpz(this->q),
+ asn1_integer_from_mpz(this->exp1),
+ asn1_integer_from_mpz(this->exp2),
+ asn1_integer_from_mpz(this->coeff));
+
+ status = chunk_write(pkcs1, filename, "pkcs1", 0066, force);
+ chunk_free_randomized(&pkcs1);
+ return status;
}
/**
- * Implementation of rsa_private_key.get_public_key.
+ * Implementation of rsa_private_key_t.get_public_key.
*/
rsa_public_key_t *get_public_key(private_rsa_private_key_t *this)
{
@@ -510,47 +531,26 @@ static status_t check(private_rsa_private_key_t *this)
status = FAILED;
}
- mpz_clear(t);
- mpz_clear(u);
- mpz_clear(q1);
+ mpz_clear_randomized(t);
+ mpz_clear_randomized(u);
+ mpz_clear_randomized(q1);
return status;
}
/**
- * Implementation of rsa_private_key.clone.
- */
-static rsa_private_key_t* _clone(private_rsa_private_key_t *this)
-{
- private_rsa_private_key_t *clone = rsa_private_key_create_empty();
-
- mpz_init_set(clone->n, this->n);
- mpz_init_set(clone->e, this->e);
- mpz_init_set(clone->p, this->p);
- mpz_init_set(clone->q, this->q);
- mpz_init_set(clone->d, this->d);
- mpz_init_set(clone->exp1, this->exp1);
- mpz_init_set(clone->exp2, this->exp2);
- mpz_init_set(clone->coeff, this->coeff);
- clone->keyid = chunk_clone(this->keyid);
- clone->k = this->k;
-
- return &clone->public;
-}
-
-/**
* Implementation of rsa_private_key.destroy.
*/
static void destroy(private_rsa_private_key_t *this)
{
- mpz_clear(this->n);
- mpz_clear(this->e);
- mpz_clear(this->p);
- mpz_clear(this->q);
- mpz_clear(this->d);
- mpz_clear(this->exp1);
- mpz_clear(this->exp2);
- mpz_clear(this->coeff);
- free(this->keyid.ptr);
+ mpz_clear_randomized(this->n);
+ mpz_clear_randomized(this->e);
+ mpz_clear_randomized(this->p);
+ mpz_clear_randomized(this->q);
+ mpz_clear_randomized(this->d);
+ mpz_clear_randomized(this->exp1);
+ mpz_clear_randomized(this->exp2);
+ mpz_clear_randomized(this->coeff);
+ chunk_free_randomized(&this->keyid);
free(this);
}
@@ -562,12 +562,11 @@ static private_rsa_private_key_t *rsa_private_key_create_empty(void)
private_rsa_private_key_t *this = malloc_thing(private_rsa_private_key_t);
/* public functions */
+ this->public.pkcs1_decrypt = (status_t (*) (rsa_private_key_t*,chunk_t,chunk_t*))pkcs1_decrypt;
this->public.build_emsa_pkcs1_signature = (status_t (*) (rsa_private_key_t*,hash_algorithm_t,chunk_t,chunk_t*))build_emsa_pkcs1_signature;
- this->public.get_key = (status_t (*) (rsa_private_key_t*,chunk_t*))get_key;
- this->public.save_key = (status_t (*) (rsa_private_key_t*,char*))save_key;
- this->public.get_public_key = (rsa_public_key_t *(*) (rsa_private_key_t*))get_public_key;
+ this->public.pkcs1_write = (bool (*) (rsa_private_key_t*,const char*,bool))pkcs1_write;
+ this->public.get_public_key = (rsa_public_key_t* (*) (rsa_private_key_t*))get_public_key;
this->public.belongs_to = (bool (*) (rsa_private_key_t*,rsa_public_key_t*))belongs_to;
- this->public.clone = (rsa_private_key_t*(*)(rsa_private_key_t*))_clone;
this->public.destroy = (void (*) (rsa_private_key_t*))destroy;
/* private functions */
@@ -575,6 +574,8 @@ static private_rsa_private_key_t *rsa_private_key_create_empty(void)
this->rsasp1 = rsadp; /* same algorithm */
this->compute_prime = compute_prime;
+ this->keyid = chunk_empty;
+
return this;
}
@@ -613,9 +614,7 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
/* Swapping Primes so p is larger then q */
if (mpz_cmp(p, q) < 0)
{
- mpz_set(t, p);
- mpz_set(p, q);
- mpz_set(q, t);
+ mpz_swap(p, q);
}
mpz_mul(n, p, q); /* n = p*q */
@@ -645,9 +644,9 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
mpz_add(coeff, coeff, p);
}
- mpz_clear(q1);
- mpz_clear(m);
- mpz_clear(t);
+ mpz_clear_randomized(q1);
+ mpz_clear_randomized(m);
+ mpz_clear_randomized(t);
/* apply values */
*(this->p) = *p;
@@ -733,7 +732,7 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
objectID++;
}
- this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
/* form the keyid as a SHA-1 hash of a publicKeyInfo object */
{
@@ -769,6 +768,6 @@ rsa_private_key_t *rsa_private_key_create_from_file(char *filename, chunk_t *pas
return NULL;
key = rsa_private_key_create_from_chunk(chunk);
- free(chunk.ptr);
+ chunk_free_randomized(&chunk);
return key;
}
diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.h b/src/libstrongswan/crypto/rsa/rsa_private_key.h
index 9ec07704e..e5cf49810 100644
--- a/src/libstrongswan/crypto/rsa/rsa_private_key.h
+++ b/src/libstrongswan/crypto/rsa/rsa_private_key.h
@@ -19,6 +19,8 @@
* 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: rsa_private_key.h 3296 2007-10-12 15:23:29Z andreas $
*/
#ifndef RSA_PRIVATE_KEY_H_
@@ -42,13 +44,24 @@ typedef struct rsa_private_key_t rsa_private_key_t;
*
* @see rsa_public_key_t
*
- * @todo Implement get_key(), save_key(), get_public_key()
- *
* @ingroup rsa
*/
struct rsa_private_key_t {
/**
+ * @brief Decrypt a data block based on EME-PKCS1 encoding.
+ *
+ *
+ * @param this calling object
+ * @param data encrypted input data
+ * @param out decrypted output data
+ * @return
+ * - SUCCESS
+ * - FAILED if padding is not correct
+ */
+ status_t (*pkcs1_decrypt) (rsa_private_key_t *this, chunk_t in, chunk_t *out);
+
+ /**
* @brief Build a signature over a chunk using EMSA-PKCS1 encoding.
*
* This signature creates a hash using the specified hash algorithm, concatenates
@@ -67,45 +80,17 @@ struct rsa_private_key_t {
status_t (*build_emsa_pkcs1_signature) (rsa_private_key_t *this, hash_algorithm_t hash_algorithm, chunk_t data, chunk_t *signature);
/**
- * @brief Gets the key.
- *
- * UNIMPLEMENTED!
- *
+ * @brief Writes an RSA private key to a file in PKCS#1 format.
+ *
* @param this calling object
- * @param key key (in a propriarity format)
- * @return
- * - SUCCESS
- * - INVALID_STATE, if key not set
+ * @param filename file to which the key should be written.
+ * @param force if TRUE overwrite existing file
+ * @return TRUE if successful - FALSE otherwise
*/
- status_t (*get_key) (rsa_private_key_t *this, chunk_t *key);
+ bool (*pkcs1_write) (rsa_private_key_t *this, const char *filename, bool force);
/**
- * @brief Saves a key to a file.
- *
- * Not implemented!
- *
- * @param this calling object
- * @param file file to which the key should be written.
- * @return NOT_SUPPORTED
- */
- status_t (*save_key) (rsa_private_key_t *this, char *file);
-
- /**
- * @brief Generate a new key.
- *
- * Generates a new private_key with specified key size
- *
- * @param this calling object
- * @param key_size size of the key in bits
- * @return
- * - SUCCESS
- * - INVALID_ARG if key_size invalid
- */
- status_t (*generate_key) (rsa_private_key_t *this, size_t key_size);
-
- /**
- * @brief Create a rsa_public_key_t with the public
- * parts of the key.
+ * @brief Create a rsa_public_key_t with the public part of the key.
*
* @param this calling object
* @return public_key
@@ -125,14 +110,6 @@ struct rsa_private_key_t {
bool (*belongs_to) (rsa_private_key_t *this, rsa_public_key_t *public);
/**
- * @brief Clone the private key.
- *
- * @param this private key to clone
- * @return clone of this
- */
- rsa_private_key_t *(*clone) (rsa_private_key_t *this);
-
- /**
* @brief Destroys the private key.
*
* @param this private key to destroy
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c
index 38899670f..6f2158d2b 100644
--- a/src/libstrongswan/crypto/rsa/rsa_public_key.c
+++ b/src/libstrongswan/crypto/rsa/rsa_public_key.c
@@ -19,6 +19,8 @@
* 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: rsa_public_key.c 3303 2007-10-12 22:49:39Z andreas $
*/
#include <gmp.h>
@@ -29,74 +31,13 @@
#include "rsa_public_key.h"
+#include <debug.h>
#include <crypto/hashers/hasher.h>
#include <asn1/asn1.h>
#include <asn1/pem.h>
-/*
- * For simplicity, we use these predefined values for hash algorithm OIDs
- * These also contain the length of the appended hash
- * These values are also used in rsa_private_key.c.
- */
-
-const u_int8_t md2_oid[] = {
- 0x30,0x20,
- 0x30,0x0c,
- 0x06,0x08,
- 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,
- 0x05,0x00,
- 0x04,0x10
-};
-
-const u_int8_t md5_oid[] = {
- 0x30,0x20,
- 0x30,0x0c,
- 0x06,0x08,
- 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,
- 0x05,0x00,
- 0x04,0x10
-};
-
-const u_int8_t sha1_oid[] = {
- 0x30,0x21,
- 0x30,0x09,
- 0x06,0x05,
- 0x2b,0x0e,0x03,0x02,0x1a,
- 0x05,0x00,
- 0x04,0x14
-};
-
-const u_int8_t sha256_oid[] = {
- 0x30,0x31,
- 0x30,0x0d,
- 0x06,0x09,
- 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,
- 0x05,0x00,
- 0x04,0x20
-};
-
-const u_int8_t sha384_oid[] = {
- 0x30,0x41,
- 0x30,0x0d,
- 0x06,0x09,
- 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,
- 0x05,0x00,
- 0x04,0x30
-};
-
-const u_int8_t sha512_oid[] = {
- 0x30,0x51,
- 0x30,0x0d,
- 0x06,0x09,
- 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,
- 0x05,0x00,
- 0x04,0x40
-};
-
-#define LARGEST_HASH_OID_SIZE sizeof(sha512_oid)
-
-/* ASN.1 definition public key */
-static const asn1Object_t pubkey_objects[] = {
+/* ASN.1 definition of RSApublicKey */
+static const asn1Object_t pubkeyObjects[] = {
{ 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */
{ 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */
@@ -107,6 +48,18 @@ static const asn1Object_t pubkey_objects[] = {
#define PUB_KEY_EXPONENT 2
#define PUB_KEY_ROOF 3
+/* ASN.1 definition of digestInfo */
+static const asn1Object_t digestInfoObjects[] = {
+ { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
+};
+
+#define DIGEST_INFO 0
+#define DIGEST_INFO_ALGORITHM 1
+#define DIGEST_INFO_DIGEST 2
+#define DIGEST_INFO_ROOF 3
+
typedef struct private_rsa_public_key_t private_rsa_public_key_t;
/**
@@ -186,12 +139,11 @@ static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data)
/**
* Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
*/
-static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, chunk_t data, chunk_t signature)
+static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this,
+ hash_algorithm_t algorithm,
+ chunk_t data, chunk_t signature)
{
- hasher_t *hasher = NULL;
- chunk_t hash;
- chunk_t em;
- u_int8_t *pos;
+ chunk_t em_ori, em;
status_t res = FAILED;
/* remove any preceding 0-bytes from signature */
@@ -207,7 +159,7 @@ static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this
}
/* unpack signature */
- em = this->rsavp1(this, signature);
+ em_ori = em = this->rsavp1(this, signature);
/* result should look like this:
* EM = 0x00 || 0x01 || PS || 0x00 || T.
@@ -216,141 +168,160 @@ static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this
*/
/* check magic bytes */
- if ((*(em.ptr) != 0x00) || (*(em.ptr+1) != 0x01))
+ if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01)
{
+ DBG2("incorrect padding - probably wrong RSA key");
goto end;
}
+ em.ptr += 2;
+ em.len -= 2;
/* find magic 0x00 */
- pos = em.ptr + 2;
- while (pos <= em.ptr + em.len)
+ while (em.len > 0)
{
- if (*pos == 0x00)
+ if (*em.ptr == 0x00)
{
/* found magic byte, stop */
- pos++;
+ em.ptr++;
+ em.len--;
break;
}
- else if (*pos != 0xFF)
+ else if (*em.ptr != 0xFF)
{
/* bad padding, decryption failed ?!*/
goto end;
}
- pos++;
+ em.ptr++;
+ em.len--;
}
- if (pos + LARGEST_HASH_OID_SIZE > em.ptr + em.len)
- {
- /* not enought room for oid compare */
- goto end;
- }
-
- if (memeq(md2_oid, pos, sizeof(md2_oid)))
- {
- hasher = hasher_create(HASH_MD2);
- pos += sizeof(md2_oid);
- }
- else if (memeq(md5_oid, pos, sizeof(md5_oid)))
+ if (em.len == 0)
{
- hasher = hasher_create(HASH_MD5);
- pos += sizeof(md5_oid);
- }
- else if (memeq(sha1_oid, pos, sizeof(sha1_oid)))
- {
- hasher = hasher_create(HASH_SHA1);
- pos += sizeof(sha1_oid);
- }
- else if (memeq(sha256_oid, pos, sizeof(sha256_oid)))
- {
- hasher = hasher_create(HASH_SHA256);
- pos += sizeof(sha256_oid);
- }
- else if (memeq(sha384_oid, pos, sizeof(sha384_oid)))
- {
- hasher = hasher_create(HASH_SHA384);
- pos += sizeof(sha384_oid);
- }
- else if (memeq(sha512_oid, pos, sizeof(sha512_oid)))
- {
- hasher = hasher_create(HASH_SHA512);
- pos += sizeof(sha512_oid);
- }
-
- if (hasher == NULL)
- {
- /* unsupported hash algorithm */
- res = NOT_SUPPORTED;;
+ /* no digestInfo found */
goto end;
}
-
- if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len)
+
+ /* parse ASN.1-based digestInfo */
{
- /* bad length */
- hasher->destroy(hasher);
- goto end;
+ asn1_ctx_t ctx;
+ chunk_t object;
+ u_int level;
+ int objectID = 0;
+ hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
+
+ asn1_init(&ctx, em, 0, FALSE, FALSE);
+
+ while (objectID < DIGEST_INFO_ROOF)
+ {
+ if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx))
+ {
+ goto end;
+ }
+ switch (objectID)
+ {
+ case DIGEST_INFO:
+ if (em.len > object.len)
+ {
+ DBG1("digestInfo field in signature is followed by %u surplus bytes",
+ em.len - object.len);
+ goto end;
+ }
+ break;
+ case DIGEST_INFO_ALGORITHM:
+ {
+ int hash_oid = parse_algorithmIdentifier(object, level+1, NULL);
+
+ hash_algorithm = hasher_algorithm_from_oid(hash_oid);
+ if (hash_algorithm == HASH_UNKNOWN
+ || (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
+ {
+ DBG1("wrong hash algorithm used in signature");
+ goto end;
+ }
+ }
+ break;
+ case DIGEST_INFO_DIGEST:
+ {
+ chunk_t hash;
+ hasher_t *hasher = hasher_create(hash_algorithm);
+
+ if (object.len != hasher->get_hash_size(hasher))
+ {
+ DBG1("hash size in signature is %u bytes instead of %u bytes",
+ object.len, hasher->get_hash_size(hasher));
+ hasher->destroy(hasher);
+ goto end;
+ }
+
+ /* build our own hash */
+ hasher->allocate_hash(hasher, data, &hash);
+ hasher->destroy(hasher);
+
+ /* compare the hashes */
+ res = memeq(object.ptr, hash.ptr, hash.len) ? SUCCESS : FAILED;
+ free(hash.ptr);
+ }
+ break;
+ default:
+ break;
+ }
+ objectID++;
+ }
}
-
- /* build our own hash */
- hasher->allocate_hash(hasher, data, &hash);
- hasher->destroy(hasher);
-
- /* compare the hashes */
- res = memeq(hash.ptr, pos, hash.len) ? SUCCESS : FAILED;
- free(hash.ptr);
end:
- free(em.ptr);
+ free(em_ori.ptr);
return res;
}
-
+
+
/**
- * Implementation of rsa_public_key.get_key.
+ * Implementation of rsa_public_key_t.get_modulus.
*/
-static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key)
-{
- chunk_t n, e;
-
- n.len = this->k;
- n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
- e.len = this->k;
- e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
-
- key->len = this->k * 2;
- key->ptr = malloc(key->len);
- memcpy(key->ptr, n.ptr, n.len);
- memcpy(key->ptr + n.len, e.ptr, e.len);
- free(n.ptr);
- free(e.ptr);
-
- return SUCCESS;
+static mpz_t *get_modulus(const private_rsa_public_key_t *this)
+{
+ return (mpz_t*)&this->n;
}
/**
- * Implementation of rsa_public_key.save_key.
+ * Implementation of rsa_public_key_t.get_keysize.
*/
-static status_t save_key(const private_rsa_public_key_t *this, char *file)
+static size_t get_keysize(const private_rsa_public_key_t *this)
{
- return NOT_SUPPORTED;
+ return this->k;
}
/**
- * Implementation of rsa_public_key.get_modulus.
+ * Build a DER-encoded publicKeyInfo object from an RSA public key.
+ * Also used in rsa_private_key.c.
*/
-static mpz_t *get_modulus(const private_rsa_public_key_t *this)
+chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e)
{
- return (mpz_t*)&this->n;
+ chunk_t rawKey = 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);
+
+ *pos++ = 0x00;
+ memcpy(pos, rawKey.ptr, rawKey.len);
+ free(rawKey.ptr);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id,
+ publicKey);
}
/**
- * Implementation of rsa_public_key.get_keysize.
+ * Implementation of rsa_public_key_t.get_publicKeyInfo.
*/
-static size_t get_keysize(const private_rsa_public_key_t *this)
+static chunk_t get_publicKeyInfo(const private_rsa_public_key_t *this)
{
- return this->k;
+ return rsa_public_key_info_to_asn1(this->n, this->e);
}
/**
- * Implementation of rsa_public_key.get_keyid.
+ * Implementation of rsa_public_key_t.get_keyid.
*/
static chunk_t get_keyid(const private_rsa_public_key_t *this)
{
@@ -358,7 +329,7 @@ static chunk_t get_keyid(const private_rsa_public_key_t *this)
}
/**
- * Implementation of rsa_public_key.clone.
+ * Implementation of rsa_public_key_t.clone.
*/
static rsa_public_key_t* _clone(const private_rsa_public_key_t *this)
{
@@ -373,7 +344,7 @@ static rsa_public_key_t* _clone(const private_rsa_public_key_t *this)
}
/**
- * Implementation of rsa_public_key.destroy.
+ * Implementation of rsa_public_key_t.destroy.
*/
static void destroy(private_rsa_public_key_t *this)
{
@@ -391,11 +362,10 @@ 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.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
- this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key;
- this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key;
+ 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;
+ this->public.get_publicKeyInfo = (chunk_t (*) (const rsa_public_key_t*))get_publicKeyInfo;
this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid;
this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone;
this->public.destroy = (void (*) (rsa_public_key_t*))destroy;
@@ -407,27 +377,6 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void)
return this;
}
-/**
- * Build a DER-encoded publicKeyInfo object from an RSA public key.
- * Also used in rsa_private_key.c.
- */
-chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e)
-{
- chunk_t rawKey = 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);
-
- *pos++ = 0x00;
- memcpy(pos, rawKey.ptr, rawKey.len);
- free(rawKey.ptr);
-
- return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id,
- publicKey);
-}
-
/*
* See header
*/
@@ -447,7 +396,7 @@ rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob)
while (objectID < PUB_KEY_ROOF)
{
- if (!extract_object(pubkey_objects, &objectID, &object, &level, &ctx))
+ if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx))
{
destroy(this);
return FALSE;
@@ -489,8 +438,9 @@ rsa_public_key_t *rsa_public_key_create_from_file(char *filename)
rsa_public_key_t *pubkey = NULL;
if (!pem_asn1_load_file(filename, NULL, "public key", &chunk, &pgp))
+ {
return NULL;
-
+ }
pubkey = rsa_public_key_create_from_chunk(chunk);
free(chunk.ptr);
return pubkey;
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.h b/src/libstrongswan/crypto/rsa/rsa_public_key.h
index 1ee54dcc3..0a40c2204 100644
--- a/src/libstrongswan/crypto/rsa/rsa_public_key.h
+++ b/src/libstrongswan/crypto/rsa/rsa_public_key.h
@@ -19,6 +19,8 @@
* 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: rsa_public_key.h 3303 2007-10-12 22:49:39Z andreas $
*/
#ifndef RSA_PUBLIC_KEY_H_
@@ -29,6 +31,7 @@ typedef struct rsa_public_key_t rsa_public_key_t;
#include <gmp.h>
#include <library.h>
+#include <crypto/hashers/hasher.h>
/**
* @brief RSA public key with associated functions.
@@ -58,6 +61,7 @@ struct rsa_public_key_t {
*
* @param this rsa_public_key to use
* @param data data to sign
+ # @param algorithm hash algorithm the signature is based on
* @param signature signature to verify
* @return
* - SUCCESS, if signature ok
@@ -66,34 +70,9 @@ struct rsa_public_key_t {
* - INVALID_ARG, if signature is not a signature
* - FAILED if signature invalid or unable to verify
*/
- status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this, chunk_t data, chunk_t signature);
-
- /**
- * @brief Gets the key.
- *
- * Currently uses a proprietary format which is only inteded
- * for testing. This should be replaced with a proper
- * ASN1 encoded key format, when charon gets the ASN1
- * capabilities.
- *
- * @param this calling object
- * @param key key (in a propriarity format)
- * @return
- * - SUCCESS
- * - INVALID_STATE, if key not set
- */
- status_t (*get_key) (const rsa_public_key_t *this, chunk_t *key);
-
- /**
- * @brief Saves a key to a file.
- *
- * Not implemented!
- *
- * @param this calling object
- * @param file file to which the key should be written.
- * @return NOT_SUPPORTED
- */
- status_t (*save_key) (const rsa_public_key_t *this, char *file);
+ status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this,
+ hash_algorithm_t algorithm,
+ chunk_t data, chunk_t signature);
/**
* @brief Get the modulus of the key.
@@ -112,6 +91,14 @@ struct rsa_public_key_t {
size_t (*get_keysize) (const rsa_public_key_t *this);
/**
+ * @brief Get the DER encoded publicKeyInfo object.
+ *
+ * @param this calling object
+ * @return DER encoded publicKeyInfo object
+ */
+ chunk_t (*get_publicKeyInfo) (const rsa_public_key_t *this);
+
+ /**
* @brief Get the keyid formed as the SHA-1 hash of a publicKeyInfo object.
*
* @param this calling object
diff --git a/src/libstrongswan/crypto/signers/hmac_signer.c b/src/libstrongswan/crypto/signers/hmac_signer.c
index 76e1ce50e..ad5b882a6 100644
--- a/src/libstrongswan/crypto/signers/hmac_signer.c
+++ b/src/libstrongswan/crypto/signers/hmac_signer.c
@@ -52,14 +52,19 @@ struct private_hmac_signer_t {
/**
* Implementation of signer_t.get_signature.
*/
-static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer)
+static void get_signature(private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer)
{
- u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
-
- this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac);
-
- /* copy MAC depending on truncation */
- memcpy(buffer, full_mac, this->block_size);
+ if (buffer == NULL)
+ { /* append mode */
+ this->hmac_prf->get_bytes(this->hmac_prf, data, NULL);
+ }
+ else
+ {
+ u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
+
+ this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac);
+ memcpy(buffer, full_mac, this->block_size);
+ }
}
/**
@@ -67,18 +72,24 @@ static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t *
*/
static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk_t *chunk)
{
- chunk_t signature;
- u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
-
- this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac);
+ if (chunk == NULL)
+ { /* append mode */
+ this->hmac_prf->get_bytes(this->hmac_prf, data, NULL);
+ }
+ else
+ {
+ chunk_t signature;
+ u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
+
+ this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac);
- signature.ptr = malloc(this->block_size);
- signature.len = this->block_size;
-
- /* copy signature */
- memcpy(signature.ptr, full_mac, this->block_size);
+ signature.ptr = malloc(this->block_size);
+ signature.len = this->block_size;
+
+ memcpy(signature.ptr, full_mac, this->block_size);
- *chunk = signature;
+ *chunk = signature;
+ }
}
/**
diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h
index 0f3709712..4218e4146 100644
--- a/src/libstrongswan/crypto/signers/signer.h
+++ b/src/libstrongswan/crypto/signers/signer.h
@@ -74,6 +74,9 @@ extern enum_name_t *integrity_algorithm_names;
struct signer_t {
/**
* @brief Generate a signature.
+ *
+ * If buffer is NULL, data is processed and prepended to a next call until
+ * buffer is a valid pointer.
*
* @param this calling object
* @param data a chunk containing the data to sign
@@ -83,6 +86,9 @@ struct signer_t {
/**
* @brief Generate a signature and allocate space for it.
+ *
+ * If chunk is NULL, data is processed and prepended to a next call until
+ * chunk is a valid chunk pointer.
*
* @param this calling object
* @param data a chunk containing the data to sign
diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c
index 5bf3f26d7..d9093fc62 100755
--- a/src/libstrongswan/crypto/x509.c
+++ b/src/libstrongswan/crypto/x509.c
@@ -23,6 +23,8 @@
* 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: x509.c 3301 2007-10-12 21:56:30Z andreas $
*/
#include <gmp.h>
@@ -114,7 +116,7 @@ struct private_x509_t {
/**
* Signature algorithm
*/
- int sigAlg;
+ int signatureAlgorithm;
/**
* ID representing the certificate issuer
@@ -197,11 +199,6 @@ struct private_x509_t {
bool isOcspSigner;
/**
- * Signature algorithm (must be identical to sigAlg)
- */
- int algorithm;
-
- /**
* Signature
*/
chunk_t signature;
@@ -445,16 +442,15 @@ static bool parse_basicConstraints(chunk_t blob, int level0)
return isCA;
}
-/*
+/**
* extracts an otherName
*/
-static bool
-parse_otherName(chunk_t blob, int level0)
+static bool parse_otherName(chunk_t blob, int level0)
{
asn1_ctx_t ctx;
chunk_t object;
- int objectID = 0;
u_int level;
+ int objectID = 0;
int oid = OID_UNKNOWN;
asn1_init(&ctx, blob, level0, FALSE, FALSE);
@@ -484,7 +480,7 @@ parse_otherName(chunk_t blob, int level0)
return TRUE;
}
-/*
+/**
* extracts a generalName
*/
static identification_t *parse_generalName(chunk_t blob, int level0)
@@ -544,10 +540,10 @@ static identification_t *parse_generalName(chunk_t blob, int level0)
}
-/**
- * extracts one or several GNs and puts them into a chained list
+/*
+ * Defined in header.
*/
-void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
+void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
{
asn1_ctx_t ctx;
chunk_t object;
@@ -589,10 +585,10 @@ static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit)
return object;
}
-/**
- * extracts an authoritykeyIdentifier
+/*
+ * Defined in header.
*/
-void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber)
+void x509_parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber)
{
asn1_ctx_t ctx;
chunk_t object;
@@ -639,8 +635,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, linked_list_t *l
chunk_t object;
u_int level;
int objectID = 0;
-
- u_int accessMethod = OID_UNKNOWN;
+ int accessMethod = OID_UNKNOWN;
asn1_init(&ctx, blob, level0, FALSE, FALSE);
while (objectID < AUTH_INFO_ACCESS_ROOF)
@@ -659,15 +654,26 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, linked_list_t *l
switch (accessMethod)
{
case OID_OCSP:
- if (*object.ptr == ASN1_CONTEXT_S_6)
+ case OID_CA_ISSUERS:
{
identification_t *accessLocation;
- if (asn1_length(&object) == ASN1_INVALID_LENGTH)
+ accessLocation = parse_generalName(object, level+1);
+ if (accessLocation == NULL)
+ {
+ /* parsing went wrong - abort */
return;
- DBG2(" '%.*s'",(int)object.len, object.ptr);
- accessLocation = identification_create_from_encoding(ID_DER_ASN1_GN_URI, object);
- list->insert_last(list, (void *)accessLocation);
+ }
+ DBG2(" '%D'", accessLocation);
+ if (accessMethod == OID_OCSP)
+ {
+ list->insert_last(list, (void *)accessLocation);
+ }
+ else
+ {
+ /* caIsssuer accessLocation is not used yet */
+ accessLocation->destroy(accessLocation);
+ }
}
break;
default:
@@ -731,7 +737,7 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0, linked_list_t
if (objectID == CRL_DIST_POINTS_FULLNAME)
{
/* append extracted generalNames to existing chained list */
- parse_generalNames(object, level+1, TRUE, list);
+ x509_parse_generalNames(object, level+1, TRUE, list);
}
objectID++;
@@ -748,8 +754,8 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
bool critical;
chunk_t object;
u_int level;
- u_int extn_oid = OID_UNKNOWN;
int objectID = 0;
+ int extn_oid = OID_UNKNOWN;
asn1_init(&ctx, blob, level0, FALSE, FALSE);
while (objectID < X509_OBJ_ROOF)
@@ -778,7 +784,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
this->serialNumber = object;
break;
case X509_OBJ_SIG_ALG:
- this->sigAlg = parse_algorithmIdentifier(object, level, NULL);
+ this->signatureAlgorithm = parse_algorithmIdentifier(object, level, NULL);
break;
case X509_OBJ_ISSUER:
this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
@@ -797,7 +803,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION)
{
- DBG2(" unsupported public key algorithm");
+ DBG1(" unsupported public key algorithm");
return FALSE;
}
break;
@@ -809,7 +815,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
}
else
{
- DBG2(" invalid RSA public key format");
+ DBG1(" invalid RSA public key format");
return FALSE;
}
break;
@@ -831,7 +837,7 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
this->subjectKeyID = chunk_clone(parse_keyIdentifier(object, level, FALSE));
break;
case OID_SUBJECT_ALT_NAME:
- parse_generalNames(object, level, FALSE, this->subjectAltNames);
+ x509_parse_generalNames(object, level, FALSE, this->subjectAltNames);
break;
case OID_BASIC_CONSTRAINTS:
this->isCA = parse_basicConstraints(object, level);
@@ -840,7 +846,8 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
parse_crlDistributionPoints(object, level, this->crlDistributionPoints);
break;
case OID_AUTHORITY_KEY_ID:
- parse_authorityKeyIdentifier(object, level , &this->authKeyID, &this->authKeySerialNumber);
+ x509_parse_authorityKeyIdentifier(object, level,
+ &this->authKeyID, &this->authKeySerialNumber);
break;
case OID_AUTHORITY_INFO_ACCESS:
parse_authorityInfoAccess(object, level, this->ocspAccessLocations);
@@ -861,7 +868,15 @@ static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this)
break;
}
case X509_OBJ_ALGORITHM:
- this->algorithm = parse_algorithmIdentifier(object, level, NULL);
+ {
+ int alg = parse_algorithmIdentifier(object, level, NULL);
+
+ if (alg != this->signatureAlgorithm)
+ {
+ DBG1(" signature algorithms do not agree");
+ return FALSE;
+ }
+ }
break;
case X509_OBJ_SIGNATURE:
this->signature = object;
@@ -1119,7 +1134,14 @@ static iterator_t *create_ocspuri_iterator(const private_x509_t *this)
*/
static bool verify(const private_x509_t *this, const rsa_public_key_t *signer)
{
- return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertificate, this->signature) == SUCCESS;
+ hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->signatureAlgorithm);
+
+ if (algorithm == HASH_UNKNOWN)
+ {
+ DBG1(" unknown signature algorithm");
+ return FALSE;
+ }
+ return signer->verify_emsa_pkcs1_signature(signer, algorithm, this->tbsCertificate, this->signature) == SUCCESS;
}
/**
@@ -1221,6 +1243,101 @@ static void list(private_x509_t *this, FILE *out, bool utc)
}
}
+/*
+ * Defined in header.
+ */
+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;
+ size_t len = 0;
+
+ while (iterator->iterate(iterator, (void**)&name))
+ {
+ asn1_t asn1_type = ASN1_EOC;
+ chunk_t *generalName = malloc_thing(chunk_t);
+
+ switch (name->get_type(name))
+ {
+ case ID_RFC822_ADDR:
+ asn1_type = ASN1_CONTEXT_S_1;
+ break;
+ case ID_FQDN:
+ asn1_type = ASN1_CONTEXT_S_2;
+ break;
+ case ID_DER_ASN1_DN:
+ asn1_type = ASN1_CONTEXT_C_4;
+ break;
+ case ID_DER_ASN1_GN_URI:
+ asn1_type = ASN1_CONTEXT_S_6;
+ break;
+ case ID_IPV4_ADDR:
+ asn1_type = ASN1_CONTEXT_S_7;
+ break;
+ default:
+ continue;
+ }
+
+ *generalName = asn1_simple_object(asn1_type, name->get_encoding(name));
+ len += generalName->len;
+ generalNames->insert_last(generalNames, generalName);
+ }
+ iterator->destroy(iterator);
+
+ if (len > 0)
+ {
+ iterator_t *iterator = generalNames->create_iterator(generalNames, TRUE);
+ chunk_t names, *generalName;
+ u_char *pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
+
+ while (iterator->iterate(iterator, (void**)&generalName))
+ {
+ memcpy(pos, generalName->ptr, generalName->len);
+ pos += generalName->len;
+ free(generalName->ptr);
+ free(generalName);
+ }
+ iterator->destroy(iterator);
+ generalNames->destroy(generalNames);
+
+ return asn1_wrap(ASN1_OCTET_STRING, "m", names);
+ }
+ else
+ {
+ return chunk_empty;
+ }
+}
+
+/*
+ * Defined in header.
+ */
+chunk_t x509_build_subjectAltNames(linked_list_t *list)
+{
+ chunk_t generalNames = x509_build_generalNames(list);
+
+ if (generalNames.len)
+ {
+ return asn1_wrap(ASN1_SEQUENCE, "cm",
+ ASN1_subjectAltName_oid,
+ asn1_wrap(ASN1_OCTET_STRING, "m", generalNames)
+ );
+ }
+ else
+ {
+ return chunk_empty;
+ }
+}
+
+/**
+ * Implementation of x509_t.build_encoding.
+ */
+static void build_encoding(private_x509_t *this, hash_algorithm_t alg,
+ rsa_private_key_t *private_key)
+{
+
+}
+
/**
* Implements x509_t.destroy
*/
@@ -1240,10 +1357,10 @@ static void destroy(private_x509_t *this)
free(this);
}
-/*
- * Described in header.
+/**
+ * Internal generic constructor
*/
-x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
+static private_x509_t *x509_create_empty(void)
{
private_x509_t *this = malloc_thing(private_x509_t);
@@ -1290,9 +1407,34 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
this->public.create_crluri_iterator = (iterator_t* (*) (const x509_t*))create_crluri_iterator;
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.list = (void (*) (x509_t*, FILE *out, bool utc))list;
+ this->public.build_encoding = (void (*) (x509_t*,hash_algorithm_t,rsa_private_key_t*))build_encoding;
this->public.destroy = (void (*) (x509_t*))destroy;
+ return this;
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_(chunk_t serialNumber, identification_t *issuer, identification_t *subject)
+{
+ private_x509_t *this = x509_create_empty();
+
+ this->serialNumber = serialNumber;
+ this->issuer = issuer->clone(issuer);
+ this->subject = subject->clone(subject);
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
+{
+ private_x509_t *this = x509_create_empty();
+
if (!parse_certificate(chunk, level, this))
{
destroy(this);
@@ -1314,8 +1456,15 @@ x509_t *x509_create_from_chunk(chunk_t chunk, u_int level)
this->isSelfSigned = FALSE;
if (this->subject->equals(this->subject, this->issuer))
{
+ hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->signatureAlgorithm);
+
+ if (algorithm == HASH_UNKNOWN)
+ {
+ destroy(this);
+ return NULL;
+ }
this->isSelfSigned = this->public_key->verify_emsa_pkcs1_signature(this->public_key,
- this->tbsCertificate, this->signature) == SUCCESS;
+ algorithm, this->tbsCertificate, this->signature) == SUCCESS;
}
if (this->isSelfSigned)
{
diff --git a/src/libstrongswan/crypto/x509.h b/src/libstrongswan/crypto/x509.h
index c6fe148d4..1ab267dac 100755
--- a/src/libstrongswan/crypto/x509.h
+++ b/src/libstrongswan/crypto/x509.h
@@ -23,6 +23,8 @@
* 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: x509.h 3301 2007-10-12 21:56:30Z andreas $
*/
#ifndef X509_H_
@@ -31,7 +33,8 @@
typedef struct x509_t x509_t;
#include <library.h>
-#include <crypto/rsa/rsa_public_key.h>
+#include <crypto/rsa/rsa_private_key.h>
+#include <crypto/hashers/hasher.h>
#include <crypto/certinfo.h>
#include <crypto/ca.h>
#include <utils/identification.h>
@@ -49,6 +52,7 @@ typedef struct x509_t x509_t;
* @brief X.509 certificate.
*
* @b Constructors:
+ * - x509_create()
* - x509_create_from_chunk()
* - x509_create_from_file()
*
@@ -288,9 +292,26 @@ struct x509_t {
* @param out stream to write to
* @param utc TRUE for UTC times, FALSE for local time
*/
- void (*list)(x509_t *this, FILE *out, bool utc);
+ void (*list) (x509_t *this, FILE *out, bool utc);
/**
+ * @brief Adds a list of subjectAltNames
+ *
+ * @param this calling object
+ * @param subjectAltNames list of subjectAltNames to be added
+ */
+ void (*add_subjectAltNames) (x509_t *this, linked_list_t *subjectAltNames);
+
+ /**
+ * @brief Builds a DER-encoded signed X.509 certificate
+ *
+ * @param this calling object
+ * @param alg hash algorithm used to compute the certificate digest
+ * @param private_key RSA private key used to sign the certificate digest
+ */
+ void (*build_encoding) (x509_t *this, hash_algorithm_t alg, rsa_private_key_t *private_key);
+
+ /**
* @brief Destroys the certificate.
*
* @param this certificate to destroy
@@ -299,17 +320,34 @@ struct x509_t {
};
/**
- * @brief Read a x509 certificate from a DER encoded blob.
- *
+ * @brief Create a X.509 certificate from its components
+ *
+ * @param serialNumber chunk containing the serialNumber
+ * @param issuer issuer distinguished name
+ * @param notBefore start date of validity
+ * @param notAfter end date of validity
+ * @param subject subject distinguished name
+ *
+ * @return created x509_t certificate, or NULL if invalid.
+ *
+ * @ingroup crypto
+ */
+x509_t *x509_create(chunk_t serialNumber, identification_t *issuer,
+ time_t notBefore, time_t notAfter,
+ identification_t *subject);
+
+/**
+ * @brief Read a X.509 certificate from a DER encoded blob.
+ *
* @param chunk chunk containing DER encoded data
- * @return created x509_t certificate, or NULL if invlid.
+ * @return created x509_t certificate, or NULL if invalid.
*
* @ingroup crypto
*/
x509_t *x509_create_from_chunk(chunk_t chunk, u_int level);
/**
- * @brief Read a x509 certificate from a DER encoded file.
+ * @brief Read a X.509 certificate from a DER encoded file.
*
* @param filename file containing DER encoded data
* @param label label describing kind of certificate
@@ -329,7 +367,7 @@ x509_t *x509_create_from_file(const char *filename, const char *label);
*
* @ingroup crypto
*/
-void parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeyID, chunk_t *authKeySerialNumber);
+void x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeyID, chunk_t *authKeySerialNumber);
/**
* @brief Parses DER encoded generalNames
@@ -337,10 +375,30 @@ void parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeyID,
* @param blob blob containing DER encoded data
* @param level0 indicates the current parsing level
* @param implicit implicit coding is used
- * @param list linked list of decoded generalNames
+ * @param list list of decoded generalNames
+ *
+ * @ingroup crypto
+ */
+void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list);
+
+/**
+ * @brief Builds a DER encoded list of generalNames
+ *
+ * @param list list of generalNames to be encoded
+ * @return DER encoded list of generalNames
+ *
+ * @ingroup crypto
+ */
+chunk_t x509_build_generalNames(linked_list_t *list);
+
+/**
+ * @brief Builds a DER encoded list of subjectAltNames
+ *
+ * @param list list of subjectAltNames to be encoded
+ * @return DER encoded list of subjectAltNames
*
* @ingroup crypto
*/
-void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list);
+chunk_t x509_build_subjectAltNames(linked_list_t *list);
#endif /* X509_H_ */