credentials/certificates/crl.h credentials/certificates/crl.c \
credentials/certificates/ocsp_request.h \
credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \
-fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \
database/database.h database/database_factory.h database/database_factory.c \
+fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \
+pgp/pgp.c pgp/pgp.h \
utils.h utils.c \
utils/host.c utils/host.h \
utils/identification.c utils/identification.h \
/*
* Defined in header.
*/
-u_int asn1_length(chunk_t *blob)
+size_t asn1_length(chunk_t *blob)
{
u_char n;
size_t len;
}
/**
- * Build an ASN.1 BITSTRING object
+ * Build an ASN.1 BIT_STRING object
*/
chunk_t asn1_bitstring(const char *mode, chunk_t content)
{
}
/**
+ * Build an ASN.1 INTEGER object
+ */
+chunk_t asn1_integer(const char *mode, chunk_t content)
+{
+ chunk_t object;
+ size_t len;
+ u_char *pos;
+
+ if (content.len == 0 || (content.len == 1 && *content.ptr == 0x00))
+ {
+ /* a zero ASN.1 integer does not have a value field */
+ len = 0;
+ }
+ else
+ {
+ /* ASN.1 integers must be positive numbers in two's complement */
+ len = content.len + ((*content.ptr & 0x80) ? 1 : 0);
+ }
+ pos = asn1_build_object(&object, ASN1_INTEGER, len);
+ if (len > content.len)
+ {
+ *pos++ = 0x00;
+ }
+ if (len)
+ {
+ memcpy(pos, content.ptr, content.len);
+ }
+ if (*mode == 'm')
+ {
+ free(content.ptr);
+ }
+ return object;
+}
+
+/**
* Build an ASN.1 object from a variable number of individual chunks.
* Depending on the mode, chunks either are moved ('m') or copied ('c').
*/
* @param blob pointer to an ASN.1 coded blob
* @return length of ASN.1 object
*/
-u_int asn1_length(chunk_t *blob);
+size_t asn1_length(chunk_t *blob);
/**
* Parses an ASN.1 algorithmIdentifier object
chunk_t asn1_bitstring(const char *mode, chunk_t content);
/**
+ * Build an ASN.1 INTEGER object
+ *
+ * @param mode 'c' for copy or 'm' for move
+ * @param content content of the INTEGER
+ * @return chunk containing the ASN.1 coded INTEGER
+ */
+chunk_t asn1_integer(const char *mode, chunk_t content);
+
+/**
* Build an ASN.1 object from a variable number of individual chunks
*
* @param type ASN.1 type to be created
"BUILD_AGENT_SOCKET",
"BUILD_BLOB_ASN1_DER",
"BUILD_BLOB_ASN1_PEM",
+ "BUILD_BLOB_PGP",
+ "BUILD_BLOB_RFC_3110",
"BUILD_KEY_SIZE",
"BUILD_SIGNING_KEY",
"BUILD_SIGNING_CERT",
* Parts to build credentials from.
*/
enum builder_part_t {
- /** path to a file containing an ASN1 blob, char* */
+ /** path to a file containing an ASN.1 blob, char* */
BUILD_FROM_FILE,
/** unix socket of a ssh/pgp agent, char* */
BUILD_AGENT_SOCKET,
- /** DER encoded ASN1 blob, chunk_t */
+ /** DER encoded ASN.1 blob, chunk_t */
BUILD_BLOB_ASN1_DER,
- /** PEM encoded ASN1 blob, null terminated char* */
+ /** PEM encoded ASN.1 blob, null terminated char* */
BUILD_BLOB_ASN1_PEM,
+ /** OpenPGP key blob, chunk_t */
+ BUILD_BLOB_PGP,
+ /** RFC 3110 DNS public key blob, chunk_t */
+ BUILD_BLOB_RFC_3110,
/** key size in bits, as used for key generation, u_int */
BUILD_KEY_SIZE,
/** private key to use for signing, private_key_t* */
case BUILD_END:
break;
case BUILD_BLOB_ASN1_DER:
+ case BUILD_BLOB_PGP:
+ case BUILD_BLOB_RFC_3110:
case BUILD_SERIAL:
builder->add(builder, part, va_arg(args, chunk_t));
continue;
public_key_t* (*get_public_key)(private_key_t *this);
/**
+ * Check if two private keys are equal.
+ *
+ * @param other other private key
+ * @return TRUE, if equality
+ */
+ bool (*equals) (private_key_t *this, private_key_t *other);
+
+ /**
* Check if a private key belongs to a public key.
*
* @param public public key
#include "public_key.h"
-ENUM(key_type_names, KEY_RSA, KEY_ECDSA,
+ENUM(key_type_names, KEY_RSA, KEY_DSA,
"RSA",
- "ECDSA"
+ "ECDSA",
+ "DSA"
);
ENUM(signature_scheme_names, SIGN_DEFAULT, SIGN_ECDSA_521,
"DEFAULT",
+ "RSA_EMSA_PKCS1_NULL",
"RSA_EMSA_PKCS1_MD5",
"RSA_EMSA_PKCS1_SHA1",
"RSA_EMSA_PKCS1_SHA256",
*/
enum key_type_t {
/** key type wildcard */
- KEY_ANY,
+ KEY_ANY = 0,
/** RSA crypto system as in PKCS#1 */
- KEY_RSA,
+ KEY_RSA = 1,
/** ECDSA as in ANSI X9.62 */
- KEY_ECDSA,
- /** DSS, ElGamal, ... */
+ KEY_ECDSA = 2,
+ /** DSA */
+ KEY_DSA = 3,
+ /** ElGamal, ... */
};
/**
/**
* Signature scheme for signature creation
*
- * EMSA-PKCS1 signatures are from the PKCS#1 standard. They include
- * the ASN1-OID of the used hash algorithm.
+ * EMSA-PKCS1 signatures are defined in PKCS#1 standard.
+ * A prepended ASN.1 encoded digestInfo field contains the
+ * OID of the used hash algorithm. The ASN.1 type of the PKCS#7
+ * variants is OCTET_STRING instead of the default BIT_STRING.
*/
enum signature_scheme_t {
- /** default scheme of that underlying crypto system */
+ /** Default scheme of the underlying crypto system */
SIGN_DEFAULT,
- /** EMSA-PKCS1 with MD5 */
+ /** EMSA-PKCS1_v1.5 signature over digest without digestInfo */
+ SIGN_RSA_EMSA_PKCS1_NULL,
+ /** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and MD5 */
SIGN_RSA_EMSA_PKCS1_MD5,
- /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA1 as hash. */
+ /** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-1 */
SIGN_RSA_EMSA_PKCS1_SHA1,
- /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA256 as hash. */
+ /** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-256 */
SIGN_RSA_EMSA_PKCS1_SHA256,
- /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA384 as hash. */
+ /** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-384 */
SIGN_RSA_EMSA_PKCS1_SHA384,
- /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA512 as hash. */
+ /** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-512 */
SIGN_RSA_EMSA_PKCS1_SHA512,
- /** ECDSA using SHA-1 as hash. */
+ /** ECDSA with SHA-1 */
SIGN_ECDSA_WITH_SHA1,
- /** ECDSA with SHA-256 on the P-256 curve as in RFC 4754 */
+ /** ECDSA on the P-256 curve with SHA-256 as in RFC 4754 */
SIGN_ECDSA_256,
- /** ECDSA with SHA-384 on the P-384 curve as in RFC 4754 */
+ /** ECDSA on the P-384 curve with SHA-384 as in RFC 4754 */
SIGN_ECDSA_384,
- /** ECDSA with SHA-512 on the P-521 curve as in RFC 4754 */
+ /** ECDSA on the P-521 curve with SHA-512 as in RFC 4754 */
SIGN_ECDSA_521,
};
/**
* Encrypt a chunk of data.
*
- * @param crypto chunk containing plaintext data
- * @param plain where to allocate encrypted data
+ * @param plain chunk containing plaintext data
+ * @param crypto where to allocate encrypted data
* @return TRUE if data successfully encrypted
*/
- bool (*encrypt)(public_key_t *this, chunk_t crypto, chunk_t *plain);
+ bool (*encrypt)(public_key_t *this, chunk_t plain, chunk_t *crypto);
/**
+ * Check if two public keys are equal.
+ *
+ * @param other other public key
+ * @return TRUE, if equality
+ */
+ bool (*equals)(public_key_t *this, public_key_t *other);
+
+ /**
* Get the strength of the key in bytes.
*
* @return strength of the key in bytes
--- /dev/null
+/*
+ * Copyright (C) 2002-2009 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 "pgp.h"
+
+ENUM(pgp_sym_alg_names, PGP_SYM_ALG_PLAIN, PGP_SYM_ALG_TWOFISH,
+ "PLAINTEXT",
+ "IDEA",
+ "3DES",
+ "CAST5",
+ "BLOWFISH",
+ "SAFER",
+ "DES",
+ "AES_128",
+ "AES_192",
+ "AES_256",
+ "TWOFISH"
+);
+
+/*
+ * Defined in header.
+ */
+size_t pgp_length(chunk_t *blob, size_t len)
+{
+ size_t size = 0;
+
+ if (len > blob->len)
+ {
+ return PGP_INVALID_LENGTH;
+ }
+ blob->len -= len;
+
+ while (len-- > 0)
+ {
+ size = 256*size + *blob->ptr++;
+ }
+ return size;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2002-2009 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.
+ */
+
+/**
+ * @defgroup pgpi pgp
+ * @{ @ingroup pgp
+ */
+
+#ifndef PGP_H_
+#define PGP_H_
+
+typedef enum pgp_sym_alg_t pgp_sym_alg_t;
+
+#include <chunk.h>
+#include <enum.h>
+
+/**
+ * OpenPGP symmetric key algorithms defined in section 9.2 of RFC 4880
+ */
+enum pgp_sym_alg_t {
+ PGP_SYM_ALG_PLAIN = 0,
+ PGP_SYM_ALG_IDEA = 1,
+ PGP_SYM_ALG_3DES = 2,
+ PGP_SYM_ALG_CAST5 = 3,
+ PGP_SYM_ALG_BLOWFISH = 4,
+ PGP_SYM_ALG_SAFER = 5,
+ PGP_SYM_ALG_DES = 6,
+ PGP_SYM_ALG_AES_128 = 7,
+ PGP_SYM_ALG_AES_192 = 8,
+ PGP_SYM_ALG_AES_256 = 9,
+ PGP_SYM_ALG_TWOFISH = 10
+};
+
+/**
+ * Enum names for pgp_sym_alg_t
+ */
+extern enum_name_t *pgp_sym_alg_names;
+
+#define PGP_INVALID_LENGTH 0xffffffff
+
+/**
+ * Returns the length of an OpenPGP (RFC 4880) packet
+ * The blob pointer is advanced past the length field
+ *
+ * @param blob pointer to an OpenPGP blob
+ * @param len size of the length field
+ * @return length of the next OpenPGP packet
+ */
+size_t pgp_length(chunk_t *blob, size_t len);
+
+#endif /** PGP_H_ @}*/
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
+#include <pgp/pgp.h>
/**
* Public exponent to use for key generation.
};
/**
- * shared functions, implemented in gmp_rsa_public_key.c
+ * Shared functions defined in gmp_rsa_public_key.c
*/
-bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid,
- identification_t **keyid_info);
-gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e);
+extern bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e,
+ identification_t **keyid,
+ identification_t **keyid_info);
+extern gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e);
/**
* Auxiliary function overwriting private key material with zero bytes
hash_algorithm_t hash_algorithm,
chunk_t data, chunk_t *signature)
{
- hasher_t *hasher;
- chunk_t em, digestInfo, hash;
- int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
-
- if (hash_oid == OID_UNKNOWN)
- {
- return FALSE;
- }
+ chunk_t digestInfo = chunk_empty;
+ chunk_t em;
- /* get hasher */
- hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
- if (hasher == NULL)
+ if (hash_algorithm != HASH_UNKNOWN)
{
- return FALSE;
- }
+ hasher_t *hasher;
+ chunk_t hash;
+ int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
- /* build hash */
- hasher->allocate_hash(hasher, data, &hash);
- hasher->destroy(hasher);
+ if (hash_oid == OID_UNKNOWN)
+ {
+ return FALSE;
+ }
+
+ hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
+ if (hasher == NULL)
+ {
+ return FALSE;
+ }
+ hasher->allocate_hash(hasher, data, &hash);
+ hasher->destroy(hasher);
- /* build DER-encoded digestInfo */
- digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
- asn1_algorithmIdentifier(hash_oid),
- asn1_simple_object(ASN1_OCTET_STRING, hash)
- );
- chunk_free(&hash);
+ /* build DER-encoded digestInfo */
+ digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
+ asn1_algorithmIdentifier(hash_oid),
+ asn1_simple_object(ASN1_OCTET_STRING, hash)
+ );
+ chunk_free(&hash);
+ data = digestInfo;
+ }
/* build chunk to rsa-decrypt:
* EM = 0x00 || 0x01 || PS || 0x00 || T.
/* set magic bytes */
*(em.ptr) = 0x00;
*(em.ptr+1) = 0x01;
- *(em.ptr + em.len - digestInfo.len - 1) = 0x00;
+ *(em.ptr + em.len - data.len - 1) = 0x00;
/* set DER-encoded hash */
- memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len);
+ memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
/* build signature */
*signature = rsasp1(this, em);
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.get_type.
*/
static key_type_t get_type(private_gmp_rsa_private_key_t *this)
{
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.sign.
*/
static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme,
chunk_t data, chunk_t *signature)
{
switch (scheme)
{
+ case SIGN_RSA_EMSA_PKCS1_NULL:
+ return build_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
case SIGN_DEFAULT:
- /* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1:
return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256:
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.decrypt.
*/
static bool decrypt(private_gmp_rsa_private_key_t *this,
chunk_t crypto, chunk_t *plain)
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.get_keysize.
*/
static size_t get_keysize(private_gmp_rsa_private_key_t *this)
{
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.get_id.
*/
static identification_t* get_id(private_gmp_rsa_private_key_t *this,
id_type_t type)
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.equals.
+ */
+static bool equals(private_gmp_rsa_private_key_t *this, private_key_t *other)
+{
+ identification_t *keyid;
+
+ if (&this->public.interface == other)
+ {
+ return TRUE;
+ }
+ if (other->get_type(other) != KEY_RSA)
+ {
+ return FALSE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid))
+ {
+ return TRUE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid_info))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of gmp_rsa_private_key.belongs_to.
*/
static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public)
{
}
/**
- * convert a MP integer into a DER coded ASN.1 object
+ * Convert a MP integer into a chunk_t
*/
-chunk_t gmp_mpz_to_asn1(const mpz_t value)
+chunk_t gmp_mpz_to_chunk(const mpz_t value)
{
chunk_t n;
- n.len = 1 + mpz_sizeinbase(value, 2) / 8; /* size in bytes */
+ n.len = 1 + mpz_sizeinbase(value, 2) / BITS_PER_BYTE;
n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value);
if (n.ptr == NULL)
{ /* if we have zero in "value", gmp returns NULL */
n.len = 0;
}
- return asn1_wrap(ASN1_INTEGER, "m", n);
+ return n;
+}
+
+/**
+ * Convert a MP integer into a DER coded ASN.1 object
+ */
+chunk_t gmp_mpz_to_asn1(const mpz_t value)
+{
+ return asn1_wrap(ASN1_INTEGER, "m", gmp_mpz_to_chunk(value));
}
/**
}
/**
- * Implementation of gmp_rsa_private_key.destroy.
+ * Implementation of gmp_rsa_private_key.get_ref.
*/
static private_gmp_rsa_private_key_t* get_ref(private_gmp_rsa_private_key_t *this)
{
/* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
* We actually require more (for security).
*/
- if (this->k < 512/8)
+ if (this->k < 512 / BITS_PER_BYTE)
{
DBG1("key shorter than 512 bits");
return FAILED;
}
/* we picked a max modulus size to simplify buffer allocation */
- if (this->k > 8192/8)
+ if (this->k > 8192 / BITS_PER_BYTE)
{
DBG1("key larger than 8192 bits");
return FAILED;
{
private_gmp_rsa_private_key_t *this = malloc_thing(private_gmp_rsa_private_key_t);
- this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
- this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
- this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
- this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
- this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
- this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
- this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
- this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
- this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
- this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
+ this->public.interface.get_type = (key_type_t (*) (private_key_t*))get_type;
+ this->public.interface.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign;
+ this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt;
+ this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize;
+ this->public.interface.get_id = (identification_t* (*) (private_key_t*, id_type_t))get_id;
+ this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key;
+ this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals;
+ this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to;
+ this->public.interface.get_encoding = (chunk_t (*) (private_key_t*))get_encoding;
+ this->public.interface.get_ref = (private_key_t* (*) (private_key_t*))get_ref;
+ this->public.interface.destroy = (void (*) (private_key_t*))destroy;
this->keyid = NULL;
this->keyid_info = NULL;
mpz_t m, q1, t;
private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty();
- key_size = key_size / 8;
+ key_size = key_size / BITS_PER_BYTE;
/* Get values of primes p and q */
if (compute_prime(this, key_size/2, &p) != SUCCESS)
/**
* load private key from a ASN1 encoded blob
*/
-static gmp_rsa_private_key_t *load(chunk_t blob)
+static gmp_rsa_private_key_t *load_asn1_der(chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
case PRIV_KEY_VERSION:
if (object.len > 0 && *object.ptr != 0)
{
+ DBG1("PKCS#1 private key format is not version 1");
goto end;
}
break;
destroy(this);
return NULL;
}
+ if (check(this) != SUCCESS)
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
+/**
+ * load private key from an OpenPGP blob coded according to section
+ */
+static gmp_rsa_private_key_t *load_pgp(chunk_t blob)
+{
+ mpz_t u;
+ int objectID;
+ pgp_sym_alg_t s2k;
+ chunk_t packet = blob;
+ private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty();
+
+ mpz_init(this->n);
+ mpz_init(this->e);
+ mpz_init(this->p);
+ mpz_init(this->q);
+ mpz_init(this->d);
+ mpz_init(this->exp1);
+ mpz_init(this->exp2);
+ mpz_init(this->coeff);
+
+ /* string-to-key usage */
+ s2k = pgp_length(&packet, 1);
+ DBG2("L3 - string-to-key: %d", s2k);
+
+ if (s2k == 255 || s2k == 254)
+ {
+ DBG1("string-to-key specifiers not supported");
+ goto end;
+ }
+ DBG2(" %N", pgp_sym_alg_names, s2k);
+
+ if (s2k != PGP_SYM_ALG_PLAIN)
+ {
+ DBG1("%N encryption not supported", pgp_sym_alg_names, s2k);
+ goto end;
+ }
+
+ for (objectID = PRIV_KEY_MODULUS; objectID <= PRIV_KEY_PRIME2; objectID++)
+ {
+ chunk_t object;
+
+ object.len = pgp_length(&packet, 2);
+
+ if (object.len == PGP_INVALID_LENGTH)
+ {
+ DBG1("OpenPGP length is invalid");
+ goto end;
+ }
+ object.len = (object.len + 7) / BITS_PER_BYTE;
+ if (object.len > packet.len)
+ {
+ DBG1("OpenPGP field is too short");
+ goto end;
+ }
+ object.ptr = packet.ptr;
+ packet.ptr += object.len;
+ packet.len -= object.len;
+
+ switch (objectID)
+ {
+ case PRIV_KEY_MODULUS:
+ mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PUB_EXP:
+ mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PRIV_EXP:
+ mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PRIME1:
+ mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ case PRIV_KEY_PRIME2:
+ mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr);
+ break;
+ }
+ }
+
+ /* auxiliary variable */
+ mpz_init(u);
+
+ /* exp1 = d mod (p-1) */
+ mpz_sub_ui(u, this->p, 1);
+ mpz_mod(this->exp1, this->d, u);
+
+ /* exp2 = d mod (q-1) */
+ mpz_sub_ui(u, this->q, 1);
+ mpz_mod(this->exp2, this->d, u);
+
+ /* coeff = (q^-1) mod p */
+ mpz_invert(this->coeff, this->q, this->p);
+ if (mpz_cmp_ui(this->coeff, 0) < 0)
+ {
+ mpz_add(this->coeff, this->coeff, this->p);
+ }
+ mpz_clear(u);
+ chunk_clear(&blob);
+
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
+
+ if (!gmp_rsa_public_key_build_id(this->n, this->e,
+ &this->keyid, &this->keyid_info))
+ {
+ destroy(this);
+ return NULL;
+ }
if (check(this) != SUCCESS)
{
destroy(this);
return NULL;
}
return &this->public;
+
+end:
+ chunk_clear(&blob);
+ destroy(this);
+ return NULL;
}
typedef struct private_builder_t private_builder_t;
{
va_start(args, part);
chunk = va_arg(args, chunk_t);
- this->key = load(chunk_clone(chunk));
+ this->key = load_asn1_der(chunk_clone(chunk));
+ va_end(args);
+ return;
+ }
+ case BUILD_BLOB_PGP:
+ {
+ va_start(args, part);
+ chunk = va_arg(args, chunk_t);
+ this->key = load_pgp(chunk_clone(chunk));
va_end(args);
return;
}
#include <asn1/asn1_parser.h>
#include <asn1/pem.h>
#include <crypto/hashers/hasher.h>
-
-/**
- * defined in gmp_rsa_private_key.c
- */
-extern chunk_t gmp_mpz_to_asn1(const mpz_t value);
+#include <pgp/pgp.h>
typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
};
/**
+ * Shared functions defined in gmp_rsa_private_key.c
+ */
+extern chunk_t gmp_mpz_to_chunk(const mpz_t value);
+extern chunk_t gmp_mpz_to_asn1(const mpz_t value);
+
+/**
* RSAEP algorithm specified in PKCS#1.
*/
static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data)
goto end;
}
- /* parse ASN.1-based digestInfo */
- {
+ if (algorithm == HASH_UNKNOWN)
+ { /* IKEv1 signatures without digestInfo */
+ if (em.len != data.len)
+ {
+ DBG1("hash size in signature is %u bytes instead of %u bytes",
+ em.len, data.len);
+ goto end;
+ }
+ success = memeq(em.ptr, data.ptr, data.len);
+ }
+ else
+ { /* IKEv2 and X.509 certificate signatures */
asn1_parser_t *parser;
chunk_t object;
int objectID;
hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
+ DBG2("signature verification:");
parser = asn1_parser_create(digestInfoObjects, em);
while (parser->iterate(parser, &objectID, &object))
parser->get_level(parser)+1, NULL);
hash_algorithm = hasher_algorithm_from_oid(hash_oid);
- if (hash_algorithm == HASH_UNKNOWN ||
- (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
+ if (hash_algorithm == HASH_UNKNOWN || hash_algorithm != algorithm)
{
DBG1("expected hash algorithm %N, but found %N (OID: %#B)",
hash_algorithm_names, algorithm,
{
switch (scheme)
{
- case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */
+ case SIGN_DEFAULT:
+ case SIGN_RSA_EMSA_PKCS1_NULL:
return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
case SIGN_RSA_EMSA_PKCS1_MD5:
return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
}
/**
+ * Implementation of gmp_rsa_public_key.equals.
+ */
+static bool equals(private_gmp_rsa_public_key_t *this, public_key_t *other)
+{
+ identification_t *keyid;
+
+ if (&this->public.interface == other)
+ {
+ return TRUE;
+ }
+ if (other->get_type(other) != KEY_RSA)
+ {
+ return FALSE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid))
+ {
+ return TRUE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid_info))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
* Implementation of public_key_t.get_keysize.
*/
static size_t get_keysize(private_gmp_rsa_public_key_t *this)
}
/**
+ * Build the PGP version 3 RSA key identifier from n and e using
+ * MD5 hashed modulus and exponent. Also used in rsa_private_key.c.
+ */
+static identification_t* gmp_rsa_build_pgp_v3_keyid(mpz_t n, mpz_t e)
+{
+ identification_t *keyid;
+ chunk_t modulus, exponent, hash;
+ hasher_t *hasher;
+
+ hasher= lib->crypto->create_hasher(lib->crypto, HASH_MD5);
+ if (hasher == NULL)
+ {
+ DBG1("computation of PGP V3 key ID failed, no MD5 hasher is available");
+ return NULL;
+ }
+ modulus = gmp_mpz_to_chunk(n);
+ exponent = gmp_mpz_to_chunk(e);
+ hasher->allocate_hash(hasher, modulus, NULL);
+ hasher->allocate_hash(hasher, exponent, &hash);
+ hasher->destroy(hasher);
+ keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
+ free(hash.ptr);
+ free(modulus.ptr);
+ free(exponent.ptr);
+ return keyid;
+}
+
+/**
* Implementation of public_key_t.get_id.
*/
static identification_t *get_id(private_gmp_rsa_public_key_t *this,
return this->keyid_info;
case ID_PUBKEY_SHA1:
return this->keyid;
+ case ID_KEY_ID:
+ return gmp_rsa_build_pgp_v3_keyid(this->n, this->e);
default:
return NULL;
}
{
private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t);
- this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
- this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
- this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_;
- this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
- this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
- this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
- this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
- this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
+ this->public.interface.get_type = (key_type_t (*) (public_key_t*))get_type;
+ this->public.interface.verify = (bool (*) (public_key_t*, signature_scheme_t, chunk_t, chunk_t))verify;
+ this->public.interface.encrypt = (bool (*) (public_key_t*, chunk_t, chunk_t*))encrypt_;
+ this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals;
+ this->public.interface.get_keysize = (size_t (*) (public_key_t*))get_keysize;
+ this->public.interface.get_id = (identification_t* (*) (public_key_t*, id_type_t))get_id;
+ this->public.interface.get_encoding = (chunk_t(*) (public_key_t*))get_encoding;
+ this->public.interface.get_ref = (public_key_t* (*) (public_key_t *this))get_ref;
+ this->public.interface.destroy = (void (*) (public_key_t *this))destroy;
this->keyid = NULL;
this->keyid_info = NULL;
mpz_init_set(this->n, n);
mpz_init_set(this->e, e);
- this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info))
{
#define PUB_KEY_EXPONENT 2
/**
- * Load a public key from an ASN1 encoded blob
+ * Load a public key from an ASN.1 encoded blob
*/
-static gmp_rsa_public_key_t *load(chunk_t blob)
+static gmp_rsa_public_key_t *load_asn1_der(chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
return NULL;
}
- this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
+
+ if (!gmp_rsa_public_key_build_id(this->n, this->e,
+ &this->keyid, &this->keyid_info))
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
+
+/**
+ * Load a public key from an OpenPGP blob
+ */
+static gmp_rsa_public_key_t* load_pgp(chunk_t blob)
+{
+ chunk_t exponent, modulus;
+ chunk_t packet = blob;
+ private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty();
+
+ mpz_init(this->n);
+ mpz_init(this->e);
+
+ /* modulus n */
+ modulus.len = (pgp_length(&packet, 2) + 7) / BITS_PER_BYTE;
+ modulus.ptr = packet.ptr;
+ if (modulus.len > packet.len)
+ {
+ DBG1("OpenPGP public key blob too short for modulus");
+ goto end;
+ }
+ packet.ptr += modulus.len;
+ packet.len -= modulus.len;
+ DBG2("L3 - modulus:");
+ DBG3("%B", &modulus);
+
+ /* public exponent e */
+ exponent.len = (pgp_length(&packet, 2) + 7) / BITS_PER_BYTE;
+ exponent.ptr = packet.ptr;
+ if (exponent.len > packet.len)
+ {
+ DBG1("OpenPGP public key blob too short for exponent");
+ goto end;
+ }
+ DBG2("L3 - public exponent:");
+ DBG3("%B", &exponent);
+
+ mpz_import(this->n, modulus.len, 1, 1, 1, 0, modulus.ptr);
+ mpz_import(this->e, exponent.len, 1, 1, 1, 0, exponent.ptr);
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
+ free(blob.ptr);
+
+ if (!gmp_rsa_public_key_build_id(this->n, this->e,
+ &this->keyid, &this->keyid_info))
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+
+end:
+ free(blob.ptr);
+ destroy(this);
+ return NULL;
+}
+
+/**
+ * Load a public key from an RFC 3110 encoded blob
+ */
+static gmp_rsa_public_key_t *load_rfc_3110(chunk_t blob)
+{
+ chunk_t exponent, modulus;
+ u_char *pos = blob.ptr;
+ size_t len = blob.len;
+ private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty();
+
+ mpz_init(this->n);
+ mpz_init(this->e);
+
+ if (blob.len < 3)
+ {
+ DBG1("RFC 3110 public key blob too short for exponent length");
+ goto end;
+ }
+ if (pos[0] != 0x00)
+ {
+ exponent = chunk_create(pos + 1, pos[0]);
+ pos++;
+ len--;
+ }
+ else
+ {
+ exponent = chunk_create(pos + 3, 256*pos[1] + pos[2]);
+ pos += 3;
+ len -= 3;
+ }
+ if (exponent.len > len)
+ {
+ DBG1("RFC 3110 public key blob too short for exponent");
+ goto end;
+ }
+ pos += exponent.len;
+ len -= exponent.len;
+
+ if (len == 0)
+ {
+ DBG1("RFC 3110 public key blob has zero length modulus");
+ goto end;
+ }
+ modulus = chunk_create(pos, len);
+
+ mpz_import(this->n, modulus.len, 1, 1, 1, 0, modulus.ptr);
+ mpz_import(this->e, exponent.len, 1, 1, 1, 0, exponent.ptr);
+ this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
+ free(blob.ptr);
if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info))
return NULL;
}
return &this->public;
+
+end:
+ free(blob.ptr);
+ destroy(this);
+ return NULL;
}
typedef struct private_builder_t private_builder_t;
{
va_start(args, part);
chunk = va_arg(args, chunk_t);
- this->key = load(chunk_clone(chunk));
+ this->key = load_asn1_der(chunk_clone(chunk));
+ va_end(args);
+ return;
+ }
+ case BUILD_BLOB_PGP:
+ {
+ va_start(args, part);
+ chunk = va_arg(args, chunk_t);
+ this->key = load_pgp(chunk_clone(chunk));
+ va_end(args);
+ return;
+ }
+ case BUILD_BLOB_RFC_3110:
+ {
+ va_start(args, part);
+ chunk = va_arg(args, chunk_t);
+ this->key = load_rfc_3110(chunk_clone(chunk));
va_end(args);
return;
}
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.get_type.
*/
static key_type_t get_type(private_openssl_rsa_private_key_t *this)
{
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.sign.
*/
static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t scheme,
chunk_t data, chunk_t *signature)
switch (scheme)
{
case SIGN_DEFAULT:
- /* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1:
return build_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256:
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.decrypt.
*/
static bool decrypt(private_openssl_rsa_private_key_t *this,
chunk_t crypto, chunk_t *plain)
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.get_keysize.
*/
static size_t get_keysize(private_openssl_rsa_private_key_t *this)
{
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.get_id.
*/
static identification_t* get_id(private_openssl_rsa_private_key_t *this,
id_type_t type)
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.get_public_key.
*/
static openssl_rsa_public_key_t* get_public_key(private_openssl_rsa_private_key_t *this)
{
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.equals.
+ */
+static bool equals(private_openssl_rsa_private_key_t *this, private_key_t *other)
+{
+ identification_t *keyid;
+
+ if (&this->public.interface == other)
+ {
+ return TRUE;
+ }
+ if (other->get_type(other) != KEY_RSA)
+ {
+ return FALSE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid))
+ {
+ return TRUE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid_info))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implementation of openssl_rsa_private_key.belongs_to.
*/
static bool belongs_to(private_openssl_rsa_private_key_t *this, public_key_t *public)
{
}
/**
- * Implementation of openssl_rsa_private_key.destroy.
+ * Implementation of openssl_rsa_private_key.get_ref.
*/
static private_openssl_rsa_private_key_t* get_ref(private_openssl_rsa_private_key_t *this)
{
{
private_openssl_rsa_private_key_t *this = malloc_thing(private_openssl_rsa_private_key_t);
- this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
- this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
- this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
- this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
- this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
- this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
- this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
- this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
- this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
- this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
+ this->public.interface.get_type = (key_type_t (*) (private_key_t*))get_type;
+ this->public.interface.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign;
+ this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt;
+ this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize;
+ this->public.interface.get_id = (identification_t* (*) (private_key_t*, id_type_t))get_id;
+ this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key;
+ this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals;
+ this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to;
+ this->public.interface.get_encoding = (chunk_t(*) (private_key_t*))get_encoding;
+ this->public.interface.get_ref = (private_key_t* (*) (private_key_t*))get_ref;
+ this->public.interface.destroy = (void (*) (private_key_t*))destroy;
this->engine = FALSE;
this->keyid = NULL;
switch (scheme)
{
case SIGN_DEFAULT:
- /* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1:
return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256:
}
/**
+ * Implementation of public_key_t.equals.
+ */
+static bool equals(private_openssl_rsa_public_key_t *this, public_key_t *other)
+{
+ identification_t *keyid;
+
+ if (&this->public.interface == other)
+ {
+ return TRUE;
+ }
+ if (other->get_type(other) != KEY_RSA)
+ {
+ return FALSE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid))
+ {
+ return TRUE;
+ }
+ keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1);
+ if (keyid && keyid->equals(keyid, this->keyid_info))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
* Implementation of public_key_t.get_keysize.
*/
static size_t get_keysize(private_openssl_rsa_public_key_t *this)
this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_;
+ this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals;
this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
if (this->public_key == NULL)
{
- DBG1("could not create public key");
goto end;
}
break;
{
private_x509_cert_t *this = malloc_thing(private_x509_cert_t);
- this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
- this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
- this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
- this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
- this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
- this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
- this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
- this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
- this->public.interface.interface.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
- this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
- this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
- this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
- this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy;
+ this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type;
+ this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject;
+ this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_issuer;
+ this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject;
+ this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_issuer;
+ this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by;
+ this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key;
+ this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity;
+ this->public.interface.interface.is_newer = (bool (*) (certificate_t*,certificate_t*))is_newer;
+ this->public.interface.interface.get_encoding = (chunk_t (*) (certificate_t*))get_encoding;
+ this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals;
+ this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref;
+ this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy;
this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags;
this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial;
this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier;
this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2),
- asn1_simple_object(ASN1_INTEGER, this->cert->serialNumber),
+ asn1_integer("c", this->cert->serialNumber),
asn1_algorithmIdentifier(this->cert->algorithm),
issuer->get_encoding(issuer),
asn1_wrap(ASN1_SEQUENCE, "mm",
ocsp.c ocsp.h \
packet.c packet.h \
pem.c pem.h \
-pgp.c pgp.h \
-pkcs1.c pkcs1.h \
+pgpcert.c pgpcert.h \
pkcs7.c pkcs7.h \
plutomain.c \
rcv_whack.c rcv_whack.h \
DBG_log("issuer aacert found")
)
- if (!check_signature(ac->certificateInfo, ac->signature
- , ac->algorithm, ac->algorithm, aacert))
+ if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm,
+ aacert))
{
plog("attribute certificate signature is invalid");
return FALSE;
}
}
- if (!check_signature(cert->tbsCertificate, cert->signature
- , cert->algorithm, cert->algorithm, authcert))
+ if (!x509_check_signature(cert->tbsCertificate, cert->signature,
+ cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("trust_authcert_candidate");
/* Certificate support for IKE authentication
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - 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
#include <freeswan.h>
+#include "library.h"
#include "asn1/asn1.h"
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "id.h"
-#include "x509.h"
-#include "pgp.h"
#include "pem.h"
#include "certs.h"
-#include "pkcs1.h"
/**
* used for initializatin of certs
}
/**
- * Loads a PKCS#1 or PGP private RSA key file
+ * Loads a PKCS#1 or PGP privatekey file
*/
-err_t load_rsa_private_key(char* filename, prompt_pass_t *pass,
- RSA_private_key_t *key)
+private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
+ key_type_t type)
{
- err_t ugh = NULL;
- bool pgp = FALSE;
+ private_key_t *key = NULL;
chunk_t blob = chunk_empty;
+ bool pgp = FALSE;
char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
{
if (pgp)
{
- if (!parse_pgp(blob, NULL, key))
- ugh = "syntax error in PGP private key file";
+ parse_pgp(blob, NULL, &key);
}
else
{
- if (!pkcs1_parse_private_key(blob, key))
- ugh = "syntax error in PKCS#1 private key file";
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+ BUILD_BLOB_ASN1_DER, blob, BUILD_END);
}
+ if (key == NULL)
+ {
+ plog("syntax error in %s private key file", pgp ? "PGP":"PKCS#");
+ }
free(blob.ptr);
}
else
- ugh = "error loading RSA private key file";
-
- return ugh;
+ {
+ plog("error loading RSA private key file");
+ }
+ return key;
}
/**
/* Certificate support for IKE authentication
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - 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
#ifndef _CERTS_H
#define _CERTS_H
-#include "pkcs1.h"
+#include <credentials/keys/private_key.h>
+
#include "x509.h"
-#include "pgp.h"
+#include "pgpcert.h"
/* path definitions for private keys, end certs,
* cacerts, attribute certs and crls
*/
extern bool no_cr_send;
-extern err_t load_rsa_private_key(char* filename, prompt_pass_t *pass
- , RSA_private_key_t *key);
+extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
+ key_type_t type);
extern chunk_t get_mycert(cert_t cert);
-extern bool load_coded_file(char *filename, prompt_pass_t *pass
- , const char *type, chunk_t *blob, bool *pgp);
+extern bool load_coded_file(char *filename, prompt_pass_t *pass,
+ const char *type, chunk_t *blob, bool *pgp);
extern bool load_cert(char *filename, const char *label, cert_t *cert);
extern bool load_host_cert(char *filename, cert_t *cert);
extern bool load_ca_cert(char *filename, cert_t *cert);
#include <freeswan.h>
#include "kameipsec.h"
+#include <credentials/keys/private_key.h>
+
#include "constants.h"
#include "defs.h"
#include "id.h"
#include "x509.h"
#include "ca.h"
#include "crl.h"
-#include "pgp.h"
+#include "pgpcert.h"
#include "certs.h"
#include "ac.h"
#include "smartcard.h"
* If so, treat as a kind of failure.
*/
enum myid_state old_myid_state = myid_state;
- const struct RSA_private_key *our_RSA_pri;
+ private_key_t *private;
err_t ugh = NULL;
myid_state = try_state;
- if (old_myid_state != myid_state
- && old_myid_state == MYID_SPECIFIED)
+ if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED)
{
ugh = "%myid was specified while we were guessing";
}
- else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
+ else if ((private = get_private_key(c)) == NULL)
{
ugh = "we don't know our own RSA key";
}
{
ugh = "all our KEY RRs have the wrong public key";
if (kr->key->alg == PUBKEY_ALG_RSA
- && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
+ && private->belongs_to(private, &kr->key->public_key))
{
ugh = NULL; /* good! */
break;
}
#endif /* USE_KEYRR */
-static err_t
-check_txt_recs(enum myid_state try_state
-, const struct connection *c
-, struct adns_continuation *ac)
+static err_t check_txt_recs(enum myid_state try_state,
+ const struct connection *c,
+ struct adns_continuation *ac)
{
/* Check if TXT lookup yielded good results.
* Looking up based on our ID. Used if
* If so, treat as a kind of failure.
*/
enum myid_state old_myid_state = myid_state;
- const struct RSA_private_key *our_RSA_pri;
+ private_key_t *private;
err_t ugh = NULL;
myid_state = try_state;
{
ugh = "%myid was specified while we were guessing";
}
- else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
+ else if ((private = get_private_key(c)) == NULL)
{
ugh = "we don't know our own RSA key";
}
ugh = "no TXT RR found for us";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
{
+ public_key_t *pub_key = gwp->key->public_key;
+
ugh = "all our TXT RRs have the wrong public key";
- if (gwp->key->alg == PUBKEY_ALG_RSA
- && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ if (pub_key->get_type(pub_key) == KEY_RSA &&
+ private->belongs_to(private, pub_key))
{
ugh = NULL; /* good! */
break;
}
}
if (ugh != NULL)
+ {
myid_state = old_myid_state;
+ }
return ugh;
}
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
- const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* normal situation */
passert(sr != NULL);
- if (our_RSA_pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
ugh = NULL; /* good! */
break;
}
- if (same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
- const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* unless we decide to look for KEY RR */
- if (our_RSA_pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
passert(same_id(&gwp->gw_id, &sr->this.id));
ugh = "TXT RR for us has wrong key";
- if (gwp->gw_key_present
- && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
+ if (gwp->gw_key_present &&
+ private->belongs_to(private, gwp->key->public_key))
{
DBG(DBG_CONTROL,
DBG_log("initiate on demand found TXT with right public key at: %s"
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
- const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* always */
- if (our_RSA_pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
{
ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)";
if (kr->key->alg == PUBKEY_ALG_RSA
- && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
+ && private->belongs_to(private, kr->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
* We must at least be able to find our private key
.*/
if (d->spd.this.sc == NULL /* no smartcard */
- && get_RSA_private_key(d) == NULL) /* no private key */
+ && get_private_key(d) == NULL) /* no private key */
continue;
break;
)
/* check the issuer's signature of the crl */
- valid_sig = check_signature(crl->tbsCertList, crl->signature
- , crl->algorithm, crl->algorithm, issuer_cert);
+ valid_sig = x509_check_signature(crl->tbsCertList, crl->signature,
+ crl->algorithm, issuer_cert);
unlock_authcert_list("insert_crl");
if (!valid_sig)
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
, crl->authKeyID, AUTH_CA);
- valid = check_signature(crl->tbsCertList, crl->signature
- , crl->algorithm, crl->algorithm, issuer_cert);
+ valid = x509_check_signature(crl->tbsCertList, crl->signature,
+ crl->algorithm, issuer_cert);
unlock_authcert_list("verify_by_crl");
#include <freeswan.h>
+#include <utils/identification.h>
+#include <credentials/keys/public_key.h>
+
#include "constants.h"
#include "adns.h" /* needs <resolv.h> */
#include "defs.h"
{
strcpy(adns_path_space, helper_bin_dir);
if (n > 0 && adns_path_space[n -1] != '/')
+ {
adns_path_space[n++] = '/';
+ }
}
}
else
n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));
if (n < 0)
+ {
exit_log_errno((e
, "readlink(\"/proc/self/exe\") failed in init_adns()"));
-
+ }
}
if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))
+ {
exit_log("path to %s is too long", adns_name);
+ }
while (n > 0 && adns_path_space[n - 1] != '/')
+ {
n--;
-
+ }
strcpy(adns_path_space + n, adns_name);
adns_path = adns_path_space;
}
if (access(adns_path, X_OK) < 0)
+ {
exit_log_errno((e, "%s missing or not executable", adns_path));
+ }
if (pipe(qfds) != 0 || pipe(afds) != 0)
+ {
exit_log_errno((e, "pipe(2) failed in init_adns()"));
+ }
adns_pid = fork();
switch (adns_pid)
* Take care to handle case where pipes already use these fds.
*/
if (afds[1] == 0)
+ {
afds[1] = dup(afds[1]); /* avoid being overwritten */
+ }
if (qfds[0] != 0)
{
dup2(qfds[0], 0);
close(qfds[1]);
}
if (afds[0] > 1)
+ {
close(afds[0]);
+ }
if (afds[1] > 1)
+ {
close(afds[1]);
-
+ }
DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));
execlp(adns_path, adns_name, NULL);
exit_log_errno((e, "execlp of %s failed", adns_path));
}
-
default:
/* parent */
close(qfds[0]);
else if (WIFEXITED(status))
{
if (WEXITSTATUS(status) != 0)
+ {
plog("ADNS process exited with status %d"
, (int) WEXITSTATUS(status));
+ }
}
else if (WIFSIGNALED(status))
{
u_char under = *e;
if (p == e)
+ {
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
-
+ }
*e = '\0';
if (*p == '@')
{
err_t ugh = atoid(p, gw_id, FALSE);
if (ugh != NULL)
+ {
return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
, ugh);
+ }
}
else
{
, &ip);
if (ugh != NULL)
+ {
return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
, ugh);
-
+ }
if (isanyaddr(&ip))
+ {
return "gateway address must not be 0.0.0.0 or 0::0";
-
+ }
iptoid(&ip, gw_id);
}
/* is this for us? */
if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)
+ {
return NULL; /* neither interesting nor bad */
+ }
p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */
p += strspn(p, " \t"); /* ignore leading whitespace */
/* decode '(' nnn ')' */
if (*p != '(')
+ {
return "X-IPsec-Server missing '('";
+ }
{
char *e;
p++;
pref = strtoul(p, &e, 0);
if ((u_char *)e == p)
+ {
return "malformed X-IPsec-Server priority";
-
+ }
p = e + strspn(e, " \t");
if (*p != ')')
+ {
return "X-IPsec-Server priority missing ')'";
-
+ }
p++;
p += strspn(p, " \t");
if (pref > 0xFFFF)
+ {
return "X-IPsec-Server priority larger than 0xFFFF";
+ }
}
/* time for '=' */
if (*p != '=')
+ {
return "X-IPsec-Server priority missing '='";
-
+ }
p++;
p += strspn(p, " \t");
/* Decode base 64 encoding of key.
* Similar code is in process_lwdnsq_key.
*/
- u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
- chunk_t kbc;
- struct RSA_public_key r;
-
- err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len
- , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
-
- if (ugh != NULL)
+ u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
+ size_t sz;
+ err_t ugh;
+ chunk_t rfc3110_chunk;
+ public_key_t *key;
+
+ ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz,
+ diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
+ if (ugh)
+ {
return builddiag("malformed key data: %s", ugh);
-
- if (kbc.len > sizeof(kb))
- return builddiag("key data larger than %lu bytes"
- , (unsigned long) sizeof(kb));
-
- kbc.ptr = kb;
- ugh = unpack_RSA_public_key(&r, &kbc);
- if (ugh != NULL)
- return builddiag("invalid key data: %s", ugh);
+ }
+ if (sz > sizeof(buf))
+ {
+ return builddiag("key data larger than %lu bytes",
+ (unsigned long) sizeof(buf));
+ }
+ rfc3110_chunk = chunk_create(buf, sz);
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+ BUILD_BLOB_RFC_3110, rfc3110_chunk,
+ BUILD_END);
+ if (key == NULL)
+ {
+ return builddiag("invalid key data");
+ }
/* now find a key entry to put it in */
- gi.key = public_key_from_rsa(&r);
-
- free_RSA_public_content(&r);
+ gi.key = public_key_from_rsa(key);
unreference_key(&cr->last_info);
cr->last_info = reference_key(gi.key);
{
char cidb[BUF_LEN];
char gwidb[BUF_LEN];
+ identification_t *keyid;
+ public_key_t *pub_key;
idtoa(client_id, cidb, sizeof(cidb));
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
+ pub_key = gi.key->public_key;
+ keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
+
if (gi.gw_key_present)
{
- DBG_log("gateway for %s is %s with key %s"
- , cidb, gwidb, gi.key->u.rsa.keyid);
+ DBG_log("gateway for %s is %s with key %Y"
+ , cidb, gwidb, keyid);
}
else
{
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include <crypto/rngs/rng.h>
+#include <credentials/keys/private_key.h>
+#include <credentials/keys/public_key.h>
#include "constants.h"
#include "defs.h"
return prf_block_size;
}
-/* Create an RSA signature of a hash.
+/* Create a public key signature of a hash.
* Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* Use PKCS#1 version 1.5 encryption of hash (called
* RSAES-PKCS1-V1_5) in PKCS#2.
*/
-static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
- const u_char *hash_val, size_t hash_len)
+static size_t sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
+ u_char *hash_val, size_t hash_len)
{
size_t sz = 0;
smartcard_t *sc = c->spd.this.sc;
if (sc == NULL) /* no smartcard */
{
- const struct RSA_private_key *k = get_RSA_private_key(c);
+ chunk_t hash, sig;
+ private_key_t *private = get_private_key(c);
- if (k == NULL)
+ if (private == NULL)
+ {
return 0; /* failure: no key to use */
-
- sz = k->pub.k;
+ }
+ sz = private->get_keysize(private);
passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
- sign_hash(k, hash_val, hash_len, sig_val, sz);
+ hash = chunk_create(hash_val, hash_len);
+ sig = chunk_create(sig_val, sz);
+ if (!private->sign(private, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
+ {
+ return 0;
+ }
+ memcpy(sig_val, sig.ptr, sz);
+ free(sig.ptr);
}
else if (sc->valid) /* if valid pin then sign hash on the smartcard */
{
- lock_certs_and_keys("RSA_sign_hash");
+ lock_certs_and_keys("sign_hash");
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
- unlock_certs_and_keys("RSA_sign_hash");
+ unlock_certs_and_keys("sign_hash");
return 0;
}
{
plog("failed to get keylength from smartcard");
scx_release_context(sc);
- unlock_certs_and_keys("RSA_sign_hash");
+ unlock_certs_and_keys("sign_hash");
return 0;
}
sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
if (!pkcs11_keep_state)
scx_release_context(sc);
- unlock_certs_and_keys("RSA_sign_hash");
+ unlock_certs_and_keys("sign_hash");
}
return sz;
}
-/* Check a Main Mode RSA Signature against computed hash using RSA public key k.
- *
- * As a side effect, on success, the public key is copied into the
- * state object to record the authenticator.
- *
- * Can fail because wrong public key is used or because hash disagrees.
- * We distinguish because diagnostics should also.
- *
- * The result is NULL if the Signature checked out.
- * Otherwise, the first character of the result indicates
- * how far along failure occurred. A greater character signifies
- * greater progress.
- *
- * Classes:
- * 0 reserved for caller
- * 1 SIG length doesn't match key length -- wrong key
- * 2-8 malformed ECB after decryption -- probably wrong key
- * 9 decrypted hash != computed hash -- probably correct key
- *
- * Although the math should be the same for generating and checking signatures,
- * it is not: the knowledge of the private key allows more efficient (i.e.
- * different) computation for encryption.
- */
-static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
- size_t hash_len, const pb_stream *sig_pbs,
- pubkey_t *kr, struct state *st)
-{
- const u_char *sig_val = sig_pbs->cur;
- size_t sig_len = pbs_left(sig_pbs);
- u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */
- u_char *hash_in_s = &s[sig_len - hash_len];
- const struct RSA_public_key *k = &kr->u.rsa;
-
- /* decrypt the signature -- reversing RSA_sign_hash */
- if (sig_len != k->k)
- {
- /* XXX notification: INVALID_KEY_INFORMATION */
- return "1" "SIG length does not match public key length";
- }
-
- /* actual exponentiation; see PKCS#1 v2.0 5.1 */
- {
- chunk_t temp_s;
- mpz_t c;
-
- n_to_mpz(c, sig_val, sig_len);
- mpz_powm(c, c, &k->e, &k->n);
-
- temp_s = mpz_to_n(c, sig_len); /* back to octets */
- memcpy(s, temp_s.ptr, sig_len);
- free(temp_s.ptr);
- mpz_clear(c);
- }
-
- /* sanity check on signature: see if it matches
- * PKCS#1 v1.5 8.1 encryption-block formatting
- */
- {
- err_t ugh = NULL;
-
- if (s[0] != 0x00)
- ugh = "2" "no leading 00";
- else if (hash_in_s[-1] != 0x00)
- ugh = "3" "00 separator not present";
- else if (s[1] == 0x01)
- {
- const u_char *p;
-
- for (p = &s[2]; p != hash_in_s - 1; p++)
- {
- if (*p != 0xFF)
- {
- ugh = "4" "invalid Padding String";
- break;
- }
- }
- }
- else if (s[1] == 0x02)
- {
- const u_char *p;
-
- for (p = &s[2]; p != hash_in_s - 1; p++)
- {
- if (*p == 0x00)
- {
- ugh = "5" "invalid Padding String";
- break;
- }
- }
- }
- else
- ugh = "6" "Block Type not 01 or 02";
-
- if (ugh != NULL)
- {
- /* note: it might be a good idea to make sure that
- * an observer cannot tell what kind of failure happened.
- * I don't know what this means in practice.
- */
- /* We probably selected the wrong public key for peer:
- * SIG Payload decrypted into malformed ECB
- */
- /* XXX notification: INVALID_KEY_INFORMATION */
- return ugh;
- }
- }
-
- /* We have the decoded hash: see if it matches. */
- if (memcmp(hash_val, hash_in_s, hash_len) != 0)
- {
- /* good: header, hash, signature, and other payloads well-formed
- * good: we could find an RSA Sig key for the peer.
- * bad: hash doesn't match
- * Guess: sides disagree about key to be used.
- */
- DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
- DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
- /* XXX notification: INVALID_HASH_INFORMATION */
- return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed";
- }
-
- /* Success: copy successful key into state.
- * There might be an old one if we previously aborted this
- * state transition.
- */
- unreference_key(&st->st_peer_pubkey);
- st->st_peer_pubkey = reference_key(kr);
-
- return NULL; /* happy happy */
-}
-
/* Check signature against all RSA public keys we can find.
* If we need keys from DNS KEY records, and they haven't been fetched,
* return STF_SUSPEND to ask for asynch DNS lookup.
* If only we had coroutines.
*/
struct tac_state {
- /* RSA_check_signature's args that take_a_crack needs */
struct state *st;
- const u_char *hash_val;
- size_t hash_len;
- const pb_stream *sig_pbs;
-
- /* state carried between calls */
- err_t best_ugh; /* most successful failure */
+ chunk_t hash;
+ chunk_t sig;
int tried_cnt; /* number of keys tried */
- char tried[50]; /* keyids of tried public keys */
- char *tn; /* roof of tried[] */
};
-static bool take_a_crack(struct tac_state *s, pubkey_t *kr,
- const char *story USED_BY_DEBUG)
+static bool take_a_crack(struct tac_state *s, pubkey_t *kr)
{
- err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
- , kr, s->st);
- const struct RSA_public_key *k = &kr->u.rsa;
+ public_key_t *pub_key = kr->public_key;
+ identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
s->tried_cnt++;
- if (ugh == NULL)
+
+ if (pub_key->verify(pub_key, SIGN_RSA_EMSA_PKCS1_NULL, s->hash, s->sig))
{
- DBG(DBG_CRYPT | DBG_CONTROL
- , DBG_log("an RSA Sig check passed with *%s [%s]"
- , k->keyid, story));
+ DBG(DBG_CRYPT | DBG_CONTROL,
+ DBG_log("signature check passed with keyid %Y", keyid)
+ )
+ unreference_key(&s->st->st_peer_pubkey);
+ s->st->st_peer_pubkey = reference_key(kr);
return TRUE;
}
else
{
- DBG(DBG_CRYPT
- , DBG_log("an RSA Sig check failure %s with *%s [%s]"
- , ugh + 1, k->keyid, story));
- if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0])
- s->best_ugh = ugh;
- if (ugh[0] > '0'
- && s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried))
- {
- strcpy(s->tn, " *");
- strcpy(s->tn + 2, k->keyid);
- s->tn += strlen(s->tn);
- }
+ DBG(DBG_CRYPT,
+ DBG_log("signature check failed with keyid %Y", keyid)
+ )
return FALSE;
}
}
static stf_status RSA_check_signature(const struct id* peer, struct state *st,
- const u_char hash_val[MAX_DIGEST_LEN],
+ u_char hash_val[MAX_DIGEST_LEN],
size_t hash_len, const pb_stream *sig_pbs,
#ifdef USE_KEYRR
const pubkey_list_t *keys_from_dns,
{
const struct connection *c = st->st_connection;
struct tac_state s;
- err_t dns_ugh = NULL;
s.st = st;
- s.hash_val = hash_val;
- s.hash_len = hash_len;
- s.sig_pbs = sig_pbs;
-
- s.best_ugh = NULL;
+ s.hash = chunk_create(hash_val, hash_len);
+ s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs));
s.tried_cnt = 0;
- s.tn = s.tried;
/* try all gateway records hung off c */
if (c->policy & POLICY_OPPO)
for (gw = c->gw_info; gw != NULL; gw = gw->next)
{
/* only consider entries that have a key and are for our peer */
- if (gw->gw_key_present
- && same_id(&gw->gw_id, &c->spd.that.id)
- && take_a_crack(&s, gw->key, "key saved from DNS TXT"))
+ if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id)&&
+ take_a_crack(&s, gw->key))
+ {
return STF_OK;
+ }
}
}
for (p = pubkeys; p != NULL; p = *pp)
{
pubkey_t *key = p->key;
+ key_type_t type = key->public_key->get_type(key->public_key);
- if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id))
+ if (type == KEY_RSA && same_id(peer, &key->id))
{
time_t now = time(NULL);
continue; /* continue with next public key */
}
- if (take_a_crack(&s, key, "preloaded key"))
- return STF_OK;
+ if (take_a_crack(&s, key))
+ {
+ return STF_OK;
+ }
}
pp = &p->next;
}
}
- /* if no key was found (evidenced by best_ugh == NULL)
- * and that side of connection is key_from_DNS_on_demand
- * then go search DNS for keys for peer.
+ /* if no key was found and that side of connection is
+ * key_from_DNS_on_demand then go search DNS for keys for peer.
*/
- if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand)
+ if (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand)
{
if (gateways_from_dns != NULL)
{
const struct gw_info *gwp;
for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
- if (gwp->gw_key_present
- && take_a_crack(&s, gwp->key, "key from DNS TXT"))
+ {
+ if (gwp->gw_key_present && take_a_crack(&s, gwp->key))
+ {
return STF_OK;
+ }
+ }
}
#ifdef USE_KEYRR
else if (keys_from_dns != NULL)
const pubkey_list_t *kr;
for (kr = keys_from_dns; kr != NULL; kr = kr->next)
- if (kr->key->alg == PUBKEY_ALG_RSA
- && take_a_crack(&s, kr->key, "key from DNS KEY"))
+ {
+ if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key))
+ {
return STF_OK;
+ }
+ }
}
#endif /* USE_KEYRR */
else
{
char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
- (void) idtoa(peer, id_buf, sizeof(id_buf));
+ idtoa(peer, id_buf, sizeof(id_buf));
- if (s.best_ugh == NULL)
+ if (s.tried_cnt == 0)
{
- if (dns_ugh == NULL)
- loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
- , id_buf);
- else
- loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
- "; DNS search for KEY failed (%s)"
- , id_buf, dns_ugh);
-
- /* ??? is this the best code there is? */
- return STF_FAIL + INVALID_KEY_INFORMATION;
+ loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf);
}
-
- if (s.best_ugh[0] == '9')
+ else if (s.tried_cnt == 1)
{
- loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
- /* XXX Could send notification back */
- return STF_FAIL + INVALID_HASH_INFORMATION;
+ loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
+ " wrong key?; tried %d", id_buf, s.tried_cnt);
+ DBG(DBG_CONTROL,
+ DBG_log("public key for '%s' failed: "
+ "decrypted SIG payload into a malformed ECB", id_buf)
+ )
}
else
{
- if (s.tried_cnt == 1)
- {
- loglog(RC_LOG_SERIOUS
- , "Signature check (on %s) failed (wrong key?); tried%s"
- , id_buf, s.tried);
- DBG(DBG_CONTROL,
- DBG_log("public key for %s failed:"
- " decrypted SIG payload into a malformed ECB (%s)"
- , id_buf, s.best_ugh + 1));
- }
- else
- {
- loglog(RC_LOG_SERIOUS
- , "Signature check (on %s) failed:"
- " tried%s keys but none worked."
- , id_buf, s.tried);
- DBG(DBG_CONTROL,
- DBG_log("all %d public keys for %s failed:"
- " best decrypted SIG payload into a malformed ECB (%s)"
- , s.tried_cnt, id_buf, s.best_ugh + 1));
- }
- return STF_FAIL + INVALID_KEY_INFORMATION;
+ loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
+ "tried %d keys but none worked.", id_buf, s.tried_cnt);
+ DBG(DBG_CONTROL,
+ DBG_log("all %d public keys for '%s' failed: "
+ "best decrypted SIG payload into a malformed ECB",
+ s.tried_cnt, id_buf)
+ )
}
+ return STF_FAIL + INVALID_KEY_INFORMATION;
}
}
{
plog("X.509 certificate rejected");
}
+ DESTROY_IF(cert.public_key);
free_generalNames(cert.subjectAltName, FALSE);
free_generalNames(cert.crlDistributionPoints, FALSE);
}
for (p = pubkeys; p != NULL; p = p->next)
{
pubkey_t *key = p->key;
+ key_type_t type = key->public_key->get_type(key->public_key);
- if (key->alg == PUBKEY_ALG_RSA &&
- same_id(&c->spd.that.id, &key->id) &&
+ if (type == KEY_RSA && same_id(&c->spd.that.id, &key->id) &&
key->until_time == UNDEFINED_TIME)
{
/* found a preloaded public key */
{
/* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS];
- size_t sig_len = RSA_sign_hash(st->st_connection
- , sig_val, hash_val, hash_len);
+ size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
+ hash_len);
if (sig_len == 0)
{
- loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
{
/* SIG_R out */
u_char sig_val[RSA_MAX_OCTETS];
- size_t sig_len = RSA_sign_hash(st->st_connection
- , sig_val, hash_val, hash_len);
+ size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
+ hash_len);
if (sig_len == 0)
{
- loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
+ loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
case vos_our_client:
next_step = vos_his_client;
{
- const struct RSA_private_key *pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
struct gw_info *gwp;
- if (pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own key";
break;
ugh = NULL; /* good! */
break;
}
- else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ else if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
case vos_our_txt:
next_step = vos_his_client;
{
- const struct RSA_private_key *pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
- if (pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own key";
break;
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
#endif
if (gwp->gw_key_present
- && same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
+ && private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
case vos_our_key:
next_step = vos_his_client;
{
- const struct RSA_private_key *pri = get_RSA_private_key(c);
+ private_key_t *private = get_private_key(c);
- if (pri == NULL)
+ if (private == NULL)
{
ugh = "we don't know our own key";
break;
for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next)
{
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
- if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa))
+ if (private->belongs_to(private, kp->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
case vos_his_client:
next_step = vos_done;
{
+ public_key_t *pub_key;
+ identification_t *p1st_keyid;
struct gw_info *gwp;
-
+
/* check that the public key that authenticated
* the ISAKMP SA (p1st) will do for this gateway.
*/
+ pub_key = p1st->st_peer_pubkey->public_key;
+ p1st_keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1);
ugh = "peer's client does not delegate to peer";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
* it implies fetching a KEY from the same
* place we must have gotten it.
*/
- if (!gwp->gw_key_present
- || same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa
- , &gwp->key->u.rsa))
+ if (!gwp->gw_key_present || p1st_keyid->equals(p1st_keyid,
+ gwp->key->public_key->get_id(gwp->key->public_key,
+ ID_PUBKEY_INFO_SHA1))
+ )
{
ugh = NULL; /* good! */
break;
for (p = pubkeys; p != NULL; p = p->next)
{
pubkey_t *key = p->key;
+ key_type_t type = key->public_key->get_type(key->public_key);
int pathlen;
- if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id)
- && trusted_ca(key->issuer, sr->that.ca, &pathlen))
+ if (type == KEY_RSA && same_id(&sr->that.id, &key->id) &&
+ trusted_ca(key->issuer, sr->that.ca, &pathlen))
{
dntoa_or_null(peerca_str, BUF_LEN, key->issuer, "");
escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str));
#include <freeswan.h>
+#include <library.h>
+#include <asn1/asn1.h>
+
#include "constants.h"
#include "defs.h"
#include "mp_defs.h"
#include "id.h"
#include "x509.h"
-#include "pgp.h"
+#include "pgpcert.h"
#include "certs.h"
#include "smartcard.h"
#include "connections.h"
enum PrivateKeyKind kind;
union {
chunk_t preshared_secret;
- RSA_private_key_t RSA_private_key;
xauth_t xauth_secret;
+ private_key_t *private_key;
smartcard_t *smartcard;
} u;
secret_t *next;
};
-static pubkey_t*
-allocate_RSA_public_key(const cert_t cert)
+static public_key_t* get_public_key(const cert_t cert)
{
- pubkey_t *pk = malloc_thing(pubkey_t);
- chunk_t e = chunk_empty, n = chunk_empty;
-
switch (cert.type)
{
- case CERT_PGP:
- e = cert.u.pgp->publicExponent;
- n = cert.u.pgp->modulus;
- break;
- case CERT_X509_SIGNATURE:
- e = cert.u.x509->publicExponent;
- n = cert.u.x509->modulus;
- break;
- default:
- plog("RSA public key allocation error");
+ case CERT_PGP:
+ /*
+ e = cert.u.pgp->publicExponent;
+ n = cert.u.pgp->modulus;
+ init_RSA_public_key(&pk->public_key, e, n);
+ */
+ return NULL;
+ break;
+ case CERT_X509_SIGNATURE:
+ return cert.u.x509->public_key;
+ break;
+ default:
+ return NULL;
}
-
- zero(pk);
- init_RSA_public_key(&pk->u.rsa, e, n);
- DBG(DBG_RAW,
- RSA_show_public_key(&pk->u.rsa)
- )
-
- pk->alg = PUBKEY_ALG_RSA;
- pk->id = empty_id;
- pk->issuer = chunk_empty;
- pk->serial = chunk_empty;
-
- return pk;
}
/*
* free a public key struct
*/
-static void
-free_public_key(pubkey_t *pk)
+static void free_public_key(pubkey_t *pk)
{
+ DESTROY_IF(pk->public_key);
free_id_content(&pk->id);
free(pk->issuer.ptr);
free(pk->serial.ptr);
-
- /* algorithm-specific freeing */
- switch (pk->alg)
- {
- case PUBKEY_ALG_RSA:
- free_RSA_public_content(&pk->u.rsa);
- break;
- default:
- bad_case(pk->alg);
- }
free(pk);
}
* me and the peer. We match the Id (if none, the IP address).
* Failure is indicated by a NULL.
*/
-static const secret_t *
-get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym)
+static const secret_t* get_secret(const struct connection *c,
+ enum PrivateKeyKind kind, bool asym)
{
enum { /* bits */
match_default = 01,
struct id rw_id;
/* is there a certificate assigned to this connection? */
- if (kind == PPK_RSA && c->spd.this.cert.type != CERT_NONE)
+ if (kind == PPK_PUBKEY && c->spd.this.cert.type != CERT_NONE)
{
- pubkey_t *my_public_key = allocate_RSA_public_key(c->spd.this.cert);
+ public_key_t *pub_key = get_public_key(c->spd.this.cert);
for (s = secrets; s != NULL; s = s->next)
{
if (s->kind == kind &&
- same_RSA_public_key(&s->u.RSA_private_key.pub, &my_public_key->u.rsa))
+ s->u.private_key->belongs_to(s->u.private_key, pub_key))
{
best = s;
break; /* we have found the private key - no sense in searching further */
}
}
- free_public_key(my_public_key);
return best;
}
* default to matching any peer.
* A more specific match will trump this.
*/
- if (match == match_me
- && s->ids->next == NULL)
+ if (match == match_me && s->ids->next == NULL)
+ {
match |= match_default;
+ }
}
switch (match)
{
case PPK_PSK:
same = s->u.preshared_secret.len == best->u.preshared_secret.len
- && memeq(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len);
+ && memeq(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len);
break;
- case PPK_RSA:
- /* Dirty trick: since we have code to compare
- * RSA public keys, but not private keys, we
- * make the assumption that equal public keys
- * mean equal private keys. This ought to work.
- */
- same = same_RSA_public_key(&s->u.RSA_private_key.pub
- , &best->u.RSA_private_key.pub);
+ case PPK_PUBKEY:
+ same = s->u.private_key->equals(s->u.private_key, best->u.private_key);
break;
default:
bad_case(kind);
* Failure is indicated by a NULL pointer.
* Note: the result is not to be freed by the caller.
*/
-const chunk_t *
-get_preshared_secret(const struct connection *c)
+const chunk_t* get_preshared_secret(const struct connection *c)
{
const secret_t *s = get_secret(c, PPK_PSK, FALSE);
/* check the existence of an RSA private key matching an RSA public
* key contained in an X.509 or OpenPGP certificate
*/
-bool
-has_private_key(cert_t cert)
+bool has_private_key(cert_t cert)
{
secret_t *s;
bool has_key = FALSE;
- pubkey_t *pubkey = allocate_RSA_public_key(cert);
+ public_key_t *pub_key = get_public_key(cert);
for (s = secrets; s != NULL; s = s->next)
{
- if (s->kind == PPK_RSA &&
- same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa))
+ if (s->kind == PPK_PUBKEY &&
+ s->u.private_key->belongs_to(s->u.private_key, pub_key))
{
has_key = TRUE;
break;
}
}
- free_public_key(pubkey);
return has_key;
}
/*
* get the matching RSA private key belonging to a given X.509 certificate
*/
-const RSA_private_key_t*
-get_x509_private_key(const x509cert_t *cert)
+private_key_t* get_x509_private_key(const x509cert_t *cert)
{
secret_t *s;
- const RSA_private_key_t *pri = NULL;
- const cert_t c = {CERT_X509_SIGNATURE, {(x509cert_t*)cert}};
-
- pubkey_t *pubkey = allocate_RSA_public_key(c);
for (s = secrets; s != NULL; s = s->next)
{
- if (s->kind == PPK_RSA &&
- same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa))
+ if (s->kind == PPK_PUBKEY &&
+ s->u.private_key->belongs_to(s->u.private_key, cert->public_key))
{
- pri = &s->u.RSA_private_key;
- break;
+ return s->u.private_key;
}
}
- free_public_key(pubkey);
- return pri;
+ return NULL;
}
/* find the appropriate RSA private key (see get_secret).
* Failure is indicated by a NULL pointer.
*/
-const RSA_private_key_t *
-get_RSA_private_key(const struct connection *c)
+private_key_t* get_private_key(const struct connection *c)
{
- const secret_t *s = get_secret(c, PPK_RSA, TRUE);
+ const secret_t *s = get_secret(c, PPK_PUBKEY, TRUE);
- return s == NULL? NULL : &s->u.RSA_private_key;
+ return s == NULL? NULL : s->u.private_key;
}
/* digest a secrets file
*/
/* parse PSK from file */
-static err_t
-process_psk_secret(chunk_t *psk)
+static err_t process_psk_secret(chunk_t *psk)
{
err_t ugh = NULL;
return ugh;
}
-/* Parse fields of RSA private key.
- * A braced list of keyword and value pairs.
- * At the moment, each field is required, in order.
- * The fields come from BIND 8.2's representation
+const char *rsa_private_keywords[] = {
+ "Modulus",
+ "PublicExponent",
+ "PrivateExponent",
+ "Prime1",
+ "Prime2",
+ "Exponent1",
+ "Exponent2",
+ "Coefficient"
+};
+
+/**
+ * Parse fields of an RSA private key in BIND 8.2's representation
+ * consistiong of a braced list of keyword and value pairs in required order.
+ * Conversion into ASN.1 DER encoded PKCS#1 representation.
*/
-static err_t
-process_rsa_secret(RSA_private_key_t *rsak)
+static err_t process_rsa_secret(private_key_t **key)
{
- char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */
- const struct fld *p;
-
- /* save bytes of Modulus and PublicExponent for keyid calculation */
- unsigned char ebytes[sizeof(buf)];
- unsigned char *eb_next = ebytes;
- chunk_t pub_bytes[2];
- chunk_t *pb_next = &pub_bytes[0];
-
- for (p = RSA_private_field; p < &RSA_private_field[RSA_PRIVATE_FIELD_ELEMENTS]; p++)
+ chunk_t asn1_chunks[countof(rsa_private_keywords)];
+ chunk_t pkcs1_chunk;
+ u_char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */
+ err_t ugh;
+ int i, j;
+ size_t sz, len = 0;
+
+ for (i = 0; i < countof(rsa_private_keywords); i++)
{
- size_t sz;
- err_t ugh;
+ chunk_t rsa_private_key_chunk;
+ const char *keyword = rsa_private_keywords[i];
if (!shift())
{
- return "premature end of RSA key";
+ ugh = "premature end of RSA key";
+ goto end;
}
- else if (!tokeqword(p->name))
+ if (!tokeqword(keyword))
{
- return builddiag("%s keyword not found where expected in RSA key"
- , p->name);
+ ugh = builddiag("%s keyword not found where expected in RSA key"
+ , keyword);
+ goto end;
}
- else if (!(shift()
- && (!tokeq(":") || shift()))) /* ignore optional ":" */
+ if (!(shift() && (!tokeq(":") || shift()))) /* ignore optional ":" */
{
- return "premature end of RSA key";
+ ugh = "premature end of RSA key";
+ goto end;
}
- else if (NULL != (ugh = ttodatav(tok, flp->cur - tok
- , 0, buf, sizeof(buf), &sz, diag_space, sizeof(diag_space)
- , TTODATAV_SPACECOUNTS)))
+ ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz,
+ diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
+ if (ugh)
{
- /* in RSA key, ttodata didn't like */
- return builddiag("RSA data malformed (%s): %s", ugh, tok);
- }
- else
- {
- MP_INT *n = (MP_INT *) ((char *)rsak + p->offset);
-
- n_to_mpz(n, buf, sz);
- if (pb_next < &pub_bytes[countof(pub_bytes)])
- {
- if (eb_next - ebytes + sz > sizeof(ebytes))
- return "public key takes too many bytes";
-
- *pb_next = chunk_create(eb_next, sz);
- memcpy(eb_next, buf, sz);
- eb_next += sz;
- pb_next++;
- }
-#if 0 /* debugging info that compromises security */
- {
- size_t sz = mpz_sizeinbase(n, 16);
- char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */
-
- passert(sz <= sizeof(buf));
- mpz_get_str(buf, 16, n);
-
- loglog(RC_LOG_SERIOUS, "%s: %s", p->name, buf);
- }
-#endif
+ ugh = builddiag("RSA data malformed (%s): %s", ugh, tok);
+ i++;
+ goto end;
}
+ rsa_private_key_chunk = chunk_create(buf, sz);
+ asn1_chunks[i] = asn1_integer("c", rsa_private_key_chunk);
+ len += asn1_chunks[i].len;
}
/* We require an (indented) '}' and the end of the record.
- * We break down the test so that the diagnostic will be
- * more helpful. Some people don't seem to wish to indent
- * the brace!
+ * We break down the test so that the diagnostic will be more helpful.
+ * Some people don't seem to wish to indent the brace!
*/
if (!shift() || !tokeq("}"))
{
- return "malformed end of RSA private key -- indented '}' required";
+ ugh = "malformed end of RSA private key -- indented '}' required";
+ goto end;
}
- else if (shift())
+ if (shift())
{
- return "malformed end of RSA private key -- unexpected token after '}'";
+ ugh = "malformed end of RSA private key -- unexpected token after '}'";
+ goto end;
}
- else
+
+ pkcs1_chunk = asn1_wrap(ASN1_SEQUENCE, "ccccccccc",
+ ASN1_INTEGER_0,
+ asn1_chunks[0],
+ asn1_chunks[1],
+ asn1_chunks[2],
+ asn1_chunks[3],
+ asn1_chunks[4],
+ asn1_chunks[5],
+ asn1_chunks[6],
+ asn1_chunks[7]);
+
+ *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+ BUILD_BLOB_ASN1_DER, pkcs1_chunk,
+ BUILD_END);
+ free(pkcs1_chunk.ptr);
+ if (*key == NULL)
{
- unsigned bits = mpz_sizeinbase(&rsak->pub.n, 2);
-
- rsak->pub.k = (bits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
- rsak->pub.keyid[0] = '\0'; /* in case of splitkeytoid failure */
- splitkeytoid(pub_bytes[1].ptr, pub_bytes[1].len
- , pub_bytes[0].ptr, pub_bytes[0].len
- , rsak->pub.keyid, sizeof(rsak->pub.keyid));
- return RSA_private_key_sanity(rsak);
+ ugh = "parsing of RSA private key failed";
}
+
+end:
+ for (j = 0 ; j < i; j++)
+ {
+ free(asn1_chunks[j].ptr);
+ }
+ return ugh;
}
-/* process rsa key file protected with optional passphrase which can either be
+/**
+ * process a key file protected with optional passphrase which can either be
* read from ipsec.secrets or prompted for by using whack
*/
-static err_t
-process_rsa_keyfile(RSA_private_key_t *rsak, int whackfd)
+static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd)
{
char filename[BUF_LEN];
prompt_pass_t pass;
if (tokeqword("%prompt"))
{
if (pass.fd == NULL_FD)
- return "RSA private key file -- enter passphrase using 'ipsec secrets'";
+ {
+ return "Private key file -- enter passphrase using 'ipsec secrets'";
+ }
pass.prompt = TRUE;
}
else
len -= 2;
}
if (len > PROMPT_PASS_LEN)
- return "RSA private key file -- passphrase exceeds 64 characters";
-
+ {
+ return "Private key file -- passphrase exceeds 64 characters";
+ }
memcpy(pass.secret, passphrase, len);
}
if (shift())
- return "RSA private key file -- unexpected token after passphrase";
+ {
+ return "Private key file -- unexpected token after passphrase";
+ }
}
- return load_rsa_private_key(filename, &pass, rsak);
+ *key = load_private_key(filename, &pass, type);
+
+ return key ? NULL : "Private key file -- could not be loaded";
}
-/*
- * process xauth secret read from ipsec.secrets
+/**
+ * Process xauth secret read from ipsec.secrets
*/
-static err_t
-process_xauth(secret_t *s)
+static err_t process_xauth(secret_t *s)
{
chunk_t user_name;
return process_psk_secret(&s->u.xauth_secret.user_password);
}
-/* get XAUTH secret from chained secrets lists
+/**
+ * Get XAUTH secret from chained secrets lists
* only one entry is currently supported
*/
-static bool
-xauth_get_secret(xauth_t *xauth_secret)
+static bool xauth_get_secret(xauth_t *xauth_secret)
{
secret_t *s;
bool found = FALSE;
return found;
}
-/*
+/**
* find a matching secret
*/
-static bool
-xauth_verify_secret(const xauth_peer_t *peer, const xauth_t *xauth_secret)
+static bool xauth_verify_secret(const xauth_peer_t *peer,
+ const xauth_t *xauth_secret)
{
bool found = FALSE;
secret_t *s;
if (s->kind == PPK_XAUTH)
{
if (!chunk_equals(xauth_secret->user_name, s->u.xauth_secret.user_name))
+ {
continue;
+ }
found = TRUE;
if (chunk_equals(xauth_secret->user_password, s->u.xauth_secret.user_password))
+ {
return TRUE;
+ }
}
}
plog("xauth user '%.*s' %s"
return FALSE;
}
-/*
+/**
* the global xauth_module struct is defined here
*/
xauth_module_t xauth_module;
-/*
- * assign the default xauth functions to any null function pointers
+/**
+ * Assign the default xauth functions to any null function pointers
*/
-void
-xauth_defaults(void)
+void xauth_defaults(void)
{
if (xauth_module.get_secret == NULL)
{
}
};
-/*
- * process pin read from ipsec.secrets or prompted for it using whack
+/**
+ * Process pin read from ipsec.secrets or prompted for it using whack
*/
-static err_t
-process_pin(secret_t *s, int whackfd)
+static err_t process_pin(secret_t *s, int whackfd)
{
smartcard_t *sc;
const char *pin_status = "no pin";
return NULL;
}
-static void
-log_psk(secret_t *s)
+static void log_psk(secret_t *s)
{
int n = 0;
char buf[BUF_LEN];
plog(" loaded shared key for %.*s", n, buf);
}
-static void
-process_secret(secret_t *s, int whackfd)
+static void process_secret(secret_t *s, int whackfd)
{
err_t ugh = NULL;
/* RSA key: the fun begins.
* A braced list of keyword and value pairs.
*/
- s->kind = PPK_RSA;
+ s->kind = PPK_PUBKEY;
if (!shift())
{
ugh = "bad RSA key syntax";
}
else if (tokeq("{"))
{
- ugh = process_rsa_secret(&s->u.RSA_private_key);
+ ugh = process_rsa_secret(&s->u.private_key);
+ }
+ else
+ {
+ ugh = process_keyfile(&s->u.private_key, KEY_RSA, whackfd);
+ }
+ }
+ else if (tokeqword("ecdsa"))
+ {
+ s->kind = PPK_PUBKEY;
+ if (!shift())
+ {
+ ugh = "bad ECDSA key syntax";
}
else
{
- ugh = process_rsa_keyfile(&s->u.RSA_private_key, whackfd);
+ ugh = process_keyfile(&s->u.private_key, KEY_ECDSA, whackfd);
}
}
else if (tokeqword("xauth"))
static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */
-static void
-process_secret_records(int whackfd)
+static void process_secret_records(int whackfd)
{
/* read records from ipsec.secrets and load them into our table */
for (;;)
}
}
-static int
-globugh(const char *epath, int eerrno)
+static int globugh(const char *epath, int eerrno)
{
log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath);
return 1; /* stop glob */
}
-static void
-process_secrets_file(const char *file_pat, int whackfd)
+static void process_secrets_file(const char *file_pat, int whackfd)
{
struct file_lex_position pos;
char **fnp;
globfree(&globbuf);
}
-void
-free_preshared_secrets(void)
+void free_preshared_secrets(void)
{
lock_certs_and_keys("free_preshared_secrets");
case PPK_PSK:
free(s->u.preshared_secret.ptr);
break;
- case PPK_RSA:
- free_RSA_private_content(&s->u.RSA_private_key);
+ case PPK_PUBKEY:
+ DESTROY_IF(s->u.private_key);
break;
case PPK_XAUTH:
free(s->u.xauth_secret.user_name.ptr);
unlock_certs_and_keys("free_preshard_secrets");
}
-void
-load_preshared_secrets(int whackfd)
+void load_preshared_secrets(int whackfd)
{
free_preshared_secrets();
(void) process_secrets_file(shared_secrets_file, whackfd);
* Note: caller must set dns_auth_level.
*/
-pubkey_t *
-public_key_from_rsa(const RSA_public_key_t *k)
+pubkey_t* public_key_from_rsa(public_key_t *key)
{
pubkey_t *p = malloc_thing(pubkey_t);
p->id = empty_id; /* don't know, doesn't matter */
p->issuer = chunk_empty;
p->serial = chunk_empty;
- p->alg = PUBKEY_ALG_RSA;
-
- memcpy(p->u.rsa.keyid, k->keyid, sizeof(p->u.rsa.keyid));
- p->u.rsa.k = k->k;
- mpz_init_set(&p->u.rsa.e, &k->e);
- mpz_init_set(&p->u.rsa.n, &k->n);
+ p->public_key = key;
/* note that we return a 1 reference count upon creation:
* invariant: recount > 0.
/* Free a public key record.
* As a convenience, this returns a pointer to next.
*/
-pubkey_list_t *
-free_public_keyentry(pubkey_list_t *p)
+pubkey_list_t* free_public_keyentry(pubkey_list_t *p)
{
pubkey_list_t *nxt = p->next;
return nxt;
}
-void
-free_public_keys(pubkey_list_t **keys)
+void free_public_keys(pubkey_list_t **keys)
{
while (*keys != NULL)
*keys = free_public_keyentry(*keys);
pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */
-void
-free_remembered_public_keys(void)
+void free_remembered_public_keys(void)
{
free_public_keys(&pubkeys);
}
-/* transfer public keys from *keys list to front of pubkeys list */
-void
-transfer_to_public_keys(struct gw_info *gateways_from_dns
+/**
+ * Transfer public keys from *keys list to front of pubkeys list
+ */
+void transfer_to_public_keys(struct gw_info *gateways_from_dns
#ifdef USE_KEYRR
, pubkey_list_t **keys
#endif /* USE_KEYRR */
#endif /* USE_KEYRR */
}
-/* decode of RSA pubkey chunk
- * - format specified in RFC 2537 RSA/MD5 Keys and SIGs in the DNS
- * - exponent length in bytes (1 or 3 octets)
- * + 1 byte if in [1, 255]
- * + otherwise 0x00 followed by 2 bytes of length
- * - exponent
- * - modulus
- */
-err_t
-unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey)
-{
- chunk_t exp;
- chunk_t mod;
-
- if (pubkey->len < 3)
- return "RSA public key blob way to short"; /* not even room for length! */
-
- if (pubkey->ptr[0] != 0x00)
- {
- exp = chunk_create(pubkey->ptr + 1, pubkey->ptr[0]);
- }
- else
- {
- exp = chunk_create(pubkey->ptr + 3,
- (pubkey->ptr[1] << BITS_PER_BYTE) + pubkey->ptr[2]);
- }
-
- if (pubkey->len - (exp.ptr - pubkey->ptr) < exp.len + RSA_MIN_OCTETS_RFC)
- {
- return "RSA public key blob too short";
- }
-
- mod.ptr = exp.ptr + exp.len;
- mod.len = &pubkey->ptr[pubkey->len] - mod.ptr;
-
- if (mod.len < RSA_MIN_OCTETS)
- return RSA_MIN_OCTETS_UGH;
-
- if (mod.len > RSA_MAX_OCTETS)
- return RSA_MAX_OCTETS_UGH;
-
- init_RSA_public_key(rsa, exp, mod);
- rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */
- rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */
- DBG(DBG_RAW,
- RSA_show_public_key(rsa)
- )
-
- if (rsa->k != mod.len)
- {
- mpz_clear(&rsa->e);
- mpz_clear(&rsa->n);
- return "RSA modulus shorter than specified";
- }
-
- return NULL;
-}
-static void
-install_public_key(pubkey_t *pk, pubkey_list_t **head)
+static void install_public_key(pubkey_t *pk, pubkey_list_t **head)
{
pubkey_list_t *p = malloc_thing(pubkey_list_t);
*head = p;
}
-
-void
-delete_public_keys(const struct id *id, enum pubkey_alg alg
-, chunk_t issuer, chunk_t serial)
+void delete_public_keys(const struct id *id, key_type_t type,
+ chunk_t issuer, chunk_t serial)
{
pubkey_list_t **pp, *p;
pubkey_t *pk;
+ key_type_t pk_type;
for (pp = &pubkeys; (p = *pp) != NULL; )
{
pk = p->key;
+ pk_type = pk->public_key->get_type(pk->public_key);
- if (same_id(id, &pk->id) && pk->alg == alg
+ if (same_id(id, &pk->id) && pk_type == type
&& (issuer.ptr == NULL || pk->issuer.ptr == NULL
|| same_dn(issuer, pk->issuer))
&& same_serial(serial, pk->serial))
+ {
*pp = free_public_keyentry(p);
+ }
else
+ {
pp = &p->next;
+ }
}
}
-pubkey_t *
-reference_key(pubkey_t *pk)
+pubkey_t* reference_key(pubkey_t *pk)
{
pk->refcnt++;
return pk;
free_public_key(pk);
}
-err_t
-add_public_key(const struct id *id, enum dns_auth_level dns_auth_level,
- enum pubkey_alg alg, const chunk_t *key, pubkey_list_t **head)
+bool add_public_key(const struct id *id, enum dns_auth_level dns_auth_level,
+ enum pubkey_alg alg, chunk_t rfc3110_key,
+ pubkey_list_t **head)
{
+ public_key_t *key = NULL;
pubkey_t *pk;
- pk = malloc_thing(pubkey_t); zero(pk);
-
/* first: algorithm-specific decoding of key chunk */
switch (alg)
{
- case PUBKEY_ALG_RSA:
- {
- err_t ugh = unpack_RSA_public_key(&pk->u.rsa, key);
-
- if (ugh != NULL)
+ case PUBKEY_ALG_RSA:
+ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
+ BUILD_BLOB_RFC_3110, rfc3110_key,
+ BUILD_END);
+ if (key == NULL)
{
- free(pk);
- return ugh;
+ return FALSE;
}
- }
- break;
- default:
- bad_case(alg);
+ break;
+ default:
+ bad_case(alg);
}
+ pk = malloc_thing(pubkey_t);
+ zero(pk);
+ pk->public_key = key;
pk->id = *id;
pk->dns_auth_level = dns_auth_level;
- pk->alg = alg;
pk->until_time = UNDEFINED_TIME;
pk->issuer = chunk_empty;
pk->serial = chunk_empty;
-
install_public_key(pk, head);
- return NULL;
+ return TRUE;
}
/* extract id and public key from x.509 certificate and
* insert it into a pubkeyrec
*/
-void
-add_x509_public_key(x509cert_t *cert , time_t until
- , enum dns_auth_level dns_auth_level)
+void add_x509_public_key(x509cert_t *cert , time_t until,
+ enum dns_auth_level dns_auth_level)
{
generalName_t *gn;
pubkey_t *pk;
- cert_t c = { CERT_X509_SIGNATURE, {cert} };
-
- /* we support RSA only */
- if (cert->subjectPublicKeyAlgorithm != PUBKEY_ALG_RSA)
- return;
+ key_type_t pk_type;
/* ID type: ID_DER_ASN1_DN (X.509 subject field) */
- pk = allocate_RSA_public_key(c);
+ pk = malloc_thing(pubkey_t);
+ zero(pk);
+ pk->public_key = cert->public_key->get_ref(cert->public_key);
pk->id.kind = ID_DER_ASN1_DN;
pk->id.name = cert->subject;
pk->dns_auth_level = dns_auth_level;
pk->until_time = until;
pk->issuer = cert->issuer;
pk->serial = cert->serialNumber;
- delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial);
+ pk_type = pk->public_key->get_type(pk->public_key);
+ delete_public_keys(&pk->id, pk_type, pk->issuer, pk->serial);
install_public_key(pk, &pubkeys);
gn = cert->subjectAltName;
gntoid(&id, gn);
if (id.kind != ID_ANY)
{
- pk = allocate_RSA_public_key(c);
+ pk = malloc_thing(pubkey_t);
+ zero(pk);
+ pk->public_key = cert->public_key->get_ref(cert->public_key);
pk->id = id;
pk->dns_auth_level = dns_auth_level;
pk->until_time = until;
pk->issuer = cert->issuer;
pk->serial = cert->serialNumber;
- delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial);
+ delete_public_keys(&pk->id, pk_type, pk->issuer, pk->serial);
install_public_key(pk, &pubkeys);
}
gn = gn->next;
/* extract id and public key from OpenPGP certificate and
* insert it into a pubkeyrec
*/
-void
-add_pgp_public_key(pgpcert_t *cert , time_t until
- , enum dns_auth_level dns_auth_level)
+void add_pgp_public_key(pgpcert_t *cert , time_t until,
+ enum dns_auth_level dns_auth_level)
{
pubkey_t *pk;
- cert_t c;
-
- c.type = CERT_PGP;
- c.u.pgp = cert;
-
- /* we support RSA only */
- if (cert->pubkeyAlg != PUBKEY_ALG_RSA)
- {
- plog(" RSA public keys supported only");
- return;
- }
+ key_type_t pk_type;
- pk = allocate_RSA_public_key(c);
+ pk = malloc_thing(pubkey_t);
+ zero(pk);
+ pk->public_key = cert->public_key->get_ref(cert->public_key);
pk->id.kind = ID_KEY_ID;
- pk->id.name.ptr = cert->fingerprint;
- pk->id.name.len = PGP_FINGERPRINT_SIZE;
+ pk->id.name = cert->fingerprint->get_encoding(cert->fingerprint);
+ pk->id.name = chunk_clone(pk->id.name);
pk->dns_auth_level = dns_auth_level;
pk->until_time = until;
- delete_public_keys(&pk->id, pk->alg, chunk_empty, chunk_empty);
+ pk_type = pk->public_key->get_type(pk->public_key);
+ delete_public_keys(&pk->id, pk_type, chunk_empty, chunk_empty);
install_public_key(pk, &pubkeys);
}
/* when a X.509 certificate gets revoked, all instances of
* the corresponding public key must be removed
*/
-void
-remove_x509_public_key(const x509cert_t *cert)
+void remove_x509_public_key(const x509cert_t *cert)
{
- const cert_t c = {CERT_X509_SIGNATURE, {(x509cert_t*)cert}};
+ public_key_t *revoked_key = cert->public_key;
pubkey_list_t *p, **pp;
- pubkey_t *revoked_pk;
- revoked_pk = allocate_RSA_public_key(c);
- p = pubkeys;
- pp = &pubkeys;
+ p = pubkeys;
+ pp = &pubkeys;
while(p != NULL)
- {
- if (same_RSA_public_key(&p->key->u.rsa, &revoked_pk->u.rsa))
+ {
+ if (revoked_key->equals(revoked_key, p->key->public_key))
{
/* remove p from list and free memory */
*pp = free_public_keyentry(p);
}
p =*pp;
}
- free_public_key(revoked_pk);
}
/*
while (p != NULL)
{
pubkey_t *key = p->key;
+ public_key_t *public = key->public_key;
+ identification_t *keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
+ char buf[BUF_LEN];
- if (key->alg == PUBKEY_ALG_RSA)
+ idtoa(&key->id, buf, BUF_LEN);
+ whack_log(RC_COMMENT,"%T, '%s'", &key->installed_time, utc, buf);
+ whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s",
+ key_type_names, public->get_type(public),
+ public->get_keysize(public) * BITS_PER_BYTE,
+ &key->until_time, utc,
+ check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE));
+ whack_log(RC_COMMENT," keyid: %Y", keyid);
+ if (key->issuer.len > 0)
{
- char buf[BUF_LEN];
-
- idtoa(&key->id, buf, BUF_LEN);
- whack_log(RC_COMMENT, "%T, %4d RSA Key %s, until %T %s",
- &key->installed_time, utc,
- 8*key->u.rsa.k, key->u.rsa.keyid,
- &key->until_time, utc,
- check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE));
- whack_log(RC_COMMENT," %s '%s'",
- enum_show(&ident_names, key->id.kind), buf);
- if (key->issuer.len > 0)
- {
- dntoa(buf, BUF_LEN, key->issuer);
- whack_log(RC_COMMENT," issuer: '%s'", buf);
- }
- if (key->serial.len > 0)
- {
- datatot(key->serial.ptr, key->serial.len, ':'
- , buf, BUF_LEN);
- whack_log(RC_COMMENT," serial: %s", buf);
- }
+ dntoa(buf, BUF_LEN, key->issuer);
+ whack_log(RC_COMMENT," issuer: '%s'", buf);
+ }
+ if (key->serial.len > 0)
+ {
+ datatot(key->serial.ptr, key->serial.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT," serial: %s", buf);
}
p = p->next;
}
/* mechanisms for preshared keys (public, private, and preshared secrets)
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
+ * Copyright (C) 2009 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
#ifndef _KEYS_H
#define _KEYS_H
-#include <gmp.h> /* GNU Multi-Precision library */
+#include <credentials/keys/private_key.h>
+#include <credentials/keys/public_key.h>
-#include "pkcs1.h"
#include "certs.h"
#ifndef SHARED_SECRETS_FILE
enum PrivateKeyKind {
PPK_PSK,
- /* PPK_DSS, */ /* not implemented */
- PPK_RSA,
+ PPK_PUBKEY,
PPK_XAUTH,
PPK_PIN
};
struct connection;
extern const chunk_t *get_preshared_secret(const struct connection *c);
-extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
-extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
-extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
+extern private_key_t *get_private_key(const struct connection *c);
+extern private_key_t *get_x509_private_key(const x509cert_t *cert);
/* public key machinery */
, until_time;
chunk_t issuer;
chunk_t serial;
- enum pubkey_alg alg;
- union {
- RSA_public_key_t rsa;
- } u;
+ public_key_t *public_key;
};
typedef struct pubkey_list pubkey_list_t;
extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */
-extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k);
+extern pubkey_t *public_key_from_rsa(public_key_t *key);
extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
extern void free_public_keys(pubkey_list_t **keys);
extern void free_remembered_public_keys(void);
-extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
- , chunk_t issuer, chunk_t serial);
-
+extern void delete_public_keys(const struct id *id, key_type_t type,
+ chunk_t issuer, chunk_t serial);
extern pubkey_t *reference_key(pubkey_t *pk);
extern void unreference_key(pubkey_t **pkp);
-extern err_t add_public_key(const struct id *id
- , enum dns_auth_level dns_auth_level
- , enum pubkey_alg alg
- , const chunk_t *key
- , pubkey_list_t **head);
+extern bool add_public_key(const struct id *id,
+ enum dns_auth_level dns_auth_level,
+ enum pubkey_alg alg,
+ chunk_t rfc3110_key,
+ pubkey_list_t **head);
extern bool has_private_key(cert_t cert);
extern void add_x509_public_key(x509cert_t *cert, time_t until
#include "certs.h"
#include "smartcard.h"
#include "whack.h"
-#include "pkcs1.h"
#include "keys.h"
#include "fetch.h"
#include "ocsp.h"
static smartcard_t *ocsp_requestor_sc = NULL;
-static const struct RSA_private_key *ocsp_requestor_pri = NULL;
+static private_key_t *ocsp_requestor_key = NULL;
/**
* ASN.1 definition of ocspResponse
*/
static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
{
+ hasher_t *hasher;
static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */
-
+
location->uri = cert->accessLocation;
if (location->uri.ptr == NULL)
}
}
+ /* compute authNameID from as SHA-1 hash of issuer DN */
location->authNameID = chunk_create(digest, HASH_SIZE_SHA1);
- compute_digest(cert->issuer, OID_SHA1, &location->authNameID);
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (hasher == NULL)
+ {
+ return FALSE;
+ }
+ hasher->get_hash(hasher, cert->issuer, digest);
+ hasher->destroy(hasher);
location->next = NULL;
location->issuer = cert->issuer;
/* initialize temporary static storage */
ocsp_requestor_cert = NULL;
ocsp_requestor_sc = NULL;
- ocsp_requestor_pri = NULL;
+ ocsp_requestor_key = NULL;
for (;;)
{
else
{
/* look for a matching private key in the chained list */
- const struct RSA_private_key *pri = get_x509_private_key(cert);
+ private_key_t *private = get_x509_private_key(cert);
- if (pri != NULL)
+ if (private != NULL)
{
DBG(DBG_CONTROL,
DBG_log("matching private key found")
)
ocsp_requestor_cert = cert;
- ocsp_requestor_pri = pri;
+ ocsp_requestor_key = private;
return TRUE;
}
}
return FALSE;
}
-static chunk_t generate_signature(chunk_t digest, smartcard_t *sc,
- const RSA_private_key_t *pri)
+static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc)
{
- chunk_t sigdata;
+ hasher_t *hasher;
u_char *pos;
+ u_char digest_buf[HASH_SIZE_SHA1];
+ chunk_t digest = chunk_from_buf(digest_buf);
+ chunk_t digest_info, sigdata;
size_t siglen = 0;
- if (sc != NULL)
+ if (!scx_establish_context(sc) || !scx_login(sc))
{
- /* RSA signature is done on smartcard */
-
- if (!scx_establish_context(sc) || !scx_login(sc))
- {
- scx_release_context(sc);
- return chunk_empty;
- }
+ scx_release_context(sc);
+ return chunk_empty;
+ }
- siglen = scx_get_keylength(sc);
+ siglen = scx_get_keylength(sc);
- if (siglen == 0)
- {
- plog("failed to get keylength from smartcard");
- scx_release_context(sc);
- return chunk_empty;
- }
+ if (siglen == 0)
+ {
+ plog("failed to get keylength from smartcard");
+ scx_release_context(sc);
+ return chunk_empty;
+ }
- DBG(DBG_CONTROL | DBG_CRYPT,
- DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
- , (int)sc->slot, sc->id)
- )
+ DBG(DBG_CONTROL | DBG_CRYPT,
+ DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
+ , (int)sc->slot, sc->id)
+ )
- pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
- *pos++ = 0x00;
- scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen);
- if (!pkcs11_keep_state)
- scx_release_context(sc);
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (hasher == NULL)
+ {
+ return chunk_empty;
}
- else
+ hasher->get_hash(hasher, tbs, digest_buf);
+ hasher->destroy(hasher);
+
+ /* according to PKCS#1 v2.1 digest must be packaged into
+ * an ASN.1 structure for encryption
+ */
+ digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
+ , asn1_algorithmIdentifier(OID_SHA1)
+ , asn1_simple_object(ASN1_OCTET_STRING, digest));
+
+ pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
+ *pos++ = 0x00;
+ scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen);
+ free(digest_info.ptr);
+
+ if (!pkcs11_keep_state)
{
- /* RSA signature is done in software */
- siglen = pri->pub.k;
- pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
- *pos++ = 0x00;
- sign_hash(pri, digest.ptr, digest.len, pos, siglen);
+ scx_release_context(sc);
}
return sigdata;
}
static chunk_t build_signature(chunk_t tbsRequest)
{
chunk_t sigdata, certs;
- chunk_t digest_info;
-
- u_char digest_buf[MAX_DIGEST_LEN];
- chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN };
- if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw))
- return chunk_empty;
-
- /* according to PKCS#1 v2.1 digest must be packaged into
- * an ASN.1 structure for encryption
- */
- digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
- , asn1_algorithmIdentifier(OID_SHA1)
- , asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
-
- /* generate the RSA signature */
- sigdata = generate_signature(digest_info
- , ocsp_requestor_sc
- , ocsp_requestor_pri);
- free(digest_info.ptr);
-
- /* has the RSA signature generation been successful? */
+ if (ocsp_requestor_sc != NULL)
+ {
+ /* RSA signature is done on smartcard */
+ sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc);
+ }
+ else
+ {
+ /* RSA signature is done in software */
+ sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key,
+ TRUE);
+ }
if (sigdata.ptr == NULL)
+ {
return chunk_empty;
+ }
/* include our certificate */
certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
DBG_log("ocsp signer cert found")
)
- if (!check_signature(res->tbs, res->signature, res->algorithm
- , res->algorithm, authcert))
+ if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert))
{
plog("signature of ocsp response is invalid");
unlock_authcert_list("valid_ocsp_response");
DBG_log("issuer cacert found")
)
- if (!check_signature(cert->tbsCertificate, cert->signature
- , cert->algorithm, cert->algorithm, authcert))
+ if (!x509_check_signature(cert->tbsCertificate, cert->signature,
+ cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("valid_ocsp_response");
+++ /dev/null
-/* Support of OpenPGP certificates
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- *
- * 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 <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <freeswan.h>
-
-#include <library.h>
-#include <crypto/hashers/hasher.h>
-
-#include "constants.h"
-#include "defs.h"
-#include "mp_defs.h"
-#include "log.h"
-#include "id.h"
-#include "pgp.h"
-#include "certs.h"
-#include "whack.h"
-#include "pkcs1.h"
-#include "keys.h"
-
-/*
- * chained list of OpenPGP end certificates
- */
-static pgpcert_t *pgpcerts = NULL;
-
-/*
- * OpenPGP packet tags defined in section 4.3 of RFC 2440
- */
-#define PGP_PKT_RESERVED 0
-#define PGP_PKT_PUBKEY_ENC_SESSION_KEY 1
-#define PGP_PKT_SIGNATURE 2
-#define PGP_PKT_SYMKEY_ENC_SESSION_KEY 3
-#define PGP_PKT_ONE_PASS_SIGNATURE_PKT 4
-#define PGP_PKT_SECRET_KEY 5
-#define PGP_PKT_PUBLIC_KEY 6
-#define PGP_PKT_SECRET_SUBKEY 7
-#define PGP_PKT_COMPRESSED_DATA 8
-#define PGP_PKT_SYMKEY_ENC_DATA 9
-#define PGP_PKT_MARKER 10
-#define PGP_PKT_LITERAL_DATA 11
-#define PGP_PKT_TRUST 12
-#define PGP_PKT_USER_ID 13
-#define PGP_PKT_PUBLIC_SUBKEY 14
-#define PGP_PKT_ROOF 15
-
-static const char *const pgp_packet_type_name[] = {
- "Reserved",
- "Public-Key Encrypted Session Key Packet",
- "Signature Packet",
- "Symmetric-Key Encrypted Session Key Packet",
- "One-Pass Signature Packet",
- "Secret Key Packet",
- "Public Key Packet",
- "Secret Subkey Packet",
- "Compressed Data Packet",
- "Symmetrically Encrypted Data Packet",
- "Marker Packet",
- "Literal Data Packet",
- "Trust Packet",
- "User ID Packet",
- "Public Subkey Packet"
-};
-
-/*
- * OpenPGP public key algorithms defined in section 9.1 of RFC 2440
- */
-#define PGP_PUBKEY_ALG_RSA 1
-#define PGP_PUBKEY_ALG_RSA_ENC_ONLY 2
-#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY 3
-#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16
-#define PGP_PUBKEY_ALG_DSA 17
-#define PGP_PUBKEY_ALG_ECC 18
-#define PGP_PUBKEY_ALG_ECDSA 19
-#define PGP_PUBKEY_ALG_ELGAMAL 20
-
-/*
- * OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440
- */
-#define PGP_SYM_ALG_PLAIN 0
-#define PGP_SYM_ALG_IDEA 1
-#define PGP_SYM_ALG_3DES 2
-#define PGP_SYM_ALG_CAST5 3
-#define PGP_SYM_ALG_BLOWFISH 4
-#define PGP_SYM_ALG_SAFER 5
-#define PGP_SYM_ALG_DES 6
-#define PGP_SYM_ALG_AES 7
-#define PGP_SYM_ALG_AES_192 8
-#define PGP_SYM_ALG_AES_256 9
-#define PGP_SYM_ALG_TWOFISH 10
-#define PGP_SYM_ALG_ROOF 11
-
-static const char *const pgp_sym_alg_name[] = {
- "Plaintext",
- "IDEA",
- "3DES",
- "CAST5",
- "Blowfish",
- "SAFER",
- "DES",
- "AES",
- "AES-192",
- "AES-256",
- "Twofish"
-};
-
-/*
- * Size of PGP Key ID
- */
-#define PGP_KEYID_SIZE 8
-
-const pgpcert_t empty_pgpcert = {
- NULL , /* *next */
- 0 , /* installed */
- 0 , /* count */
- { NULL, 0 }, /* certificate */
- 0 , /* created */
- 0 , /* until */
- 0 , /* pubkeyAlgorithm */
- { NULL, 0 }, /* modulus */
- { NULL, 0 }, /* publicExponent */
- "" /* fingerprint */
-};
-
-static size_t
-pgp_size(chunk_t *blob, int len)
-{
- size_t size = 0;
-
- blob->len -= len;
- while (len-- > 0)
- size = 256*size + *blob->ptr++;
- return size;
-}
-
-/*
- * extracts the length of a PGP packet
- */
-static size_t
-pgp_old_packet_length(chunk_t *blob)
-{
- /* bits 0 and 1 define the packet length type */
- int len_type = 0x03 & *blob->ptr++;
-
- blob->len--;
-
- /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
- return pgp_size(blob, (len_type == 0)? 1: len_type << 1);
-}
-
-/*
- * extracts PGP packet version (V3 or V4)
- */
-static u_char
-pgp_version(chunk_t *blob)
-{
- u_char version = *blob->ptr++;
- blob->len--;
- DBG(DBG_PARSING,
- DBG_log("L3 - version:");
- DBG_log(" V%d", version)
- )
- return version;
-}
-
-/*
- * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
- */
-static bool
-parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
-{
- u_char version = pgp_version(packet);
-
- if (version < 3 || version > 4)
- {
- plog("PGP packet version V%d not supported", version);
- return FALSE;
- }
-
- /* creation date - 4 bytes */
- cert->created = (time_t)pgp_size(packet, 4);
- DBG(DBG_PARSING,
- DBG_log("L3 - created:");
- DBG_log(" %T", &cert->created, TRUE)
- )
-
- if (version == 3)
- {
- /* validity in days - 2 bytes */
- cert->until = (time_t)pgp_size(packet, 2);
-
- /* validity of 0 days means that the key never expires */
- if (cert->until > 0)
- cert->until = cert->created + 24*3600*cert->until;
-
- DBG(DBG_PARSING,
- DBG_log("L3 - until:");
- DBG_log(" %T", &cert->until, TRUE);
- )
- }
-
- /* public key algorithm - 1 byte */
- DBG(DBG_PARSING,
- DBG_log("L3 - public key algorithm:")
- )
-
- switch (pgp_size(packet, 1))
- {
- case PGP_PUBKEY_ALG_RSA:
- case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
- cert->pubkeyAlg = PUBKEY_ALG_RSA;
- DBG(DBG_PARSING,
- DBG_log(" RSA")
- )
- /* modulus n */
- cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
- cert->modulus.ptr = packet->ptr;
- packet->ptr += cert->modulus.len;
- packet->len -= cert->modulus.len;
- DBG(DBG_PARSING,
- DBG_log("L3 - modulus:")
- )
- DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus);
-
- /* public exponent e */
- cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
- cert->publicExponent.ptr = packet->ptr;
- packet->ptr += cert->publicExponent.len;
- packet->len -= cert->publicExponent.len;
- DBG(DBG_PARSING,
- DBG_log("L3 - public exponent:")
- )
- DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent);
-
- if (version == 3)
- {
- hasher_t *hasher;
-
- /* a V3 fingerprint is the MD5 hash of modulus and public exponent */
-
- hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- if (hasher == NULL)
- {
- plog(" computation of V3 key ID failed, no MD5 hasher is available");
- return FALSE;
- }
- hasher->get_hash(hasher, cert->modulus, NULL);
- hasher->get_hash(hasher, cert->publicExponent, cert->fingerprint);
- hasher->destroy(hasher);
- }
- else
- {
- plog(" computation of V4 key ID not implemented yet");
- }
- break;
- case PGP_PUBKEY_ALG_DSA:
- cert->pubkeyAlg = PUBKEY_ALG_DSA;
- DBG(DBG_PARSING,
- DBG_log(" DSA")
- )
- plog(" DSA public keys not supported");
- return FALSE;
- default:
- cert->pubkeyAlg = 0;
- DBG(DBG_PARSING,
- DBG_log(" other")
- )
- plog(" exotic not RSA public keys not supported");
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440
- */
-static bool
-parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key)
-{
- int i, s2k;
- pgpcert_t cert = empty_pgpcert;
-
- if (!parse_pgp_pubkey_packet(packet, &cert))
- return FALSE;
-
- init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent
- , cert.modulus);
-
- /* string-to-key usage */
- s2k = pgp_size(packet, 1);
-
- DBG(DBG_PARSING,
- DBG_log("L3 - string-to-key: %d", s2k)
- )
-
- if (s2k == 255)
- {
- plog(" string-to-key specifiers not supported");
- return FALSE;
- }
-
- if (s2k >= PGP_SYM_ALG_ROOF)
- {
- plog(" undefined symmetric key algorithm");
- return FALSE;
- }
-
- /* a known symmetric key algorithm is specified*/
- DBG(DBG_PARSING,
- DBG_log(" %s", pgp_sym_alg_name[s2k])
- )
-
- /* private key is unencrypted */
- if (s2k == PGP_SYM_ALG_PLAIN)
- {
- for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++)
- {
- mpz_t u; /* auxiliary variable */
-
- /* compute offset to private key component i*/
- MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset);
-
- switch (i)
- {
- case 2:
- case 3:
- case 4:
- {
- size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
-
- n_to_mpz(n, packet->ptr, len);
- DBG(DBG_PARSING,
- DBG_log("L3 - %s:", RSA_private_field[i].name)
- )
- DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len);
- packet->ptr += len;
- packet->len -= len;
- }
- break;
- case 5: /* dP = d mod (p-1) */
- mpz_init(u);
- mpz_sub_ui(u, &key->p, 1);
- mpz_mod(n, &key->d, u);
- mpz_clear(u);
- break;
- case 6: /* dQ = d mod (q-1) */
- mpz_init(u);
- mpz_sub_ui(u, &key->q, 1);
- mpz_mod(n, &key->d, u);
- mpz_clear(u);
- break;
- case 7: /* qInv = (q^-1) mod p */
- mpz_invert(n, &key->q, &key->p);
- if (mpz_cmp_ui(n, 0) < 0)
- mpz_add(n, n, &key->p);
- passert(mpz_cmp(n, &key->p) < 0);
- break;
- }
- }
- return TRUE;
- }
-
- plog(" %s encryption not supported", pgp_sym_alg_name[s2k]);
- return FALSE;
-}
-
-/*
- * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
- */
-static bool
-parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
-{
- time_t created;
- chunk_t keyid;
- u_char sig_type;
- u_char version = pgp_version(packet);
-
- /* we parse only V3 signature packets */
- if (version != 3)
- return TRUE;
-
- /* size byte must have the value 5 */
- if (pgp_size(packet, 1) != 5)
- {
- plog(" size must be 5");
- return FALSE;
- }
-
- /* signature type - 1 byte */
- sig_type = (u_char)pgp_size(packet, 1);
- DBG(DBG_PARSING,
- DBG_log("L3 - signature type: 0x%2x", sig_type)
- )
-
- /* creation date - 4 bytes */
- created = (time_t)pgp_size(packet, 4);
- DBG(DBG_PARSING,
- DBG_log("L3 - created:");
- DBG_log(" %T", &cert->created, TRUE)
- )
-
- /* key ID of signer - 8 bytes */
- keyid.ptr = packet->ptr;
- keyid.len = PGP_KEYID_SIZE;
- DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
-
- return TRUE;
-}
-
-bool
-parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
-{
- DBG(DBG_PARSING,
- DBG_log("L0 - PGP file:")
- )
- DBG_cond_dump_chunk(DBG_RAW, "", blob);
-
- if (cert != NULL)
- {
- /* parse a PGP certificate file */
- cert->certificate = blob;
- time(&cert->installed);
- }
- else if (key == NULL)
- {
- /* should not occur, nothing to parse */
- return FALSE;
- }
-
- while (blob.len > 0)
- {
- chunk_t packet = chunk_empty;
- u_char packet_tag = *blob.ptr;
-
- DBG(DBG_PARSING,
- DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag)
- )
-
- /* bit 7 must be set */
- if (!(packet_tag & 0x80))
- {
- plog(" incorrect Packet Tag");
- return FALSE;
- }
-
- /* bit 6 set defines new packet format */
- if (packet_tag & 0x40)
- {
- plog(" new PGP packet format not supported");
- return FALSE;
- }
- else
- {
- int packet_type = (packet_tag & 0x3C) >> 2;
-
- packet.len = pgp_old_packet_length(&blob);
- packet.ptr = blob.ptr;
- blob.ptr += packet.len;
- blob.len -= packet.len;
- DBG(DBG_PARSING,
- DBG_log(" %s (%d), old format, %d bytes",
- (packet_type < PGP_PKT_ROOF) ?
- pgp_packet_type_name[packet_type] :
- "Undefined Packet Type", packet_type, (int)packet.len);
- DBG_log("L2 - body:")
- )
- DBG_cond_dump_chunk(DBG_RAW, "", packet);
-
- if (cert != NULL)
- {
- /* parse a PGP certificate */
- switch (packet_type)
- {
- case PGP_PKT_PUBLIC_KEY:
- if (!parse_pgp_pubkey_packet(&packet, cert))
- return FALSE;
- break;
- case PGP_PKT_SIGNATURE:
- if (!parse_pgp_signature_packet(&packet, cert))
- return FALSE;
- break;
- case PGP_PKT_USER_ID:
- DBG(DBG_PARSING,
- DBG_log("L3 - user ID:");
- DBG_log(" '%.*s'", (int)packet.len, packet.ptr)
- )
- break;
- default:
- break;
- }
- }
- else
- {
- /* parse a PGP private key file */
- switch (packet_type)
- {
- case PGP_PKT_SECRET_KEY:
- if (!parse_pgp_secretkey_packet(&packet, key))
- return FALSE;
- break;
- default:
- break;
- }
- }
- }
- }
- return TRUE;
-}
-
-/*
- * compare two OpenPGP certificates
- */
-static bool
-same_pgpcert(pgpcert_t *a, pgpcert_t *b)
-{
- return a->certificate.len == b->certificate.len &&
- memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
-}
-
-/*
- * for each link pointing to the certificate increase the count by one
- */
-void
-share_pgpcert(pgpcert_t *cert)
-{
- if (cert != NULL)
- {
- cert->count++;
- }
-}
-
-/*
- * select the OpenPGP keyid as ID
- */
-void
-select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
-{
- end_id->kind = ID_KEY_ID;
- end_id->name.len = PGP_FINGERPRINT_SIZE;
- end_id->name.ptr = cert->fingerprint;
- end_id->name.ptr = temporary_cyclic_buffer();
- memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE);
-}
-
-/*
- * add an OpenPGP user/host certificate to the chained list
- */
-pgpcert_t*
-add_pgpcert(pgpcert_t *cert)
-{
- pgpcert_t *c = pgpcerts;
-
- while (c != NULL)
- {
- if (same_pgpcert(c, cert)) /* already in chain, free cert */
- {
- free_pgpcert(cert);
- return c;
- }
- c = c->next;
- }
-
- /* insert new cert at the root of the chain */
- cert->next = pgpcerts;
- pgpcerts = cert;
- DBG(DBG_CONTROL | DBG_PARSING,
- DBG_log(" pgp cert inserted")
- )
- return cert;
-}
-
-/* release of a certificate decreases the count by one
- " the certificate is freed when the counter reaches zero
- */
-void
-release_pgpcert(pgpcert_t *cert)
-{
- if (cert != NULL && --cert->count == 0)
- {
- pgpcert_t **pp = &pgpcerts;
- while (*pp != cert)
- pp = &(*pp)->next;
- *pp = cert->next;
- free_pgpcert(cert);
- }
-}
-
-/*
- * free a PGP certificate
- */
-void
-free_pgpcert(pgpcert_t *cert)
-{
- if (cert != NULL)
- {
- free(cert->certificate.ptr);
- free(cert);
- }
-}
-
-/*
- * list all PGP end certificates in a chained list
- */
-void
-list_pgp_end_certs(bool utc)
-{
- pgpcert_t *cert = pgpcerts;
- time_t now;
-
- /* determine the current time */
- time(&now);
-
- if (cert != NULL)
- {
- whack_log(RC_COMMENT, " ");
- whack_log(RC_COMMENT, "List of PGP End certificates:");
- whack_log(RC_COMMENT, " ");
- }
-
- while (cert != NULL)
- {
- unsigned keysize;
- char buf[BUF_LEN];
- cert_t c;
-
- c.type = CERT_PGP;
- c.u.pgp = cert;
-
- whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
- datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN);
- whack_log(RC_COMMENT, " fingerprint: %s", buf);
- form_keyid(cert->publicExponent, cert->modulus, buf, &keysize);
- whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf,
- (has_private_key(c))? ", has private key" : "");
- whack_log(RC_COMMENT, " created: %T", &cert->created, utc);
- whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc,
- check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
- cert = cert->next;
- }
-}
-
+++ /dev/null
-/* Support of OpenPGP certificates
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- *
- * 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 _PGP_H
-#define _PGP_H
-
-#include <crypto/hashers/hasher.h>
-
-#include "pkcs1.h"
-
-/*
- * Length of PGP V3 fingerprint
- */
-#define PGP_FINGERPRINT_SIZE HASH_SIZE_MD5
-
-typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
-
-/* access structure for an OpenPGP certificate */
-
-typedef struct pgpcert pgpcert_t;
-
-struct pgpcert {
- pgpcert_t *next;
- time_t installed;
- int count;
- chunk_t certificate;
- time_t created;
- time_t until;
- enum pubkey_alg pubkeyAlg;
- chunk_t modulus;
- chunk_t publicExponent;
- fingerprint_t fingerprint;
-};
-
-extern const pgpcert_t empty_pgpcert;
-extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key);
-extern void share_pgpcert(pgpcert_t *cert);
-extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
-extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
-extern void list_pgp_end_certs(bool utc);
-extern void release_pgpcert(pgpcert_t *cert);
-extern void free_pgpcert(pgpcert_t *cert);
-
-#endif /* _PGP_H */
--- /dev/null
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - 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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeswan.h>
+
+#include <library.h>
+#include <pgp/pgp.h>
+#include <crypto/hashers/hasher.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "id.h"
+#include "pgpcert.h"
+#include "certs.h"
+#include "whack.h"
+#include "keys.h"
+
+/*
+ * chained list of OpenPGP end certificates
+ */
+static pgpcert_t *pgpcerts = NULL;
+
+/*
+ * OpenPGP packet tags defined in section 4.3 of RFC 2440
+ */
+#define PGP_PKT_RESERVED 0
+#define PGP_PKT_PUBKEY_ENC_SESSION_KEY 1
+#define PGP_PKT_SIGNATURE 2
+#define PGP_PKT_SYMKEY_ENC_SESSION_KEY 3
+#define PGP_PKT_ONE_PASS_SIGNATURE_PKT 4
+#define PGP_PKT_SECRET_KEY 5
+#define PGP_PKT_PUBLIC_KEY 6
+#define PGP_PKT_SECRET_SUBKEY 7
+#define PGP_PKT_COMPRESSED_DATA 8
+#define PGP_PKT_SYMKEY_ENC_DATA 9
+#define PGP_PKT_MARKER 10
+#define PGP_PKT_LITERAL_DATA 11
+#define PGP_PKT_TRUST 12
+#define PGP_PKT_USER_ID 13
+#define PGP_PKT_PUBLIC_SUBKEY 14
+#define PGP_PKT_ROOF 15
+
+static const char *const pgp_packet_type_name[] = {
+ "Reserved",
+ "Public-Key Encrypted Session Key Packet",
+ "Signature Packet",
+ "Symmetric-Key Encrypted Session Key Packet",
+ "One-Pass Signature Packet",
+ "Secret Key Packet",
+ "Public Key Packet",
+ "Secret Subkey Packet",
+ "Compressed Data Packet",
+ "Symmetrically Encrypted Data Packet",
+ "Marker Packet",
+ "Literal Data Packet",
+ "Trust Packet",
+ "User ID Packet",
+ "Public Subkey Packet"
+};
+
+/*
+ * OpenPGP public key algorithms defined in section 9.1 of RFC 2440
+ */
+#define PGP_PUBKEY_ALG_RSA 1
+#define PGP_PUBKEY_ALG_RSA_ENC_ONLY 2
+#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY 3
+#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16
+#define PGP_PUBKEY_ALG_DSA 17
+#define PGP_PUBKEY_ALG_ECC 18
+#define PGP_PUBKEY_ALG_ECDSA 19
+#define PGP_PUBKEY_ALG_ELGAMAL 20
+
+/*
+ * Size of PGP Key ID
+ */
+#define PGP_KEYID_SIZE 8
+
+const pgpcert_t empty_pgpcert = {
+ NULL , /* *next */
+ 0 , /* installed */
+ 0 , /* count */
+ { NULL, 0 }, /* certificate */
+ 0 , /* created */
+ 0 , /* until */
+ NULL , /* public key */
+ NULL /* fingerprint */
+};
+
+
+/*
+ * extracts the length of a PGP packet
+ */
+static size_t pgp_old_packet_length(chunk_t *blob)
+{
+ /* bits 0 and 1 define the packet length type */
+ int len_type = 0x03 & *blob->ptr++;
+
+ blob->len--;
+
+ /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
+ return pgp_length(blob, (len_type == 0)? 1: len_type << 1);
+}
+
+/*
+ * extracts PGP packet version (V3 or V4)
+ */
+static u_char pgp_version(chunk_t *blob)
+{
+ u_char version = *blob->ptr++;
+ blob->len--;
+ DBG(DBG_PARSING,
+ DBG_log("L3 - version:");
+ DBG_log(" V%d", version)
+ )
+ return version;
+}
+
+/*
+ * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
+ */
+static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
+{
+ u_char version = pgp_version(packet);
+ public_key_t *key;
+
+ if (version < 3 || version > 4)
+ {
+ plog("PGP packet version V%d not supported", version);
+ return FALSE;
+ }
+
+ /* creation date - 4 bytes */
+ cert->created = (time_t)pgp_length(packet, 4);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - created:");
+ DBG_log(" %T", &cert->created, TRUE)
+ )
+
+ if (version == 3)
+ {
+ /* validity in days - 2 bytes */
+ cert->until = (time_t)pgp_length(packet, 2);
+
+ /* validity of 0 days means that the key never expires */
+ if (cert->until > 0)
+ {
+ cert->until = cert->created + 24*3600*cert->until;
+ }
+ DBG(DBG_PARSING,
+ DBG_log("L3 - until:");
+ DBG_log(" %T", &cert->until, TRUE);
+ )
+ }
+
+ /* public key algorithm - 1 byte */
+ DBG(DBG_PARSING,
+ DBG_log("L3 - public key algorithm:")
+ )
+
+ switch (pgp_length(packet, 1))
+ {
+ case PGP_PUBKEY_ALG_RSA:
+ case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
+ DBG(DBG_PARSING,
+ DBG_log(" RSA")
+ )
+ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
+ BUILD_BLOB_PGP, *packet,
+ BUILD_END);
+ if (key == NULL)
+ {
+ return FALSE;
+ }
+ cert->public_key = key;
+
+ if (version == 3)
+ {
+ cert->fingerprint = key->get_id(key, ID_KEY_ID);
+ if (cert->fingerprint == NULL)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ plog(" computation of V4 key ID not implemented yet");
+ }
+ break;
+ case PGP_PUBKEY_ALG_DSA:
+ DBG(DBG_PARSING,
+ DBG_log(" DSA")
+ )
+ plog(" DSA public keys not supported");
+ return FALSE;
+ default:
+ DBG(DBG_PARSING,
+ DBG_log(" other")
+ )
+ plog(" exotic not RSA public keys not supported");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
+ */
+static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
+{
+ time_t created;
+ chunk_t keyid;
+ u_char sig_type;
+ u_char version = pgp_version(packet);
+
+ /* we parse only V3 signature packets */
+ if (version != 3)
+ return TRUE;
+
+ /* size byte must have the value 5 */
+ if (pgp_length(packet, 1) != 5)
+ {
+ plog(" size must be 5");
+ return FALSE;
+ }
+
+ /* signature type - 1 byte */
+ sig_type = (u_char)pgp_length(packet, 1);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - signature type: 0x%2x", sig_type)
+ )
+
+ /* creation date - 4 bytes */
+ created = (time_t)pgp_length(packet, 4);
+ DBG(DBG_PARSING,
+ DBG_log("L3 - created:");
+ DBG_log(" %T", &cert->created, TRUE)
+ )
+
+ /* key ID of signer - 8 bytes */
+ keyid.ptr = packet->ptr;
+ keyid.len = PGP_KEYID_SIZE;
+ DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
+
+ return TRUE;
+}
+
+bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key)
+{
+ DBG(DBG_PARSING,
+ DBG_log("L0 - PGP file:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", blob);
+
+ if (cert != NULL)
+ {
+ /* parse a PGP certificate file */
+ cert->certificate = blob;
+ time(&cert->installed);
+ }
+ else if (key == NULL)
+ {
+ /* should not occur, nothing to parse */
+ return FALSE;
+ }
+
+ while (blob.len > 0)
+ {
+ chunk_t packet = chunk_empty;
+ u_char packet_tag = *blob.ptr;
+
+ DBG(DBG_PARSING,
+ DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag)
+ )
+
+ /* bit 7 must be set */
+ if (!(packet_tag & 0x80))
+ {
+ plog(" incorrect Packet Tag");
+ return FALSE;
+ }
+
+ /* bit 6 set defines new packet format */
+ if (packet_tag & 0x40)
+ {
+ plog(" new PGP packet format not supported");
+ return FALSE;
+ }
+ else
+ {
+ int packet_type = (packet_tag & 0x3C) >> 2;
+
+ packet.len = pgp_old_packet_length(&blob);
+ packet.ptr = blob.ptr;
+ blob.ptr += packet.len;
+ blob.len -= packet.len;
+ DBG(DBG_PARSING,
+ DBG_log(" %s (%d), old format, %d bytes",
+ (packet_type < PGP_PKT_ROOF) ?
+ pgp_packet_type_name[packet_type] :
+ "Undefined Packet Type", packet_type, (int)packet.len);
+ DBG_log("L2 - body:")
+ )
+ DBG_cond_dump_chunk(DBG_RAW, "", packet);
+
+ if (cert != NULL)
+ {
+ /* parse a PGP certificate */
+ switch (packet_type)
+ {
+ case PGP_PKT_PUBLIC_KEY:
+ if (!parse_pgp_pubkey_packet(&packet, cert))
+ {
+ return FALSE;
+ }
+ break;
+ case PGP_PKT_SIGNATURE:
+ if (!parse_pgp_signature_packet(&packet, cert))
+ {
+ return FALSE;
+ }
+ break;
+ case PGP_PKT_USER_ID:
+ DBG(DBG_PARSING,
+ DBG_log("L3 - user ID:");
+ DBG_log(" '%.*s'", (int)packet.len, packet.ptr)
+ )
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ /* parse a PGP private key file */
+ switch (packet_type)
+ {
+ case PGP_PKT_SECRET_KEY:
+ *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+ BUILD_BLOB_PGP, packet,
+ BUILD_END);
+ break;
+ default:
+ break;
+ }
+ if (*key == NULL)
+ {
+ return FALSE;
+ }
+
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * compare two OpenPGP certificates
+ */
+static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b)
+{
+ return a->certificate.len == b->certificate.len &&
+ memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
+}
+
+/*
+ * for each link pointing to the certificate increase the count by one
+ */
+void share_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL)
+ {
+ cert->count++;
+ }
+}
+
+/*
+ * select the OpenPGP keyid as ID
+ */
+void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
+{
+ end_id->kind = ID_KEY_ID;
+ end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
+ end_id->name = chunk_clone(end_id->name);
+}
+
+/*
+ * add an OpenPGP user/host certificate to the chained list
+ */
+pgpcert_t* add_pgpcert(pgpcert_t *cert)
+{
+ pgpcert_t *c = pgpcerts;
+
+ while (c != NULL)
+ {
+ if (same_pgpcert(c, cert)) /* already in chain, free cert */
+ {
+ free_pgpcert(cert);
+ return c;
+ }
+ c = c->next;
+ }
+
+ /* insert new cert at the root of the chain */
+ cert->next = pgpcerts;
+ pgpcerts = cert;
+ DBG(DBG_CONTROL | DBG_PARSING,
+ DBG_log(" pgp cert inserted")
+ )
+ return cert;
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void release_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL && --cert->count == 0)
+ {
+ pgpcert_t **pp = &pgpcerts;
+ while (*pp != cert)
+ {
+ pp = &(*pp)->next;
+ }
+ *pp = cert->next;
+ free_pgpcert(cert);
+ }
+}
+
+/*
+ * free a PGP certificate
+ */
+void free_pgpcert(pgpcert_t *cert)
+{
+ if (cert != NULL)
+ {
+ DESTROY_IF(cert->public_key);
+ DESTROY_IF(cert->fingerprint);
+ free(cert->certificate.ptr);
+ free(cert);
+ }
+}
+
+/*
+ * list all PGP end certificates in a chained list
+ */
+void list_pgp_end_certs(bool utc)
+{
+ pgpcert_t *cert = pgpcerts;
+ time_t now;
+
+ /* determine the current time */
+ time(&now);
+
+ if (cert != NULL)
+ {
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of PGP End certificates:");
+ whack_log(RC_COMMENT, " ");
+ }
+
+ while (cert != NULL)
+ {
+ public_key_t *key = cert->public_key;
+ cert_t c;
+
+ c.type = CERT_PGP;
+ c.u.pgp = cert;
+
+ whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
+ whack_log(RC_COMMENT, " fingerprint: %Y", cert->fingerprint);
+ whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
+ key_type_names, key->get_type(key),
+ key->get_keysize(key) * BITS_PER_BYTE,
+ has_private_key(c)? ", has private key" : "");
+ whack_log(RC_COMMENT, " keyid: %Y",
+ key->get_id(key, ID_PUBKEY_INFO_SHA1));
+ whack_log(RC_COMMENT, " created: %T", &cert->created, utc);
+ whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc,
+ check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+ cert = cert->next;
+ }
+}
+
--- /dev/null
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - 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 _PGPCERT_H
+#define _PGPCERT_H
+
+#include <crypto/hashers/hasher.h>
+#include <credentials/keys/private_key.h>
+#include <credentials/keys/public_key.h>
+
+/*
+ * Length of PGP V3 fingerprint
+ */
+#define PGP_FINGERPRINT_SIZE HASH_SIZE_MD5
+
+typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
+
+/* access structure for an OpenPGP certificate */
+
+typedef struct pgpcert pgpcert_t;
+
+struct pgpcert {
+ pgpcert_t *next;
+ time_t installed;
+ int count;
+ chunk_t certificate;
+ time_t created;
+ time_t until;
+ public_key_t *public_key;
+ identification_t *fingerprint;
+};
+
+extern const pgpcert_t empty_pgpcert;
+extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key);
+extern void share_pgpcert(pgpcert_t *cert);
+extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
+extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
+extern void list_pgp_end_certs(bool utc);
+extern void release_pgpcert(pgpcert_t *cert);
+extern void free_pgpcert(pgpcert_t *cert);
+
+#endif /* _PGPCERT_H */
+++ /dev/null
-/* Support of PKCS#1 private key data structures
- * Copyright (C) 2005 Jan Hutter, Martin Willi
- * Copyright (C) 2002-2009 Andreas Steffen
- *
- * HSR 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.
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <freeswan.h>
-
-#include <library.h>
-#include <asn1/asn1.h>
-#include <asn1/asn1_parser.h>
-#include <asn1/oid.h>
-#include <crypto/rngs/rng.h>
-#include <crypto/hashers/hasher.h>
-
-#include "constants.h"
-#include "defs.h"
-#include "mp_defs.h"
-#include "log.h"
-#include "pkcs1.h"
-
-const struct fld RSA_private_field[] =
-{
- { "Modulus", offsetof(RSA_private_key_t, pub.n) },
- { "PublicExponent", offsetof(RSA_private_key_t, pub.e) },
-
- { "PrivateExponent", offsetof(RSA_private_key_t, d) },
- { "Prime1", offsetof(RSA_private_key_t, p) },
- { "Prime2", offsetof(RSA_private_key_t, q) },
- { "Exponent1", offsetof(RSA_private_key_t, dP) },
- { "Exponent2", offsetof(RSA_private_key_t, dQ) },
- { "Coefficient", offsetof(RSA_private_key_t, qInv) },
-};
-
-/**
- * ASN.1 definition of a PKCS#1 RSA private key
- */
-static const asn1Object_t privkeyObjects[] = {
- { 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, "exit", ASN1_EOC, ASN1_EXIT }
-};
-#define PKCS1_PRIV_KEY_VERSION 1
-#define PKCS1_PRIV_KEY_MODULUS 2
-#define PKCS1_PRIV_KEY_PUB_EXP 3
-#define PKCS1_PRIV_KEY_COEFF 9
-
-/**
- * Forms the FreeS/WAN keyid from the public exponent e and modulus n
- */
-void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
-{
- /* eliminate leading zero bytes in modulus from ASN.1 coding */
- while (n.len > 1 && *n.ptr == 0x00)
- {
- n.ptr++; n.len--;
- }
-
- /* form the FreeS/WAN keyid */
- keyid[0] = '\0'; /* in case of splitkeytoid failure */
- splitkeytoid(e.ptr, e.len, n.ptr, n.len, keyid, KEYID_BUF);
-
- /* return the RSA modulus size in octets */
- *keysize = n.len;
-}
-
-/**
- * Initialize an RSA_public_key_t object
- */
-void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
-{
- n_to_mpz(&rsa->e, e.ptr, e.len);
- n_to_mpz(&rsa->n, n.ptr, n.len);
-
- form_keyid(e, n, rsa->keyid, &rsa->k);
-}
-
-#ifdef DEBUG
-static void RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt)
-{
- const struct fld *p;
-
- DBG_log(" keyid: *%s", k->pub.keyid);
-
- for (p = RSA_private_field; p < &RSA_private_field[fieldcnt]; p++)
- {
- MP_INT *n = (MP_INT *) ((char *)k + p->offset);
- size_t sz = mpz_sizeinbase(n, 16);
- char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */
-
- passert(sz <= sizeof(buf));
- mpz_get_str(buf, 16, n);
-
- DBG_log(" %s: 0x%s", p->name, buf);
- }
-}
-
-/**
- * debugging info that compromises security!
- */
-void RSA_show_private_key(RSA_private_key_t *k)
-{
- RSA_show_key_fields(k, countof(RSA_private_field));
-}
-
-void RSA_show_public_key(RSA_public_key_t *k)
-{
- /* Kludge: pretend that it is a private key, but only display the
- * first two fields (which are the public key).
- */
- passert(offsetof(RSA_private_key_t, pub) == 0);
- RSA_show_key_fields((RSA_private_key_t *)k, 2);
-}
-#endif
-
-err_t RSA_private_key_sanity(RSA_private_key_t *k)
-{
- /* note that the *last* error found is reported */
- err_t ugh = NULL;
- mpz_t t, u, q1;
-
-#ifdef DEBUG /* debugging info that compromises security */
- DBG(DBG_PRIVATE, RSA_show_private_key(k));
-#endif
-
- /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
- * We actually require more (for security).
- */
- if (k->pub.k < RSA_MIN_OCTETS)
- return RSA_MIN_OCTETS_UGH;
-
- /* we picked a max modulus size to simplify buffer allocation */
- if (k->pub.k > RSA_MAX_OCTETS)
- return RSA_MAX_OCTETS_UGH;
-
- mpz_init(t);
- mpz_init(u);
- mpz_init(q1);
-
- /* check that n == p * q */
- mpz_mul(u, &k->p, &k->q);
- if (mpz_cmp(u, &k->pub.n) != 0)
- ugh = "n != p * q";
-
- /* check that e divides neither p-1 nor q-1 */
- mpz_sub_ui(t, &k->p, 1);
- mpz_mod(t, t, &k->pub.e);
- if (mpz_cmp_ui(t, 0) == 0)
- ugh = "e divides p-1";
-
- mpz_sub_ui(t, &k->q, 1);
- mpz_mod(t, t, &k->pub.e);
- if (mpz_cmp_ui(t, 0) == 0)
- ugh = "e divides q-1";
-
- /* check that d is e^-1 (mod lcm(p-1, q-1)) */
- /* see PKCS#1v2, aka RFC 2437, for the "lcm" */
- mpz_sub_ui(q1, &k->q, 1);
- mpz_sub_ui(u, &k->p, 1);
- mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */
- mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */
- mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */
-
- mpz_mul(t, &k->d, &k->pub.e);
- mpz_mod(t, t, u);
- if (mpz_cmp_ui(t, 1) != 0)
- ugh = "(d * e) mod (lcm(p-1, q-1)) != 1";
-
- /* check that dP is d mod (p-1) */
- mpz_sub_ui(u, &k->p, 1);
- mpz_mod(t, &k->d, u);
- if (mpz_cmp(t, &k->dP) != 0)
- ugh = "dP is not congruent to d mod (p-1)";
-
- /* check that dQ is d mod (q-1) */
- mpz_sub_ui(u, &k->q, 1);
- mpz_mod(t, &k->d, u);
- if (mpz_cmp(t, &k->dQ) != 0)
- ugh = "dQ is not congruent to d mod (q-1)";
-
- /* check that qInv is (q^-1) mod p */
- mpz_mul(t, &k->qInv, &k->q);
- mpz_mod(t, t, &k->p);
- if (mpz_cmp_ui(t, 1) != 0)
- ugh = "qInv is not conguent ot (q^-1) mod p";
-
- mpz_clear(t);
- mpz_clear(u);
- mpz_clear(q1);
- return ugh;
-}
-
-/**
- * Check the equality of two RSA public keys
- */
-bool same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b)
-{
- return a == b
- || (a->k == b->k && mpz_cmp(&a->n, &b->n) == 0 && mpz_cmp(&a->e, &b->e) == 0);
-}
-
-/**
- * Parses a PKCS#1 private key
- */
-bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
-{
- asn1_parser_t *parser;
- chunk_t object, modulus, exp;
- int objectID;
- bool success = FALSE;
-
- parser = asn1_parser_create(privkeyObjects, blob);
- parser->set_flags(parser, FALSE, TRUE);
-
- while (parser->iterate(parser, &objectID, &object))
- {
- if (objectID == PKCS1_PRIV_KEY_VERSION)
- {
- if (object.len > 0 && *object.ptr != 0)
- {
- plog(" wrong PKCS#1 private key version");
- goto end;
- }
- }
- else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
- objectID <= PKCS1_PRIV_KEY_COEFF)
- {
- MP_INT *u = (MP_INT *) ((char *)key
- + RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
-
- n_to_mpz(u, object.ptr, object.len);
-
- if (objectID == PKCS1_PRIV_KEY_MODULUS)
- modulus = object;
- else if (objectID == PKCS1_PRIV_KEY_PUB_EXP)
- exp = object;
- }
- }
- success = parser->success(parser);
-
-end:
- parser->destroy(parser);
-
- if (success)
- {
- err_t ugh;
-
- form_keyid(exp, modulus, key->pub.keyid, &key->pub.k);
- ugh = RSA_private_key_sanity(key);
- success = (ugh == NULL);
- }
- return success;
-}
-
-/**
- * Compute a digest over a binary blob
- */
-bool compute_digest(chunk_t tbs, int oid, chunk_t *digest)
-{
- hasher_t *hasher;
- hash_algorithm_t alg = hasher_algorithm_from_oid(oid);
-
- if (alg == HASH_UNKNOWN)
- {
- digest->len = 0;
- return FALSE;
- }
-
- hasher = lib->crypto->create_hasher(lib->crypto, alg);
- if (hasher == NULL)
- {
- digest->len = 0;
- return FALSE;
- }
- digest->len = hasher->get_hash_size(hasher);
- hasher->get_hash(hasher, tbs, digest->ptr);
- hasher->destroy(hasher);
- return TRUE;
-}
-
-/**
- * Compute an RSA signature with PKCS#1 padding
- */
-void sign_hash(const RSA_private_key_t *k, const u_char *hash_val,
- size_t hash_len, u_char *sig_val, size_t sig_len)
-{
- chunk_t ch;
- mpz_t t1, t2;
- size_t padlen;
- u_char *p = sig_val;
-
- DBG(DBG_CONTROL | DBG_CRYPT,
- DBG_log("signing hash with RSA Key *%s", k->pub.keyid)
- )
- /* PKCS#1 v1.5 8.1 encryption-block formatting */
- *p++ = 0x00;
- *p++ = 0x01; /* BT (block type) 01 */
- padlen = sig_len - 3 - hash_len;
- memset(p, 0xFF, padlen);
- p += padlen;
- *p++ = 0x00;
- memcpy(p, hash_val, hash_len);
- passert(p + hash_len - sig_val == (ptrdiff_t)sig_len);
-
- /* PKCS#1 v1.5 8.2 octet-string-to-integer conversion */
- n_to_mpz(t1, sig_val, sig_len); /* (could skip leading 0x00) */
-
- /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n
- * Better described in PKCS#1 v2.0 5.1 RSADP.
- * There are two methods, depending on the form of the private key.
- * We use the one based on the Chinese Remainder Theorem.
- */
- mpz_init(t2);
-
- mpz_powm(t2, t1, &k->dP, &k->p); /* m1 = c^dP mod p */
-
- mpz_powm(t1, t1, &k->dQ, &k->q); /* m2 = c^dQ mod Q */
-
- mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
- mpz_mod(t2, t2, &k->p);
- mpz_mul(t2, t2, &k->qInv);
- mpz_mod(t2, t2, &k->p);
-
- mpz_mul(t2, t2, &k->q); /* m = m2 + h q */
- mpz_add(t1, t1, t2);
-
- /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */
- ch = mpz_to_n(t1, sig_len);
- memcpy(sig_val, ch.ptr, sig_len);
- free(ch.ptr);
-
- mpz_clear(t1);
- mpz_clear(t2);
-}
-
-/**
- * Encrypt data with an RSA public key after padding
- */
-chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
-{
- u_char padded[RSA_MAX_OCTETS];
- u_char *pos = padded;
- int padding = key->k - in.len - 3;
- int i;
- rng_t *rng;
-
- if (padding < 8 || key->k > RSA_MAX_OCTETS)
- return chunk_empty;
-
- /* add padding according to PKCS#1 7.2.1 1.+2. */
- *pos++ = 0x00;
- *pos++ = 0x02;
-
- /* pad with pseudo random bytes unequal to zero */
- rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- for (i = 0; i < padding; i++)
- {
- rng->get_bytes(rng, padding, pos);
- while (!*pos)
- {
- rng->get_bytes(rng, 1, pos);
- }
- pos++;
- }
- rng->destroy(rng);
-
- /* append the padding terminator */
- *pos++ = 0x00;
-
- /* now add the data */
- memcpy(pos, in.ptr, in.len);
- DBG(DBG_RAW,
- DBG_dump_chunk("data for rsa encryption:\n", in);
- DBG_dump("padded data for rsa encryption:\n", padded, key->k)
- )
-
- /* convert chunk to integer (PKCS#1 7.2.1 3.a) */
- {
- chunk_t out;
- mpz_t m, c;
-
- mpz_init(c);
- n_to_mpz(m, padded, key->k);
-
- /* encrypt(PKCS#1 7.2.1 3.b) */
- mpz_powm(c, m, &key->e, &key->n);
-
- /* convert integer back to a chunk (PKCS#1 7.2.1 3.c) */
- out = mpz_to_n(c, key->k);
- mpz_clear(c);
- mpz_clear(m);
-
- DBG(DBG_RAW,
- DBG_dump_chunk("rsa encrypted data:\n", out)
- )
- return out;
- }
-}
-
-/**
- * Decrypt data with an RSA private key and remove padding
- */
-bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
-{
- chunk_t padded, plaintext;
- u_char *pos;
- mpz_t t1, t2;
-
- n_to_mpz(t1, in.ptr,in.len);
-
- /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n
- * Better described in PKCS#1 v2.0 5.1 RSADP.
- * There are two methods, depending on the form of the private key.
- * We use the one based on the Chinese Remainder Theorem.
- */
- mpz_init(t2);
-
- mpz_powm(t2, t1, &key->dP, &key->p); /* m1 = c^dP mod p */
- mpz_powm(t1, t1, &key->dQ, &key->q); /* m2 = c^dQ mod Q */
-
- mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
- mpz_mod(t2, t2, &key->p);
- mpz_mul(t2, t2, &key->qInv);
- mpz_mod(t2, t2, &key->p);
-
- mpz_mul(t2, t2, &key->q); /* m = m2 + h q */
- mpz_add(t1, t1, t2);
-
- padded = mpz_to_n(t1, key->pub.k);
- mpz_clear(t1);
- mpz_clear(t2);
-
- DBG(DBG_PRIVATE,
- DBG_dump_chunk("rsa decrypted data with padding:\n", padded)
- )
- pos = padded.ptr;
-
- /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */
-
- /* check for hex pattern 00 02 in decrypted message */
- if ((*pos++ != 0x00) || (*(pos++) != 0x02))
- {
- plog("incorrect padding - probably wrong RSA key");
- chunk_clear(&padded);
- return FALSE;
- }
- padded.len -= 2;
-
- /* the plaintext data starts after first 0x00 byte */
- while (padded.len-- > 0 && *pos++ != 0x00)
-
- if (padded.len == 0)
- {
- plog("no plaintext data");
- free(padded.ptr);
- return FALSE;
- }
-
- plaintext = chunk_create(pos, padded.len);
- *out = chunk_clone(plaintext);
- chunk_clear(&padded);
- return TRUE;
-}
-
-/**
- * Build signatureValue
- */
-chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg,
- const RSA_private_key_t *key, bool bit_string)
-{
-
- size_t siglen = key->pub.k;
-
- u_char digest_buf[MAX_DIGEST_LEN];
- chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
- chunk_t digestInfo, signatureValue;
- u_char *pos;
-
- if (!compute_digest(tbs, hash_alg, &digest))
- {
- return chunk_empty;
- }
-
- /* according to PKCS#1 v2.1 digest must be packaged into
- * an ASN.1 structure for encryption
- */
- digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm"
- , asn1_algorithmIdentifier(hash_alg)
- , asn1_simple_object(ASN1_OCTET_STRING, digest));
-
- /* generate the RSA signature */
- if (bit_string)
- {
- pos = asn1_build_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen);
- *pos++ = 0x00;
- }
- else
- {
- pos = asn1_build_object(&signatureValue, ASN1_OCTET_STRING, siglen);
- }
- sign_hash(key, digestInfo.ptr, digestInfo.len, pos, siglen);
- free(digestInfo.ptr);
-
- return signatureValue;
-}
-
-/**
- * Build a DER-encoded PKCS#1 private key object
- */
-chunk_t pkcs1_build_private_key(const RSA_private_key_t *key)
-{
- chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm"
- , ASN1_INTEGER_0
- , asn1_integer_from_mpz(&key->pub.n)
- , asn1_integer_from_mpz(&key->pub.e)
- , asn1_integer_from_mpz(&key->d)
- , asn1_integer_from_mpz(&key->p)
- , asn1_integer_from_mpz(&key->q)
- , asn1_integer_from_mpz(&key->dP)
- , asn1_integer_from_mpz(&key->dQ)
- , asn1_integer_from_mpz(&key->qInv));
-
- DBG(DBG_PRIVATE,
- DBG_dump_chunk("PKCS#1 encoded private key:", pkcs1)
- )
- return pkcs1;
-}
-
-/**
- * Build a DER-encoded PKCS#1 public key object
- */
-chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa)
-{
- return asn1_wrap(ASN1_SEQUENCE, "mm"
- , asn1_integer_from_mpz(&rsa->n)
- , asn1_integer_from_mpz(&rsa->e));
-}
-
-/**
- * Build a DER-encoded publicKeyInfo object
- */
-chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa)
-{
- chunk_t publicKey;
- chunk_t rawKey = pkcs1_build_public_key(rsa);
- u_char *pos;
-
- pos = asn1_build_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
- *pos++ = 0x00;
- mv_chunk(&pos, rawKey);
-
- return asn1_wrap(ASN1_SEQUENCE, "cm"
- , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
- , publicKey);
-}
-
-void free_RSA_public_content(RSA_public_key_t *rsa)
-{
- mpz_clear(&rsa->n);
- mpz_clear(&rsa->e);
-}
-
-void free_RSA_private_content(RSA_private_key_t *rsak)
-{
- free_RSA_public_content(&rsak->pub);
- mpz_clear(&rsak->d);
- mpz_clear(&rsak->p);
- mpz_clear(&rsak->q);
- mpz_clear(&rsak->dP);
- mpz_clear(&rsak->dQ);
- mpz_clear(&rsak->qInv);
-}
+++ /dev/null
-/* Support of PKCS#1 private key data structures
- * 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.
- */
-
-#ifndef _PKCS1_H
-#define _PKCS1_H
-
-#include <gmp.h> /* GNU Multi Precision library */
-
-#include "defs.h"
-
-typedef struct RSA_public_key RSA_public_key_t;
-
-struct RSA_public_key
-{
- char keyid[KEYID_BUF]; /* see ipsec_keyblobtoid(3) */
-
- /* length of modulus n in octets: [RSA_MIN_OCTETS, RSA_MAX_OCTETS] */
- unsigned k;
-
- /* public: */
- MP_INT
- n, /* modulus: p * q */
- e; /* exponent: relatively prime to (p-1) * (q-1) [probably small] */
-};
-
-typedef struct RSA_private_key RSA_private_key_t;
-
-struct RSA_private_key {
- struct RSA_public_key pub; /* must be at start for RSA_show_public_key */
-
- MP_INT
- d, /* private exponent: (e^-1) mod ((p-1) * (q-1)) */
- /* help for Chinese Remainder Theorem speedup: */
- p, /* first secret prime */
- q, /* second secret prime */
- dP, /* first factor's exponent: (e^-1) mod (p-1) == d mod (p-1) */
- dQ, /* second factor's exponent: (e^-1) mod (q-1) == d mod (q-1) */
- qInv; /* (q^-1) mod p */
-};
-
-struct fld {
- const char *name;
- size_t offset;
-};
-
-extern const struct fld RSA_private_field[];
-#define RSA_PRIVATE_FIELD_ELEMENTS 8
-
-extern void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n);
-extern bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key);
-extern chunk_t pkcs1_build_private_key(const RSA_private_key_t *key);
-extern chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa);
-extern chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa);
-extern chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg
- , const RSA_private_key_t *key, bool bit_string);
-extern bool compute_digest(chunk_t tbs, int alg, chunk_t *digest);
-extern void sign_hash(const RSA_private_key_t *k, const u_char *hash_val
- , size_t hash_len, u_char *sig_val, size_t sig_len);
-extern chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in);
-extern bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in
- , chunk_t *out);
-extern bool same_RSA_public_key(const RSA_public_key_t *a
- , const RSA_public_key_t *b);
-extern void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize);
-extern err_t RSA_private_key_sanity(RSA_private_key_t *k);
-#ifdef DEBUG
-extern void RSA_show_public_key(RSA_public_key_t *k);
-extern void RSA_show_private_key(RSA_private_key_t *k);
-#endif
-extern void free_RSA_public_content(RSA_public_key_t *rsa);
-extern void free_RSA_private_content(RSA_private_key_t *rsak);
-
-#endif /* _PKCS1_H */
/* check the signature only if a cacert is available */
if (cacert != NULL)
{
+ public_key_t *key = cacert->public_key;
+ signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+
if (signerInfos == 0)
{
DBG1("no signerInfo object found");
DBG1("no authenticatedAttributes object found");
return FALSE;
}
- if (!check_signature(*attributes, encrypted_digest, digest_alg,
- enc_alg, cacert))
+ if (enc_alg != OID_RSA_ENCRYPTION)
{
- DBG1("invalid signature");
+ DBG1("only RSA digest encryption supported");
return FALSE;
}
- else
+ switch (digest_alg)
+ {
+ case OID_MD5:
+ scheme = SIGN_RSA_EMSA_PKCS1_MD5;
+ break;
+ case OID_SHA1:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ break;
+ case OID_SHA256:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
+ break;
+ case OID_SHA384:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
+ break;
+ case OID_SHA512:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
+ break;
+ default:
+ return FALSE;
+ }
+ if (key->verify(key, scheme, *attributes, encrypted_digest))
{
DBG2("signature is valid");
}
+ else
+ {
+ DBG1("invalid signature");
+ return FALSE;
+ }
}
return TRUE;
}
*/
bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber,
- const RSA_private_key_t *key)
+ private_key_t *key)
{
asn1_parser_t *parser;
chunk_t object;
}
break;
case PKCS7_ENCRYPTED_KEY:
- if (!RSA_decrypt(key, object, &symmetric_key))
+ if (!key->decrypt(key, object, &symmetric_key))
{
DBG1("symmetric key could not be decrypted with rsa");
goto end;
*/
chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
{
- u_char digest_buf[MAX_DIGEST_LEN];
- chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
-
- compute_digest(content, digest_alg, &digest);
-
- return asn1_wrap(ASN1_SEQUENCE, "cm"
- , ASN1_messageDigest_oid
- , asn1_wrap(ASN1_SET, "m"
- , asn1_simple_object(ASN1_OCTET_STRING, digest)
- )
- );
+ chunk_t digest;
+ hash_algorithm_t hash_alg;
+ hasher_t *hasher;
+
+ hash_alg = hasher_algorithm_from_oid(digest_alg);
+ hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
+ hasher->allocate_hash(hasher, content, &digest);
+
+ return asn1_wrap(ASN1_SEQUENCE, "cm",
+ ASN1_messageDigest_oid,
+ asn1_wrap(ASN1_SET, "m",
+ asn1_wrap(ASN1_OCTET_STRING, "m", digest)
+ )
+ );
}
/**
*/
chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
const x509cert_t *cert, int digest_alg,
- const RSA_private_key_t *key)
+ private_key_t *key)
{
contentInfo_t pkcs7Data, signedData;
chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
if (attributes.ptr != NULL)
{
- encryptedDigest = pkcs1_build_signature(attributes, digest_alg
- , key, FALSE);
+ encryptedDigest = x509_build_signature(attributes, digest_alg, key,
+ FALSE);
authenticatedAttributes = chunk_clone(attributes);
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
}
else
{
encryptedDigest = (data.ptr == NULL)? chunk_empty
- : pkcs1_build_signature(data, digest_alg, key, FALSE);
+ : x509_build_signature(data, digest_alg, key, FALSE);
authenticatedAttributes = chunk_empty;
}
{
encryption_algorithm_t alg;
size_t alg_key_size;
- RSA_public_key_t public_key;
- chunk_t symmetricKey, iv, in, out;
+ chunk_t symmetricKey, protectedKey, iv, in, out;
crypter_t *crypter;
alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size);
free(in.ptr);
free(iv.ptr);
- init_RSA_public_key(&public_key, cert->publicExponent, cert->modulus);
-
+ cert->public_key->encrypt(cert->public_key, symmetricKey, &protectedKey);
+
/* build pkcs7 enveloped data object */
{
+
chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_build_known_oid(enc_alg)
, asn1_simple_object(ASN1_OCTET_STRING, iv));
, asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
- , RSA_encrypt(&public_key, symmetricKey));
+ , protectedKey);
chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
, ASN1_INTEGER_0
cInfo = pkcs7_build_contentInfo(&envelopedData);
DBG3("envelopedData %B", &cInfo);
- free_RSA_public_content(&public_key);
free(envelopedData.content.ptr);
free(symmetricKey.ptr);
return cInfo;
/* Support of PKCS#7 data structures
* Copyright (C) 2005 Jan Hutter, Martin Willi
- * Copyright (C) 2002-2005 Andreas Steffen
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
* Hochschule fuer Technik Rapperswil, Switzerland
*
* This program is free software; you can redistribute it and/or modify it
#define _PKCS7_H
#include <crypto/crypters/crypter.h>
-
+#include <credentials/keys/private_key.h>
#include "defs.h"
-#include "pkcs1.h"
#include "x509.h"
/* Access structure for a PKCS#7 ContentInfo object */
extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data,
x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert);
extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
- chunk_t serialNumber, const RSA_private_key_t *key);
+ chunk_t serialNumber, private_key_t *key);
extern chunk_t pkcs7_contentType_attribute(void);
extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg);
extern chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert);
extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
- const x509cert_t *cert, int digest_alg, const RSA_private_key_t *key);
+ const x509cert_t *cert, int digest_alg, private_key_t *key);
extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert,
int enc_alg);
}
else
{
- ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg
- , &msg->keyval, &pubkeys);
- if (ugh != NULL)
- loglog(RC_LOG_SERIOUS, "%s", ugh);
+ if (!add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, msg->keyval,
+ &pubkeys))
+ {
+ loglog(RC_LOG_SERIOUS, "failed to add public key");
+ }
}
}
}
#include "mp_defs.h"
#include "log.h"
#include "id.h"
-#include "pkcs1.h"
#include "x509.h"
#include "crl.h"
#include "ca.h"
* ASN.1 definition of an X.509v3 x509_cert
*/
static const asn1Object_t certObjects[] = {
- { 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
- { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
- { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
- { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
- { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
- { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
- { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
- { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
- { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
- { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
- { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
- { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
- { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */
- { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */
- { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 14 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
- { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 16 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
- { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 18 */
- { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 19 */
- { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 20 */
- { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 21 */
- { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
- ASN1_BODY }, /* 22 */
- { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 23 */
- { 3, "end loop", ASN1_EOC, ASN1_END }, /* 24 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 25 */
- { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 26 */
- { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 27 */
- { 0, "exit", ASN1_EOC, ASN1_EXIT }
+ { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
+ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
+ { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
+ { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
+ { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
+ { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
+ { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */
+ { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
+ { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */
+ { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define X509_OBJ_CERTIFICATE 0
#define X509_OBJ_TBS_CERTIFICATE 1
#define X509_OBJ_NOT_BEFORE 8
#define X509_OBJ_NOT_AFTER 9
#define X509_OBJ_SUBJECT 10
-#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12
-#define X509_OBJ_SUBJECT_PUBLIC_KEY 13
-#define X509_OBJ_EXTN_ID 21
-#define X509_OBJ_CRITICAL 22
-#define X509_OBJ_EXTN_VALUE 23
-#define X509_OBJ_ALGORITHM 26
-#define X509_OBJ_SIGNATURE 27
+#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11
+#define X509_OBJ_EXTN_ID 19
+#define X509_OBJ_CRITICAL 20
+#define X509_OBJ_EXTN_VALUE 21
+#define X509_OBJ_ALGORITHM 24
+#define X509_OBJ_SIGNATURE 25
const x509cert_t empty_x509cert = {
NULL , /* *next */
0 , /* notBefore */
0 , /* notAfter */
{ NULL, 0 } , /* subject */
- /* subjectPublicKeyInfo */
- OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
- { NULL, 0 } , /* subjectPublicKey */
- { NULL, 0 } , /* modulus */
- { NULL, 0 } , /* publicExponent */
+ NULL , /* public_key */
/* issuerUniqueID */
/* subjectUniqueID */
/* extensions */
/**
* Build a to-be-signed X.509 certificate body
*/
-static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
+static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa)
{
/* version is always X.509v3 */
chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
chunk_t extensions = chunk_empty;
+ chunk_t key = rsa->get_encoding(rsa);
+
+ chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
+ asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
+ asn1_bitstring("m", key));
+
if (cert->subjectAltName != NULL)
{
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
, version
- , asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
+ , asn1_integer("c", cert->serialNumber)
, asn1_algorithmIdentifier(cert->sigAlg)
, cert->issuer
, asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_from_time(&cert->notAfter, ASN1_UTCTIME)
)
, cert->subject
- , pkcs1_build_publicKeyInfo(rsa)
+ , keyInfo
, extensions
);
}
/**
* Build a DER-encoded X.509 certificate
*/
-void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key,
- &nb