diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2009-06-05 21:14:31 +0200 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2009-06-09 11:03:32 +0200 |
commit | 8b799d55ce5b0cf48b6d1dd0c3ca6a1474234ed6 (patch) | |
tree | 6933a085f303dd3e232683cbdb9a25b99078b187 | |
parent | b00fbdb55a1054b35270051722cdcd8c059a337a (diff) | |
download | strongswan-8b799d55ce5b0cf48b6d1dd0c3ca6a1474234ed6.tar.bz2 strongswan-8b799d55ce5b0cf48b6d1dd0c3ca6a1474234ed6.tar.xz |
pluto and scepclient use private and public key plugins of libstrongswan
46 files changed, 1802 insertions, 2596 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 089d089f5..c2a1a5a4f 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -41,8 +41,9 @@ credentials/certificates/ac.h \ 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 \ diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index 85f906caa..d57444d67 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -255,7 +255,7 @@ chunk_t asn1_build_known_oid(int n) /* * Defined in header. */ -u_int asn1_length(chunk_t *blob) +size_t asn1_length(chunk_t *blob) { u_char n; size_t len; @@ -675,7 +675,7 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content) } /** - * Build an ASN.1 BITSTRING object + * Build an ASN.1 BIT_STRING object */ chunk_t asn1_bitstring(const char *mode, chunk_t content) { @@ -692,6 +692,41 @@ 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'). */ diff --git a/src/libstrongswan/asn1/asn1.h b/src/libstrongswan/asn1/asn1.h index 12390596a..6a2b594c0 100644 --- a/src/libstrongswan/asn1/asn1.h +++ b/src/libstrongswan/asn1/asn1.h @@ -120,7 +120,7 @@ chunk_t asn1_build_known_oid(int n); * @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 @@ -228,6 +228,15 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content); 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 diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index 0bca198f1..701cbcde3 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -20,6 +20,8 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END, "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", diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 4b3fb1ae4..01ccf2a5c 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -38,14 +38,18 @@ typedef builder_t* (*builder_constructor_t)(int subtype); * 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* */ diff --git a/src/libstrongswan/credentials/credential_factory.c b/src/libstrongswan/credentials/credential_factory.c index 76438a56c..2e9a541d4 100644 --- a/src/libstrongswan/credentials/credential_factory.c +++ b/src/libstrongswan/credentials/credential_factory.c @@ -156,6 +156,8 @@ static void* create(private_credential_factory_t *this, credential_type_t type, 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; diff --git a/src/libstrongswan/credentials/keys/private_key.h b/src/libstrongswan/credentials/keys/private_key.h index 62f1167c4..f38af8ff4 100644 --- a/src/libstrongswan/credentials/keys/private_key.h +++ b/src/libstrongswan/credentials/keys/private_key.h @@ -80,6 +80,14 @@ struct private_key_t { 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 diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c index f08b2dcce..c5b5d6f9a 100644 --- a/src/libstrongswan/credentials/keys/public_key.c +++ b/src/libstrongswan/credentials/keys/public_key.c @@ -15,13 +15,15 @@ #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", diff --git a/src/libstrongswan/credentials/keys/public_key.h b/src/libstrongswan/credentials/keys/public_key.h index 86571b013..d78791aeb 100644 --- a/src/libstrongswan/credentials/keys/public_key.h +++ b/src/libstrongswan/credentials/keys/public_key.h @@ -34,12 +34,14 @@ typedef enum signature_scheme_t signature_scheme_t; */ 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, ... */ }; /** @@ -50,29 +52,33 @@ extern enum_name_t *key_type_names; /** * 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, }; @@ -107,13 +113,21 @@ struct public_key_t { /** * 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 diff --git a/src/scepclient/rsakey.h b/src/libstrongswan/pgp/pgp.c index f9245d25b..f1f924774 100644 --- a/src/scepclient/rsakey.h +++ b/src/libstrongswan/pgp/pgp.c @@ -1,11 +1,6 @@ -/** - * @file rsakey.h - * @brief Functions for RSA key generation - */ - -/* - * Copyright (C) 1999, 2000, 2001 Henry Spencer. - * Copyright (C) 2005 Jan Hutter, Martin Willi +/* + * Copyright (C) 2002-2009 Andreas Steffen + * * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,12 +13,40 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ + +#include "pgp.h" -#ifndef RSAKEY_H_ -#define RSAKEY_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; -#include "../pluto/pkcs1.h" + if (len > blob->len) + { + return PGP_INVALID_LENGTH; + } + blob->len -= len; -extern err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key); + while (len-- > 0) + { + size = 256*size + *blob->ptr++; + } + return size; +} -#endif // RSAKEY_H_ diff --git a/src/libstrongswan/pgp/pgp.h b/src/libstrongswan/pgp/pgp.h new file mode 100644 index 000000000..b12031970 --- /dev/null +++ b/src/libstrongswan/pgp/pgp.h @@ -0,0 +1,64 @@ +/* + * 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_ @}*/ diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c index e3244ccbf..bfe9d3cdd 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -26,6 +26,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> +#include <pgp/pgp.h> /** * Public exponent to use for key generation. @@ -110,11 +111,12 @@ struct private_gmp_rsa_private_key_t { }; /** - * 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 @@ -215,32 +217,36 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, 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. @@ -255,9 +261,9 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, /* 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); @@ -269,7 +275,7 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, } /** - * 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) { @@ -277,15 +283,16 @@ 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: @@ -304,7 +311,7 @@ static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme, } /** - * 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) @@ -314,7 +321,7 @@ static bool decrypt(private_gmp_rsa_private_key_t *this, } /** - * 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) { @@ -322,7 +329,7 @@ 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) @@ -347,7 +354,35 @@ static gmp_rsa_public_key_t* get_public_key(private_gmp_rsa_private_key_t *this) } /** - * 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) { @@ -371,19 +406,27 @@ 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)); } /** @@ -404,7 +447,7 @@ static chunk_t get_encoding(private_gmp_rsa_private_key_t *this) } /** - * 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) { @@ -445,14 +488,14 @@ static status_t check(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; @@ -540,16 +583,17 @@ static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void) { 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; @@ -567,7 +611,7 @@ static gmp_rsa_private_key_t *generate(size_t key_size) 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) @@ -678,7 +722,7 @@ static const asn1Object_t privkeyObjects[] = { /** * 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; @@ -706,6 +750,7 @@ static gmp_rsa_private_key_t *load(chunk_t blob) case PRIV_KEY_VERSION: if (object.len > 0 && *object.ptr != 0) { + DBG1("PKCS#1 private key format is not version 1"); goto end; } break; @@ -755,13 +800,131 @@ end: 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; @@ -802,7 +965,15 @@ static void add(private_builder_t *this, builder_part_t part, ...) { 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; } diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index acb44a110..4c779703b 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -28,11 +28,7 @@ #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; @@ -77,6 +73,12 @@ struct 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) @@ -189,13 +191,24 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, 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)) @@ -218,8 +231,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, 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, @@ -287,7 +299,8 @@ static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme { 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); @@ -316,6 +329,34 @@ static bool encrypt_(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t } /** + * 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) @@ -324,6 +365,34 @@ 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, @@ -335,6 +404,8 @@ 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; } @@ -381,14 +452,15 @@ static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty() { 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; @@ -443,7 +515,7 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e) 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)) { @@ -467,9 +539,9 @@ static const asn1Object_t pubkeyObjects[] = { #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; @@ -505,7 +577,121 @@ static gmp_rsa_public_key_t *load(chunk_t blob) 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)) @@ -514,6 +700,11 @@ static gmp_rsa_public_key_t *load(chunk_t blob) return NULL; } return &this->public; + +end: + free(blob.ptr); + destroy(this); + return NULL; } typedef struct private_builder_t private_builder_t; @@ -554,7 +745,23 @@ static void add(private_builder_t *this, builder_part_t part, ...) { 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; } diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index 4004e0949..12040f229 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -136,7 +136,7 @@ error: } /** - * 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) { @@ -144,7 +144,7 @@ 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) @@ -152,7 +152,6 @@ static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t sch 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: @@ -171,7 +170,7 @@ static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t sch } /** - * 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) @@ -181,7 +180,7 @@ static bool decrypt(private_openssl_rsa_private_key_t *this, } /** - * 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) { @@ -189,7 +188,7 @@ 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) @@ -206,7 +205,7 @@ static identification_t* get_id(private_openssl_rsa_private_key_t *this, } /** - * 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) { @@ -214,7 +213,35 @@ static openssl_rsa_public_key_t* get_public_key(private_openssl_rsa_private_key_ } /** - * 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) { @@ -253,7 +280,7 @@ static chunk_t get_encoding(private_openssl_rsa_private_key_t *this) } /** - * 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) { @@ -286,16 +313,17 @@ static private_openssl_rsa_private_key_t *openssl_rsa_private_key_create_empty(v { 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; diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 8803b7960..d0fd562af 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -124,7 +124,6 @@ static bool verify(private_openssl_rsa_public_key_t *this, signature_scheme_t sc 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: @@ -152,6 +151,34 @@ static bool encrypt_(private_openssl_rsa_public_key_t *this, chunk_t crypto, chu } /** + * 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) @@ -262,6 +289,7 @@ static private_openssl_rsa_public_key_t *openssl_rsa_public_key_create_empty() 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; diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 57fef9496..34c121d7b 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -730,7 +730,6 @@ static bool parse_certificate(private_x509_cert_t *this) KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); if (this->public_key == NULL) { - DBG1("could not create public key"); goto end; } break; @@ -1123,19 +1122,19 @@ static private_x509_cert_t* create_empty(void) { 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; @@ -1314,7 +1313,7 @@ static bool generate(private_builder_t *this) 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", diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index 2c91c3d84..269401121 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -38,8 +38,7 @@ nat_traversal.c nat_traversal.h \ 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 \ diff --git a/src/pluto/ac.c b/src/pluto/ac.c index 3c886f973..3b5df9738 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -783,8 +783,8 @@ bool verify_x509acert(x509acert_t *ac, bool strict) 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; diff --git a/src/pluto/ca.c b/src/pluto/ca.c index 363a78b92..4fdb8cfe7 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -385,8 +385,8 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) } } - 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"); diff --git a/src/pluto/certs.c b/src/pluto/certs.c index 7d78f229a..29e7dbfa4 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -1,5 +1,7 @@ /* 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 @@ -18,17 +20,15 @@ #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 @@ -118,14 +118,14 @@ bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type, } /** - * 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); @@ -133,20 +133,24 @@ err_t load_rsa_private_key(char* filename, prompt_pass_t *pass, { 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; } /** diff --git a/src/pluto/certs.h b/src/pluto/certs.h index 1d9e984e9..a88fc152e 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -1,5 +1,7 @@ /* 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 @@ -15,9 +17,10 @@ #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 @@ -59,11 +62,11 @@ extern const cert_t empty_cert; */ 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); diff --git a/src/pluto/connections.c b/src/pluto/connections.c index 960884e84..bdfdc10a0 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -29,13 +29,15 @@ #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" @@ -2155,17 +2157,16 @@ check_key_recs(enum myid_state try_state * 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"; } @@ -2185,7 +2186,7 @@ check_key_recs(enum myid_state try_state { 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; @@ -2198,10 +2199,9 @@ check_key_recs(enum myid_state try_state } #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 @@ -2211,7 +2211,7 @@ check_txt_recs(enum myid_state try_state * 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; @@ -2221,7 +2221,7 @@ check_txt_recs(enum 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"; } @@ -2239,9 +2239,11 @@ check_txt_recs(enum myid_state try_state 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; @@ -2249,7 +2251,9 @@ check_txt_recs(enum myid_state try_state } } if (ugh != NULL) + { myid_state = old_myid_state; + } return ugh; } @@ -2513,13 +2517,13 @@ initiate_opportunistic_body(struct find_oppo_bundle *b * 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"; } @@ -2560,7 +2564,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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; @@ -2579,11 +2583,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b * 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"; } @@ -2604,8 +2608,8 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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" @@ -2639,11 +2643,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b * 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"; } @@ -2663,7 +2667,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b { 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) @@ -3399,7 +3403,7 @@ refine_host_connection(const struct state *st, const struct id *peer_id * 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; diff --git a/src/pluto/crl.c b/src/pluto/crl.c index 1d9b5445e..c800f2acc 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -238,8 +238,8 @@ bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl) ) /* 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) @@ -656,8 +656,8 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate 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"); diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c index bd190530c..ed901ade5 100644 --- a/src/pluto/dnskey.c +++ b/src/pluto/dnskey.c @@ -29,6 +29,9 @@ #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" @@ -83,7 +86,9 @@ init_adns(void) { strcpy(adns_path_space, helper_bin_dir); if (n > 0 && adns_path_space[n -1] != '/') + { adns_path_space[n++] = '/'; + } } } else @@ -95,25 +100,33 @@ init_adns(void) 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) @@ -128,7 +141,9 @@ init_adns(void) * 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); @@ -140,16 +155,18 @@ init_adns(void) 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]); @@ -183,8 +200,10 @@ stop_adns(void) else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) + { plog("ADNS process exited with status %d" , (int) WEXITSTATUS(status)); + } } else if (WIFSIGNALED(status)) { @@ -227,8 +246,9 @@ decode_iii(u_char **pp, struct id *gw_id) u_char under = *e; if (p == e) + { return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; - + } *e = '\0'; if (*p == '@') { @@ -236,8 +256,10 @@ decode_iii(u_char **pp, struct id *gw_id) err_t ugh = atoid(p, gw_id, FALSE); if (ugh != NULL) + { return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s" , ugh); + } } else { @@ -248,12 +270,14 @@ decode_iii(u_char **pp, struct id *gw_id) , &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); } @@ -278,14 +302,18 @@ process_txt_rr_body(u_char *str /* 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; @@ -293,25 +321,30 @@ process_txt_rr_body(u_char *str 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"); @@ -384,29 +417,34 @@ process_txt_rr_body(u_char *str /* 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); @@ -426,13 +464,18 @@ process_txt_rr_body(u_char *str { 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 { diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index 52f5553f0..49f40e38d 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -34,6 +34,8 @@ #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" @@ -1402,35 +1404,44 @@ static bool generate_skeyids_iv(struct state *st) 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; } @@ -1439,7 +1450,7 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS] { 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; } @@ -1450,142 +1461,11 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS] 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. @@ -1597,54 +1477,39 @@ static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], * 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, @@ -1653,16 +1518,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, { 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) @@ -1672,10 +1532,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, 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; + } } } @@ -1688,8 +1549,9 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, 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); @@ -1702,18 +1564,19 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, 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) { @@ -1721,9 +1584,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, 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) @@ -1732,9 +1598,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, 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 @@ -1748,53 +1617,32 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st, { 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; } } @@ -2245,6 +2093,7 @@ static void decode_cert(struct msg_digest *md) { plog("X.509 certificate rejected"); } + DESTROY_IF(cert.public_key); free_generalNames(cert.subjectAltName, FALSE); free_generalNames(cert.crlDistributionPoints, FALSE); } @@ -2749,9 +2598,9 @@ static bool has_preloaded_public_key(struct state *st) 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 */ @@ -3595,12 +3444,12 @@ stf_status main_inR2_outI3(struct msg_digest *md) { /* 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; } @@ -3997,12 +3846,12 @@ main_inI3_outR3_tail(struct msg_digest *md { /* 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; } @@ -4479,10 +4328,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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; @@ -4503,7 +4352,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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; @@ -4515,9 +4364,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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; @@ -4534,7 +4383,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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; @@ -4551,9 +4400,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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; @@ -4565,7 +4414,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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) @@ -4585,11 +4434,15 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( 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) @@ -4601,9 +4454,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( * 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; diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c index fdc2c4c3c..f698de2c8 100644 --- a/src/pluto/kernel.c +++ b/src/pluto/kernel.c @@ -488,10 +488,11 @@ static bool do_command(struct connection *c, struct spd_route *sr, 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)); diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 031d00a46..c0eb6ae74 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -33,12 +33,15 @@ #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" @@ -69,66 +72,42 @@ struct secret { 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); } @@ -138,8 +117,8 @@ secret_t *secrets = NULL; * 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, @@ -155,20 +134,19 @@ get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym) 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; } @@ -222,9 +200,10 @@ get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym) * 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) @@ -251,16 +230,10 @@ get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym) { 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); @@ -288,8 +261,7 @@ get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym) * 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); @@ -305,60 +277,50 @@ get_preshared_secret(const struct connection *c) /* 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 @@ -401,8 +363,7 @@ get_RSA_private_key(const struct connection *c) */ /* 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; @@ -435,109 +396,113 @@ process_psk_secret(chunk_t *psk) 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; @@ -560,7 +525,9 @@ process_rsa_keyfile(RSA_private_key_t *rsak, int whackfd) 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 @@ -574,21 +541,25 @@ process_rsa_keyfile(RSA_private_key_t *rsak, int whackfd) 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; @@ -616,11 +587,11 @@ process_xauth(secret_t *s) 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; @@ -643,11 +614,11 @@ xauth_get_secret(xauth_t *xauth_secret) 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; @@ -657,10 +628,14 @@ xauth_verify_secret(const xauth_peer_t *peer, const xauth_t *xauth_secret) 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" @@ -669,16 +644,15 @@ xauth_verify_secret(const xauth_peer_t *peer, const xauth_t *xauth_secret) 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) { @@ -696,11 +670,10 @@ xauth_defaults(void) } }; -/* - * 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"; @@ -776,8 +749,7 @@ process_pin(secret_t *s, int whackfd) return NULL; } -static void -log_psk(secret_t *s) +static void log_psk(secret_t *s) { int n = 0; char buf[BUF_LEN]; @@ -808,8 +780,7 @@ log_psk(secret_t *s) 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; @@ -832,18 +803,30 @@ process_secret(secret_t *s, int whackfd) /* 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")) @@ -877,8 +860,7 @@ process_secret(secret_t *s, int whackfd) 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 (;;) @@ -1013,15 +995,13 @@ process_secret_records(int whackfd) } } -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; @@ -1075,8 +1055,7 @@ process_secrets_file(const char *file_pat, int whackfd) globfree(&globbuf); } -void -free_preshared_secrets(void) +void free_preshared_secrets(void) { lock_certs_and_keys("free_preshared_secrets"); @@ -1102,8 +1081,8 @@ free_preshared_secrets(void) 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); @@ -1123,8 +1102,7 @@ free_preshared_secrets(void) 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); @@ -1134,8 +1112,7 @@ load_preshared_secrets(int 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); @@ -1143,12 +1120,7 @@ public_key_from_rsa(const RSA_public_key_t *k) 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. @@ -1161,8 +1133,7 @@ public_key_from_rsa(const RSA_public_key_t *k) /* 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; @@ -1172,8 +1143,7 @@ free_public_keyentry(pubkey_list_t *p) 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); @@ -1183,15 +1153,15 @@ free_public_keys(pubkey_list_t **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 */ @@ -1224,66 +1194,8 @@ transfer_to_public_keys(struct gw_info *gateways_from_dns #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); @@ -1304,30 +1216,33 @@ install_public_key(pubkey_t *pk, pubkey_list_t **head) *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; @@ -1357,67 +1272,63 @@ unreference_key(pubkey_t **pkp) 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; @@ -1429,13 +1340,15 @@ add_x509_public_key(x509cert_t *cert , time_t until 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; @@ -1445,50 +1358,39 @@ add_x509_public_key(x509cert_t *cert , time_t until /* 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); @@ -1501,7 +1403,6 @@ remove_x509_public_key(const x509cert_t *cert) } p =*pp; } - free_public_key(revoked_pk); } /* @@ -1521,30 +1422,28 @@ void list_public_keys(bool utc) 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; } diff --git a/src/pluto/keys.h b/src/pluto/keys.h index 84d941fe8..8bc94d839 100644 --- a/src/pluto/keys.h +++ b/src/pluto/keys.h @@ -1,5 +1,6 @@ /* 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 @@ -15,9 +16,9 @@ #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 @@ -31,8 +32,7 @@ extern void free_preshared_secrets(void); enum PrivateKeyKind { PPK_PSK, - /* PPK_DSS, */ /* not implemented */ - PPK_RSA, + PPK_PUBKEY, PPK_XAUTH, PPK_PIN }; @@ -43,9 +43,8 @@ extern void xauth_defaults(void); 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 */ @@ -62,10 +61,7 @@ struct pubkey { , 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; @@ -77,21 +73,20 @@ struct pubkey_list { 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 diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c index 1445f4b8e..80164fa1d 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -39,7 +39,6 @@ #include "certs.h" #include "smartcard.h" #include "whack.h" -#include "pkcs1.h" #include "keys.h" #include "fetch.h" #include "ocsp.h" @@ -159,7 +158,7 @@ static x509cert_t *ocsp_requestor_cert = NULL; 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 @@ -293,8 +292,9 @@ static const asn1Object_t singleResponseObjects[] = { */ 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) @@ -311,8 +311,15 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio } } + /* 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; @@ -660,7 +667,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) /* initialize temporary static storage */ ocsp_requestor_cert = NULL; ocsp_requestor_sc = NULL; - ocsp_requestor_pri = NULL; + ocsp_requestor_key = NULL; for (;;) { @@ -699,15 +706,15 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) 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; } } @@ -715,50 +722,58 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) 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; } @@ -770,30 +785,22 @@ static chunk_t generate_signature(chunk_t digest, smartcard_t *sc, 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" @@ -992,8 +999,7 @@ static bool valid_ocsp_response(response_t *res) 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"); @@ -1051,8 +1057,8 @@ static bool valid_ocsp_response(response_t *res) 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"); diff --git a/src/pluto/pgp.c b/src/pluto/pgpcert.c index e80b2cc5b..bfa048265 100644 --- a/src/pluto/pgp.c +++ b/src/pluto/pgpcert.c @@ -1,5 +1,7 @@ /* Support of OpenPGP certificates - * 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 @@ -19,6 +21,7 @@ #include <freeswan.h> #include <library.h> +#include <pgp/pgp.h> #include <crypto/hashers/hasher.h> #include "constants.h" @@ -26,10 +29,9 @@ #include "mp_defs.h" #include "log.h" #include "id.h" -#include "pgp.h" +#include "pgpcert.h" #include "certs.h" #include "whack.h" -#include "pkcs1.h" #include "keys.h" /* @@ -88,36 +90,6 @@ static const char *const pgp_packet_type_name[] = { #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 @@ -129,28 +101,15 @@ const pgpcert_t empty_pgpcert = { { NULL, 0 }, /* certificate */ 0 , /* created */ 0 , /* until */ - 0 , /* pubkeyAlgorithm */ - { NULL, 0 }, /* modulus */ - { NULL, 0 }, /* publicExponent */ - "" /* fingerprint */ + NULL , /* public key */ + NULL /* 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) +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++; @@ -158,14 +117,13 @@ pgp_old_packet_length(chunk_t *blob) blob->len--; /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ - return pgp_size(blob, (len_type == 0)? 1: len_type << 1); + 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) +static u_char pgp_version(chunk_t *blob) { u_char version = *blob->ptr++; blob->len--; @@ -179,10 +137,10 @@ pgp_version(chunk_t *blob) /* * 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) +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) { @@ -191,7 +149,7 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) } /* creation date - 4 bytes */ - cert->created = (time_t)pgp_size(packet, 4); + cert->created = (time_t)pgp_length(packet, 4); DBG(DBG_PARSING, DBG_log("L3 - created:"); DBG_log(" %T", &cert->created, TRUE) @@ -200,12 +158,13 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) if (version == 3) { /* validity in days - 2 bytes */ - cert->until = (time_t)pgp_size(packet, 2); + 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); @@ -217,49 +176,29 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) DBG_log("L3 - public key algorithm:") ) - switch (pgp_size(packet, 1)) + switch (pgp_length(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); + 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) { - 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) + cert->fingerprint = key->get_id(key, ID_KEY_ID); + if (cert->fingerprint == 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 { @@ -267,14 +206,12 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) } 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") ) @@ -285,103 +222,9 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) } /* - * 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) +static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert) { time_t created; chunk_t keyid; @@ -393,20 +236,20 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert) return TRUE; /* size byte must have the value 5 */ - if (pgp_size(packet, 1) != 5) + if (pgp_length(packet, 1) != 5) { plog(" size must be 5"); return FALSE; } /* signature type - 1 byte */ - sig_type = (u_char)pgp_size(packet, 1); + 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_size(packet, 4); + created = (time_t)pgp_length(packet, 4); DBG(DBG_PARSING, DBG_log("L3 - created:"); DBG_log(" %T", &cert->created, TRUE) @@ -420,8 +263,7 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert) return TRUE; } -bool -parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key) +bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key) { DBG(DBG_PARSING, DBG_log("L0 - PGP file:") @@ -486,11 +328,15 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key) { 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, @@ -508,12 +354,18 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key) switch (packet_type) { case PGP_PKT_SECRET_KEY: - if (!parse_pgp_secretkey_packet(&packet, key)) - return FALSE; + *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; + } + } } } @@ -523,8 +375,7 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key) /* * compare two OpenPGP certificates */ -static bool -same_pgpcert(pgpcert_t *a, pgpcert_t *b) +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); @@ -533,8 +384,7 @@ same_pgpcert(pgpcert_t *a, pgpcert_t *b) /* * for each link pointing to the certificate increase the count by one */ -void -share_pgpcert(pgpcert_t *cert) +void share_pgpcert(pgpcert_t *cert) { if (cert != NULL) { @@ -545,21 +395,17 @@ share_pgpcert(pgpcert_t *cert) /* * select the OpenPGP keyid as ID */ -void -select_pgpcert_id(pgpcert_t *cert, struct id *end_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); + 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* add_pgpcert(pgpcert_t *cert) { pgpcert_t *c = pgpcerts; @@ -585,14 +431,15 @@ add_pgpcert(pgpcert_t *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) +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); } @@ -601,11 +448,12 @@ release_pgpcert(pgpcert_t *cert) /* * free a PGP certificate */ -void -free_pgpcert(pgpcert_t *cert) +void free_pgpcert(pgpcert_t *cert) { if (cert != NULL) { + DESTROY_IF(cert->public_key); + DESTROY_IF(cert->fingerprint); free(cert->certificate.ptr); free(cert); } @@ -614,8 +462,7 @@ free_pgpcert(pgpcert_t *cert) /* * list all PGP end certificates in a chained list */ -void -list_pgp_end_certs(bool utc) +void list_pgp_end_certs(bool utc) { pgpcert_t *cert = pgpcerts; time_t now; @@ -632,19 +479,20 @@ list_pgp_end_certs(bool utc) while (cert != NULL) { - unsigned keysize; - char buf[BUF_LEN]; + 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); - 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, " 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)); diff --git a/src/pluto/pgp.h b/src/pluto/pgpcert.h index 4519022e4..9d8912ec5 100644 --- a/src/pluto/pgp.h +++ b/src/pluto/pgpcert.h @@ -1,5 +1,7 @@ /* Support of OpenPGP certificates - * 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 @@ -12,12 +14,12 @@ * for more details. */ -#ifndef _PGP_H -#define _PGP_H +#ifndef _PGPCERT_H +#define _PGPCERT_H #include <crypto/hashers/hasher.h> - -#include "pkcs1.h" +#include <credentials/keys/private_key.h> +#include <credentials/keys/public_key.h> /* * Length of PGP V3 fingerprint @@ -31,20 +33,18 @@ typedef char fingerprint_t[PGP_FINGERPRINT_SIZE]; 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; + 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, RSA_private_key_t *key); +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); @@ -52,4 +52,4 @@ 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 */ +#endif /* _PGPCERT_H */ diff --git a/src/pluto/pkcs1.c b/src/pluto/pkcs1.c deleted file mode 100644 index 51c90a2e2..000000000 --- a/src/pluto/pkcs1.c +++ /dev/null @@ -1,602 +0,0 @@ -/* 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); -} diff --git a/src/pluto/pkcs1.h b/src/pluto/pkcs1.h deleted file mode 100644 index 4aaa8c409..000000000 --- a/src/pluto/pkcs1.h +++ /dev/null @@ -1,86 +0,0 @@ -/* 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 */ diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c index c793d28df..ab4362c73 100644 --- a/src/pluto/pkcs7.c +++ b/src/pluto/pkcs7.c @@ -340,6 +340,9 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert /* 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"); @@ -355,16 +358,40 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert 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; } @@ -374,7 +401,7 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert */ 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; @@ -446,7 +473,7 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, } 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; @@ -579,17 +606,20 @@ chunk_t pkcs7_contentType_attribute(void) */ 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) + ) + ); } /** @@ -649,7 +679,7 @@ chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert) */ 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; @@ -658,15 +688,15 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, 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; } @@ -705,8 +735,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ { 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); @@ -759,10 +788,11 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ 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)); @@ -773,7 +803,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ , 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 @@ -793,7 +823,6 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ cInfo = pkcs7_build_contentInfo(&envelopedData); DBG3("envelopedData %B", &cInfo); - free_RSA_public_content(&public_key); free(envelopedData.content.ptr); free(symmetricKey.ptr); return cInfo; diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h index 09ffd65d5..028822dfe 100644 --- a/src/pluto/pkcs7.h +++ b/src/pluto/pkcs7.h @@ -1,6 +1,7 @@ /* 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 @@ -18,9 +19,8 @@ #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 */ @@ -39,12 +39,12 @@ extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, 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); diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c index d40a4e28a..01f721ee9 100644 --- a/src/pluto/rcv_whack.c +++ b/src/pluto/rcv_whack.c @@ -234,10 +234,11 @@ key_add_request(const whack_message_t *msg) } 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"); + } } } } diff --git a/src/pluto/x509.c b/src/pluto/x509.c index 9a5714bc9..ca926a9b8 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -35,7 +35,6 @@ #include "mp_defs.h" #include "log.h" #include "id.h" -#include "pkcs1.h" #include "x509.h" #include "crl.h" #include "ca.h" @@ -198,36 +197,33 @@ static const asn1Object_t pubkeyObjects[] = { * 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 @@ -238,13 +234,12 @@ static const asn1Object_t certObjects[] = { #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 */ @@ -262,11 +257,7 @@ const x509cert_t empty_x509cert = { 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 */ @@ -1140,13 +1131,19 @@ chunk_t build_subjectAltNames(generalName_t *subjectAltNames) /** * 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" @@ -1156,7 +1153,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa) 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" @@ -1164,7 +1161,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa) , asn1_from_time(&cert->notAfter, ASN1_UTCTIME) ) , cert->subject - , pkcs1_build_publicKeyInfo(rsa) + , keyInfo , extensions ); } @@ -1172,13 +1169,13 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa) /** * Build a DER-encoded X.509 certificate */ -void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key, - const RSA_private_key_t *signer_key) +void build_x509cert(x509cert_t *cert, public_key_t *cert_key, + private_key_t *signer_key) { chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key); - chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg - , signer_key, TRUE); + chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg + , signer_key, TRUE); cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm" , tbs_cert @@ -1210,6 +1207,7 @@ void free_x509cert(x509cert_t *cert) { if (cert != NULL) { + DESTROY_IF(cert->public_key); free_generalNames(cert->subjectAltName, FALSE); free_generalNames(cert->crlDistributionPoints, FALSE); free(cert->certificate.ptr); @@ -1318,111 +1316,75 @@ void store_x509certs(x509cert_t **firstcert, bool strict) } /** - * Decrypts an RSA signature using the issuer's certificate + * Check if a signature over binary blob is genuine */ -static bool decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert, - chunk_t *digest) +bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, + const x509cert_t *issuer_cert) { - switch (alg) - { - chunk_t decrypted; + public_key_t *key = issuer_cert->public_key; + signature_scheme_t scheme = SIGN_DEFAULT; - case OID_RSA_ENCRYPTION: - case OID_MD2_WITH_RSA: + switch (algorithm) + { case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; case OID_SHA1_WITH_RSA: - case OID_SHA1_WITH_RSA_OIW: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; case OID_SHA512_WITH_RSA: - { - mpz_t s; - RSA_public_key_t rsa; - - init_RSA_public_key(&rsa, issuer_cert->publicExponent - , issuer_cert->modulus); - - /* decrypt the signature s = s^e mod n */ - n_to_mpz(s, sig.ptr, sig.len); - mpz_powm(s, s, &rsa.e, &rsa.n); - - /* convert back to bytes */ - decrypted = mpz_to_n(s, rsa.k); - DBG(DBG_PARSING, - DBG_dump_chunk(" decrypted signature: ", decrypted) - ) - - /* copy the least significant bits of decrypted signature - * into the digest string - */ - memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len, - digest->len); - - /* free memory */ - free_RSA_public_content(&rsa); - free(decrypted.ptr); - mpz_clear(s); - return TRUE; - } + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + case OID_ECDSA_WITH_SHA1: + scheme = SIGN_ECDSA_WITH_SHA1; + break; default: - digest->len = 0; return FALSE; } + return key->verify(key, scheme, tbs, sig); } /** - * Check if a signature over binary blob is genuine + * Build an ASN.1 encoded PKCS#1 signature over a binary blob */ -bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg, - const x509cert_t *issuer_cert) +chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key, + bool bit_string) { - u_char digest_buf[MAX_DIGEST_LEN]; - u_char decrypted_buf[MAX_DIGEST_LEN]; - chunk_t digest = {digest_buf, MAX_DIGEST_LEN}; - chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN}; - - DBG(DBG_PARSING, - if (digest_alg != OID_UNKNOWN) - { - DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name); - } - else - { - DBG_log("unknown signature digest algorithm"); - } - ) + signature_scheme_t scheme = SIGN_DEFAULT; + chunk_t signature; - if (!compute_digest(tbs, digest_alg, &digest)) + switch (hash_alg) { - plog(" digest algorithm not supported"); - return FALSE; + 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 chunk_empty; } - - DBG(DBG_PARSING, - DBG_dump_chunk(" digest:", digest) - ) - - decrypted.len = digest.len; /* we want the same digest length */ - - DBG(DBG_PARSING, - if (enc_alg != OID_UNKNOWN) - { - DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name); - } - else - { - DBG_log("unknown signature encryption algorithm"); - } - ) - - if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted)) + if (!key->sign(key, scheme, tbs, &signature)) { - plog(" decryption algorithm not supported"); - return FALSE; - } - - /* check if digests are equal */ - return memeq(decrypted.ptr, digest.ptr, digest.len); + return chunk_empty; + } + return (bit_string) ? asn1_bitstring("m", signature) + : asn1_wrap(ASN1_OCTET_STRING, "m", signature); } /** @@ -1489,15 +1451,17 @@ void gntoid(struct id *id, const generalName_t *gn) */ bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID) { - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + identification_t *keyid; + chunk_t encoding; - if (hasher == NULL) + keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1); + if (keyid == NULL) { - plog(" no SHA-1 hasher available to compute subjectKeyID"); + plog(" unable to compute subjectKeyID"); return FALSE; } - hasher->get_hash(hasher, cert->subjectPublicKey, subjectKeyID.ptr); - hasher->destroy(hasher); + encoding = keyid->get_encoding(keyid); + memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len); return TRUE; } @@ -1825,50 +1789,6 @@ static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0) } /** - * Parses an RSA public key - */ -bool parse_RSA_public_key(chunk_t blob, u_int level0, x509cert_t *cert) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool success = FALSE; - - parser = asn1_parser_create(pubkeyObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) { - case PUB_KEY_RSA_PUBLIC_KEY: - cert->subjectPublicKey = object; - break; - case PUB_KEY_MODULUS: - if (object.len < RSA_MIN_OCTETS + 1) - { - plog(" " RSA_MIN_OCTETS_UGH); - goto end; - } - if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00)) - { - plog(" " RSA_MAX_OCTETS_UGH); - goto end; - } - cert->modulus = object; - break; - case PUB_KEY_EXPONENT: - cert->publicExponent = object; - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; -} - -/** * Parses an X.509v3 certificate */ bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert) @@ -1927,30 +1847,11 @@ bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert) DBG_log(" '%s'",buf) ) break; - case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: - if (asn1_parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION) - { - cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA; - } - else - { - plog(" unsupported public key algorithm"); - goto end; - } - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY: - if (object.len > 0 && *object.ptr == 0x00) - { - /* skip initial bit string octet defining 0 unused bits */ - object = chunk_skip(object, 1); - if (!parse_RSA_public_key(object, level, cert)) - { - goto end; - } - } - else + case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: + cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, + KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); + if (cert->public_key == NULL) { - plog(" invalid RSA public key format"); goto end; } break; @@ -2116,8 +2017,8 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) DBG_log("issuer cacert found") ) - if (!check_signature(cert->tbsCertificate, cert->signature - , cert->algorithm, cert->algorithm, issuer_cert)) + if (!x509_check_signature(cert->tbsCertificate, cert->signature, + cert->algorithm, issuer_cert)) { plog("certificate signature is invalid"); unlock_authcert_list("verify_x509cert"); @@ -2220,9 +2121,8 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, { if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) { - unsigned keysize; - char keyid[KEYID_BUF]; u_char buf[BUF_LEN]; + public_key_t *key = cert->public_key; cert_t c; c.type = CERT_X509_SIGNATURE; @@ -2242,36 +2142,38 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, whack_log(RC_COMMENT, " subject: '%s'", buf); dntoa(buf, BUF_LEN, cert->issuer); whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':' - , buf, BUF_LEN); + datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':', + buf, BUF_LEN); whack_log(RC_COMMENT, " serial: %s", buf); - form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize); - whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s" - , 8*keysize, keyid - , cert->smartcard ? ", on smartcard" : - (has_private_key(c)? ", has private key" : "")); whack_log(RC_COMMENT, " validity: not before %T %s", &cert->notBefore, utc, (cert->notBefore < now)?"ok":"fatal (not valid yet)"); whack_log(RC_COMMENT, " not after %T %s", &cert->notAfter, utc, check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + cert->smartcard ? ", on smartcard" : + (has_private_key(c)? ", has private key" : "")); + whack_log(RC_COMMENT, " keyid: %Y", + key->get_id(key, ID_PUBKEY_INFO_SHA1)); if (cert->subjectKeyID.ptr != NULL) { - datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':' - , buf, BUF_LEN); + datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':', + buf, BUF_LEN); whack_log(RC_COMMENT, " subjkey: %s", buf); } if (cert->authKeyID.ptr != NULL) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); + datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':', + buf, BUF_LEN); whack_log(RC_COMMENT, " authkey: %s", buf); } if (cert->authKeySerialNumber.ptr != NULL) { - datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len - , ':', buf, BUF_LEN); + datatot(cert->authKeySerialNumber.ptr, + cert->authKeySerialNumber.len, ':', buf, BUF_LEN); whack_log(RC_COMMENT, " aserial: %s", buf); } } diff --git a/src/pluto/x509.h b/src/pluto/x509.h index ec3203d74..1810cad06 100644 --- a/src/pluto/x509.h +++ b/src/pluto/x509.h @@ -2,7 +2,7 @@ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * Copyright (C) 2000-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 @@ -18,8 +18,10 @@ #ifndef _X509_H #define _X509_H +#include <credentials/keys/public_key.h> +#include <credentials/keys/private_key.h> + #include "constants.h" -#include "pkcs1.h" #include "id.h" /* Definition of generalNames kinds */ @@ -51,46 +53,42 @@ struct generalName { typedef struct x509cert x509cert_t; struct x509cert { - x509cert_t *next; - time_t installed; - int count; - bool smartcard; - u_char authority_flags; - chunk_t certificate; - chunk_t tbsCertificate; - u_int version; - chunk_t serialNumber; - /* signature */ - int sigAlg; - chunk_t issuer; - /* validity */ - time_t notBefore; - time_t notAfter; - chunk_t subject; - /* subjectPublicKeyInfo */ - enum pubkey_alg subjectPublicKeyAlgorithm; - chunk_t subjectPublicKey; - chunk_t modulus; - chunk_t publicExponent; - /* issuerUniqueID */ - /* subjectUniqueID */ - /* v3 extensions */ - /* extension */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - bool isCA; - bool isOcspSigner; /* ocsp */ - chunk_t subjectKeyID; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t accessLocation; /* ocsp */ - generalName_t *subjectAltName; - generalName_t *crlDistributionPoints; - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; + x509cert_t *next; + time_t installed; + int count; + bool smartcard; + u_char authority_flags; + chunk_t certificate; + chunk_t tbsCertificate; + u_int version; + chunk_t serialNumber; + /* signature */ + int sigAlg; + chunk_t issuer; + /* validity */ + time_t notBefore; + time_t notAfter; + chunk_t subject; + public_key_t *public_key; + /* issuerUniqueID */ + /* subjectUniqueID */ + /* v3 extensions */ + /* extension */ + /* extension */ + /* extnID */ + /* critical */ + /* extnValue */ + bool isCA; + bool isOcspSigner; /* ocsp */ + chunk_t subjectKeyID; + chunk_t authKeyID; + chunk_t authKeySerialNumber; + chunk_t accessLocation; /* ocsp */ + generalName_t *subjectAltName; + generalName_t *crlDistributionPoints; + /* signatureAlgorithm */ + int algorithm; + chunk_t signature; }; /* used for initialization */ @@ -104,8 +102,8 @@ extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b); extern void hex_str(chunk_t bin, chunk_t *str); extern int dn_count_wildcards(chunk_t dn); extern int dntoa(char *dst, size_t dstlen, chunk_t dn); -extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn - , const char* null_dn); +extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, + const char* null_dn); extern err_t atodn(char *src, chunk_t *dn); extern void gntoid(struct id *id, const generalName_t *gn); extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID); @@ -116,21 +114,23 @@ extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber); extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit); extern err_t check_validity(const x509cert_t *cert, time_t *until); -extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg - , int enc_alg, const x509cert_t *issuer_cert); +extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, + const x509cert_t *issuer_cert); +extern chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key, + bool bit_string); extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until); extern x509cert_t* add_x509cert(x509cert_t *cert); -extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid - , x509cert_t* chain); -extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key - , const RSA_private_key_t *signer_key); +extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, + x509cert_t* chain); +extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key, + private_key_t *signer_key); extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames); extern void share_x509cert(x509cert_t *cert); extern void release_x509cert(x509cert_t *cert); extern void free_x509cert(x509cert_t *cert); extern void store_x509certs(x509cert_t **firstcert, bool strict); -extern void list_x509cert_chain(const char *caption, x509cert_t* cert - , u_char auth_flags, bool utc); +extern void list_x509cert_chain(const char *caption, x509cert_t* cert, + u_char auth_flags, bool utc); extern void list_x509_end_certs(bool utc); extern void free_generalNames(generalName_t* gn, bool free_name); diff --git a/src/scepclient/Makefile.am b/src/scepclient/Makefile.am index f7cfc7355..a6e43a4f1 100644 --- a/src/scepclient/Makefile.am +++ b/src/scepclient/Makefile.am @@ -1,5 +1,5 @@ ipsec_PROGRAMS = scepclient -scepclient_SOURCES = scepclient.c rsakey.c rsakey.h pkcs10.c pkcs10.h scep.c scep.h loglite.c +scepclient_SOURCES = scepclient.c pkcs10.c pkcs10.h scep.c scep.h loglite.c PLUTODIR=$(top_srcdir)/src/pluto OPENACDIR=$(top_srcdir)/src/openac @@ -28,7 +28,7 @@ LIBCRYPTOBUILDDIR=$(top_builddir)/src/libcrypto scepclient_LDADD = \ ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o \ -mp_defs.o ocsp.o pem.o pgp.o pkcs1.o pkcs7.o smartcard.o x509.o \ +mp_defs.o ocsp.o pem.o pgpcert.o pkcs7.o smartcard.o x509.o \ $(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \ $(LIBFREESWANBUILDDIR)/libfreeswan.a \ -lgmp @@ -77,10 +77,7 @@ ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h $(COMPILE) $(INCLUDES) -c -o $@ $< -pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h - $(COMPILE) $(INCLUDES) -c -o $@ $< - -pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h +pgpcert.o : $(PLUTODIR)/pgpcert.c $(PLUTODIR)/pgpcert.h $(COMPILE) $(INCLUDES) -c -o $@ $< pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h diff --git a/src/scepclient/pkcs10.c b/src/scepclient/pkcs10.c index 6933adaf8..cdd68431e 100644 --- a/src/scepclient/pkcs10.c +++ b/src/scepclient/pkcs10.c @@ -31,7 +31,6 @@ #include "../pluto/constants.h" #include "../pluto/defs.h" -#include "../pluto/pkcs1.h" #include "../pluto/log.h" #include "../pluto/x509.h" @@ -158,21 +157,25 @@ build_req_info_attributes(pkcs10_t* pkcs10) static chunk_t pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg) { - RSA_public_key_t *rsak = (RSA_public_key_t *) pkcs10->private_key; + chunk_t key = pkcs10->public_key->get_encoding(pkcs10->public_key); - chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm" - , ASN1_INTEGER_0 - , pkcs10->subject - , pkcs1_build_publicKeyInfo(rsak) - , build_req_info_attributes(pkcs10)); + chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + asn1_bitstring("m", key)); - chunk_t signature = pkcs1_build_signature(cert_req_info - , signature_alg, pkcs10->private_key, TRUE); + chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm", + ASN1_INTEGER_0, + pkcs10->subject, + keyInfo, + build_req_info_attributes(pkcs10)); - return asn1_wrap(ASN1_SEQUENCE, "mcm" - , cert_req_info - , asn1_algorithmIdentifier(signature_alg) - , signature); + chunk_t signature = x509_build_signature(cert_req_info, signature_alg, + pkcs10->private_key, TRUE); + + return asn1_wrap(ASN1_SEQUENCE, "mcm", + cert_req_info, + asn1_algorithmIdentifier(signature_alg), + signature); } /** @@ -189,14 +192,15 @@ pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg) * @param[in] subjectAltNames linked list of subjectAltNames or NULL * @return pointer to a #pkcs10_t object */ -pkcs10_t* -pkcs10_build(RSA_private_key_t *key, chunk_t subject, chunk_t challengePassword -, generalName_t *subjectAltNames, int signature_alg) +pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public, + chunk_t subject, chunk_t challengePassword, + generalName_t *subjectAltNames, int signature_alg) { pkcs10_t *pkcs10 = malloc_thing(pkcs10_t); pkcs10->subject = subject; - pkcs10->private_key = key; + pkcs10->private_key = private; + pkcs10->public_key = public; pkcs10->challengePassword = challengePassword; pkcs10->subjectAltNames = subjectAltNames; diff --git a/src/scepclient/pkcs10.h b/src/scepclient/pkcs10.h index a48dd7c2e..3f29f019a 100644 --- a/src/scepclient/pkcs10.h +++ b/src/scepclient/pkcs10.h @@ -23,8 +23,10 @@ #ifndef _PKCS10_H #define _PKCS10_H +#include <credentials/keys/private_key.h> +#include <credentials/keys/public_key.h> + #include "../pluto/defs.h" -#include "../pluto/pkcs1.h" #include "../pluto/x509.h" typedef struct pkcs10_struct pkcs10_t; @@ -38,20 +40,21 @@ typedef struct pkcs10_struct pkcs10_t; * The RSA private key is needed to compute the signature of the given request */ struct pkcs10_struct { - RSA_private_key_t *private_key; - chunk_t request; - chunk_t subject; - chunk_t challengePassword; - generalName_t *subjectAltNames; + private_key_t *private_key; + public_key_t *public_key; + chunk_t request; + chunk_t subject; + chunk_t challengePassword; + generalName_t *subjectAltNames; }; extern const pkcs10_t empty_pkcs10; -extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames - , generalNames_t kind, char *value); -extern pkcs10_t* pkcs10_build(RSA_private_key_t *key, chunk_t subject - , chunk_t challengePassword, generalName_t *subjectAltNames - , int signature_alg); +extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames, + generalNames_t kind, char *value); +extern pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public, + chunk_t subject, chunk_t challengePassword, + generalName_t *subjectAltNames, int signature_alg); extern void pkcs10_free(pkcs10_t *pkcs10); #endif /* _PKCS10_H */ diff --git a/src/scepclient/rsakey.c b/src/scepclient/rsakey.c deleted file mode 100644 index e7e4a47f5..000000000 --- a/src/scepclient/rsakey.c +++ /dev/null @@ -1,313 +0,0 @@ -/** - * @file rsakey.c - * @brief Functions for RSA key generation - */ - -/* - * Copyright (C) 1999, 2000, 2001 Henry Spencer. - * Copyright (C) 2005 Jan Hutter, Martin Willi - * 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 <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <assert.h> -#include <gmp.h> - -#include <freeswan.h> - -#include <library.h> -#include <crypto/rngs/rng.h> - -#include "../pluto/constants.h" -#include "../pluto/defs.h" -#include "../pluto/mp_defs.h" -#include "../pluto/log.h" -#include "../pluto/pkcs1.h" - -#include "rsakey.h" - -/* Number of times the probabilistic primality test is applied */ -#define PRIMECHECK_ROUNDS 30 - -/* Public exponent used for signature key generation */ -#define PUBLIC_EXPONENT 0x10001 - -#ifndef DEV_RANDOM -#define DEV_RANDOM "/dev/random" -#endif - - -/** - * @brief Reads a specific number of bytes from a given device/file - * - * @param[in] nbytes number of bytes to read from random device - * @param[out] buf pointer to buffer where to write the data in. - * size of buffer has to be at least nbytes. - * @return TRUE, if succeeded, FALSE otherwise - */ - -/** - * @brief initialize an mpz_t to a random number, specified bit count - * - * Converting the random value in a value of type mpz_t is done - * by creating a hexbuffer. - * Converting via hex is a bit weird, but it's the best route GMP gives us. - * Note that highmost and lowmost bits are forced on -- highmost to give a - * number of exactly the specified length, lowmost so it is an odd number. - * - * @param[out] var uninitialized mpz_t to store th random number in - * @param[in] nbits length of var in bits (known to be a multiple of BITS_PER_BYTE) - * @return TRUE on success, FALSE otherwise - */ -static bool init_random(mpz_t var, int nbits) -{ - size_t nbytes = (size_t)(nbits/BITS_PER_BYTE); - char random_buf[RSA_MAX_OCTETS/2]; - rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); - - if (!rng) - { - return FALSE; - } - assert(nbytes <= sizeof(random_buf)); - rng->get_bytes(rng, nbytes, random_buf); - rng->destroy(rng); - - random_buf[0] |= 01 << (BITS_PER_BYTE-1); /* force high bit on */ - random_buf[nbytes-1] |= 01; /* force low bit on */ - n_to_mpz(var, random_buf, nbytes); - return TRUE; -} - -/** - * @brief initialize an mpz_t to a random prime of specified size - * - * Efficiency tweak: we reject candidates that are 1 higher than a multiple - * of e, since they will make the internal modulus not relatively prime to e. - * - * @param[out] var mpz_t variable to initialize - * @param[in] nbits length of given prime in bits (known to be a multiple of BITS_PER_BYTE) - * @param[in] eval E-Value, 0 means don't bother w. tweak - * @return 1 on success, 0 otherwise - */ -static bool init_prime(mpz_t var, int nbits, int eval) -{ - unsigned long tries; - size_t len; - - /* get a random value of nbits length */ - if (!init_random(var, nbits)) - return FALSE; - - /* check if odd number */ - assert(mpz_fdiv_ui(var, 2) == 1); - DBG(DBG_CONTROLMORE, - DBG_log("looking for a prime starting there (can take a while)...") - ) - - tries = 1; - while (mpz_fdiv_ui(var, eval) == 1 - || !mpz_probab_prime_p(var, PRIMECHECK_ROUNDS)) - { - /* not a prime, increase by 2 */ - mpz_add_ui(var, var, 2); - tries++; - } - - len = mpz_sizeinbase(var, 2); - - /* check bit length of primee */ - assert(len == (size_t)nbits || len == (size_t)(nbits+1)); - - if (len == (size_t)(nbits+1)) - { - DBG(DBG_CONTROLMORE, - DBG_log("carry out occurred (!), retrying...") - ) - mpz_clear(var); - /* recursive call */ - return init_prime(var, nbits, eval); - } - DBG(DBG_CONTROLMORE, - DBG_log("found it after %lu tries.",tries) - ) - return TRUE; -} - -/** - * @brief Generate a RSA key usable for encryption - * - * Generate an RSA key usable for encryption. All the - * values of the RSA key are filled into mpz_t parameters. - * These mpz_t parameters must not be initialized and have - * to be cleared with mpz_clear after using. - * - * @param[in] nbits size of rsa key in bits - * @return RSA_public_key_t containing the generated RSA key - */ -err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key) -{ - mpz_t p, q, n, e, d, exp1, exp2, coeff; - mpz_t m, q1, t; /* temporary variables*/ - - DBG(DBG_CONTROL, - DBG_log("generating %d bit RSA key:", nbits) - ) - - if (nbits <= 0) - return "negative rsa key length!"; - - /* Get values of primes p and q */ - DBG(DBG_CONTROLMORE, - DBG_log("initialize prime p") - ) - if (!init_prime(p, nbits/2, PUBLIC_EXPONENT)) - return "could not generate prime p"; - - DBG(DBG_CONTROLMORE, - DBG_log("initialize prime q") - ) - if (!init_prime(q, nbits/2, PUBLIC_EXPONENT)) - return "could not generate prime q"; - - mpz_init(t); - - /* Swapping primes so p is larger then q */ - if (mpz_cmp(p, q) < 0) - { - DBG(DBG_CONTROLMORE, - DBG_log("swapping primes so p is the larger...") - ); - mpz_set(t, p); - mpz_set(p, q); - mpz_set(q, t); - } - - DBG(DBG_CONTROLMORE, - DBG_log("computing modulus...") - ) - mpz_init(n); - /* n = p*q */ - mpz_mul(n, p, q); - - /* Assign e the value of defined PUBLIC_EXPONENT */ - mpz_init_set_ui(e, PUBLIC_EXPONENT); - - DBG(DBG_CONTROLMORE, - DBG_log("computing lcm(p-1, q-1)...") - ) - /* m = p */ - mpz_init_set(m, p); - /* m = m-1 */ - mpz_sub_ui(m, m, 1); - /* q1 = q */ - mpz_init_set(q1, q); - /* q1 = q1-1 */ - mpz_sub_ui(q1, q1, 1); - /* t = gcd(p-1, q-1) */ - mpz_gcd(t, m, q1); - /* m = (p-1)*(q-1) */ - mpz_mul(m, m, q1); - /* m = m / t */ - mpz_divexact(m, m, t); - /* t = gcd(m, e) (greatest common divisor) */ - mpz_gcd(t, m, e); - /* m and e relatively prime */ - assert(mpz_cmp_ui(t, 1) == 0); - - /* decryption key */ - DBG(DBG_CONTROLMORE, - DBG_log("computing d...") - ) - mpz_init(d); - /* e has an inverse mod m */ - assert(mpz_invert(d, e, m)); - - /* make sure d is positive */ - if (mpz_cmp_ui(d, 0) < 0) - mpz_add(d, d, m); - - /* d has to be positive */ - assert(mpz_cmp(d, m) < 0); - - /* the speedup hacks */ - DBG(DBG_CONTROLMORE, - DBG_log("computing exp1, exp1, coeff...") - ) - mpz_init(exp1); - /* t = p-1 */ - mpz_sub_ui(t, p, 1); - /* exp1 = d mod p-1 */ - mpz_mod(exp1, d, t); - - mpz_init(exp2); - /* t = q-1 */ - mpz_sub_ui(t, q, 1); - /* exp2 = d mod q-1 */ - mpz_mod(exp2, d, t); - - mpz_init(coeff); - /* coeff = q^-1 mod p */ - mpz_invert(coeff, q, p); - - /* make sure coeff is positive */ - if (mpz_cmp_ui(coeff, 0) < 0) - mpz_add(coeff, coeff, p); - - /* coeff has to be positive */ - assert(mpz_cmp(coeff, p) < 0); - - /* Clear temporary variables */ - mpz_clear(q1); - mpz_clear(m); - mpz_clear(t); - - /* form FreeS/WAN keyid */ - { - size_t e_len = (mpz_sizeinbase(e,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE; - size_t n_len = (mpz_sizeinbase(n,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE; - chunk_t e_ch = mpz_to_n(e, e_len); - chunk_t n_ch = mpz_to_n(n, n_len); - - form_keyid(e_ch, n_ch, key->pub.keyid, &key->pub.k); - free(e_ch.ptr); - free(n_ch.ptr); - } - - /* fill in the elements of the RSA private key */ - key->p = *p; - key->q = *q; - key->pub.n = *n; - key->pub.e = *e; - key->d = *d; - key->dP = *exp1; - key->dQ = *exp2; - key->qInv = *coeff; - - DBG(DBG_CONTROL, - DBG_log("RSA key *%s generated with %d bits", key->pub.keyid - , (int)mpz_sizeinbase(n,2)) - ) - -#ifdef DEBUG - DBG(DBG_PRIVATE, - RSA_show_private_key(key) - ) -#endif - return NULL; -} diff --git a/src/scepclient/scep.c b/src/scepclient/scep.c index dd16dff1b..a788c6f41 100644 --- a/src/scepclient/scep.c +++ b/src/scepclient/scep.c @@ -34,7 +34,6 @@ #include "../pluto/constants.h" #include "../pluto/defs.h" -#include "../pluto/pkcs1.h" #include "../pluto/fetch.h" #include "../pluto/log.h" @@ -266,35 +265,43 @@ end: * Generates a unique fingerprint of the pkcs10 request * by computing an MD5 hash over it */ -void scep_generate_pkcs10_fingerprint(chunk_t pkcs10, chunk_t *fingerprint) +chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10) { - char buf[HASH_SIZE_MD5]; - chunk_t digest = { buf, sizeof(buf) }; - - /* the fingerprint is the MD5 hash in hexadecimal format */ - compute_digest(pkcs10, OID_MD5, &digest); - fingerprint->len = 2*digest.len; - fingerprint->ptr = malloc(fingerprint->len + 1); - datatot(digest.ptr, digest.len, 16, fingerprint->ptr, fingerprint->len + 1); + char digest_buf[HASH_SIZE_MD5]; + chunk_t digest = chunk_from_buf(digest_buf); + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + hasher->get_hash(hasher, pkcs10, digest_buf); + hasher->destroy(hasher); + + return chunk_to_hex(digest, NULL, FALSE); } /** * Generate a transaction id as the MD5 hash of an public key * the transaction id is also used as a unique serial number */ -void scep_generate_transaction_id(const RSA_public_key_t *rsak, - chunk_t *transID, chunk_t *serialNumber) +void scep_generate_transaction_id(public_key_t *key, chunk_t *transID, + chunk_t *serialNumber) { - char buf[HASH_SIZE_MD5]; - - chunk_t digest = { buf, sizeof(buf) }; - chunk_t public_key = pkcs1_build_publicKeyInfo(rsak); - + char digest_buf[HASH_SIZE_MD5]; + chunk_t digest = chunk_from_buf(digest_buf); + chunk_t keyEncoding, keyInfo; + hasher_t *hasher; bool msb_set; u_char *pos; + + keyEncoding = key->get_encoding(key); + + keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + asn1_bitstring("m", keyEncoding)); - compute_digest(public_key, OID_MD5, &digest); - free(public_key.ptr); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + hasher->get_hash(hasher, keyInfo, digest_buf); + hasher->destroy(hasher); + free(keyInfo.ptr); /* is the most significant bit of the digest set? */ msb_set = (*digest.ptr & 0x80) == 0x80; @@ -376,7 +383,7 @@ chunk_t scep_senderNonce_attribute(void) chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg, const x509cert_t *enc_cert, int enc_alg, const x509cert_t *signer_cert, int digest_alg, - const RSA_private_key_t *private_key) + private_key_t *private_key) { chunk_t envelopedData, attributes, request; diff --git a/src/scepclient/scep.h b/src/scepclient/scep.h index 2a11a246e..e8dc87591 100644 --- a/src/scepclient/scep.h +++ b/src/scepclient/scep.h @@ -24,7 +24,6 @@ #define _SCEP_H #include "../pluto/defs.h" -#include "../pluto/pkcs1.h" #include "../pluto/pkcs7.h" /* supported SCEP operation types */ @@ -74,20 +73,21 @@ typedef struct { extern const scep_attributes_t empty_scep_attributes; extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs); -extern void scep_generate_pkcs10_fingerprint(chunk_t pkcs10 - , chunk_t *fingerprint); -extern void scep_generate_transaction_id(const RSA_public_key_t *rsak - , chunk_t *transID, chunk_t *serialNumber); +extern void scep_generate_transaction_id(public_key_t *key, + chunk_t *transID, + chunk_t *serialNumber); +extern chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10); extern chunk_t scep_transId_attribute(chunk_t transaction_id); extern chunk_t scep_messageType_attribute(scep_msg_t m); extern chunk_t scep_senderNonce_attribute(void); -extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg - , const x509cert_t *enc_cert, int enc_alg - , const x509cert_t *signer_cert, int digest_alg - , const RSA_private_key_t *private_key); -extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op - , bool http_get_request, chunk_t *response); -extern err_t scep_parse_response(chunk_t response, chunk_t transID - , contentInfo_t *data, scep_attributes_t *attrs, x509cert_t *signer_cert); +extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg, + const x509cert_t *enc_cert, int enc_alg, + const x509cert_t *signer_cert, int digest_alg, + private_key_t *private_key); +extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op, + bool http_get_request, chunk_t *response); +extern err_t scep_parse_response(chunk_t response, chunk_t transID, + contentInfo_t *data, scep_attributes_t *attrs, + x509cert_t *signer_cert); #endif /* _SCEP_H */ diff --git a/src/scepclient/scepclient.c b/src/scepclient/scepclient.c index 96853e948..eb3197689 100644 --- a/src/scepclient/scepclient.c +++ b/src/scepclient/scepclient.c @@ -42,15 +42,15 @@ #include <asn1/oid.h> #include <utils/optionsfrom.h> #include <utils/enumerator.h> +#include <credentials/keys/private_key.h> +#include <credentials/keys/public_key.h> #include "../pluto/constants.h" #include "../pluto/defs.h" #include "../pluto/log.h" -#include "../pluto/pkcs1.h" #include "../pluto/pkcs7.h" #include "../pluto/certs.h" -#include "rsakey.h" #include "pkcs10.h" #include "scep.h" @@ -120,7 +120,8 @@ options_t *options; * Global variables */ -RSA_private_key_t *private_key = NULL; +private_key_t *private_key = NULL; +public_key_t *public_key = NULL; chunk_t pkcs1; chunk_t pkcs7; @@ -150,11 +151,8 @@ exit_scepclient(err_t message, ...) { int status = 0; - if (private_key != NULL) - { - free_RSA_private_content(private_key); - free(private_key); - } + DESTROY_IF(private_key); + DESTROY_IF(public_key); free(pkcs1.ptr); free(pkcs7.ptr); free(subject.ptr); @@ -784,24 +782,27 @@ int main(int argc, char **argv) /* * input of PKCS#1 file */ - private_key = malloc_thing(RSA_private_key_t); - if (filetype_in & PKCS1) /* load an RSA key pair from file */ { prompt_pass_t pass = { "", FALSE, STDIN_FILENO }; char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1); - ugh = load_rsa_private_key(path, &pass, private_key); + private_key = load_private_key(path, &pass, KEY_RSA); } else /* generate an RSA key pair */ { - ugh = generate_rsa_private_key(rsa_keylength, private_key); + private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_KEY_SIZE, rsa_keylength, + BUILD_END); } - if (ugh != NULL) - exit_scepclient(ugh); + if (private_key == NULL) + { + exit_scepclient("no RSA private key available"); + } + public_key = private_key->get_public_key(private_key); /* check for minimum key length */ - if ((private_key->pub.k) < RSA_MIN_OCTETS) + if (private_key->get_keysize(private_key) < RSA_MIN_OCTETS) { exit_scepclient("length of RSA key has to be at least %d bits" ,RSA_MIN_OCTETS * BITS_PER_BYTE); @@ -855,10 +856,11 @@ int main(int argc, char **argv) DBG(DBG_CONTROL, DBG_log("building pkcs10 object:") ) - pkcs10 = pkcs10_build(private_key, subject, challengePassword - , subjectAltNames, pkcs10_signature_alg); - scep_generate_pkcs10_fingerprint(pkcs10->request, &fingerprint); - plog(" fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr); + pkcs10 = pkcs10_build(private_key, public_key, subject, + challengePassword, subjectAltNames, + pkcs10_signature_alg); + fingerprint = scep_generate_pkcs10_fingerprint(pkcs10->request); + plog(" fingerprint: %s", fingerprint.ptr); } /* @@ -889,7 +891,7 @@ int main(int argc, char **argv) DBG(DBG_CONTROL, DBG_log("building pkcs1 object:") ) - pkcs1 = pkcs1_build_private_key(private_key); + pkcs1 = private_key->get_encoding(private_key); if (!chunk_write(pkcs1, path, "pkcs1", 0066, force)) exit_scepclient("could not write pkcs1 file '%s'", path); @@ -902,8 +904,7 @@ int main(int argc, char **argv) exit_scepclient(NULL); /* no further output required */ } - scep_generate_transaction_id((const RSA_public_key_t *)private_key - , &transID, &serialNumber); + scep_generate_transaction_id(public_key, &transID, &serialNumber); plog(" transaction ID: %.*s", (int)transID.len, transID.ptr); /* generate a self-signed X.509 certificate */ @@ -918,9 +919,7 @@ int main(int argc, char **argv) : x509_signer->notBefore + validity; x509_signer->subject = subject; x509_signer->subjectAltName = subjectAltNames; - - build_x509cert(x509_signer, (const RSA_public_key_t *)private_key - , private_key); + build_x509cert(x509_signer, public_key, private_key); /* * output of self-signed X.509 certificate file diff --git a/src/strongswan.conf b/src/strongswan.conf index 661792a67..0ec4ae9ef 100644 --- a/src/strongswan.conf +++ b/src/strongswan.conf @@ -6,12 +6,11 @@ charon { threads = 16 # plugins to load in charon - # load = aes des gmp hmac md5 random sha1 sha2 pubkey xcbc x509 stroke + # load = aes des sha1 md5 sha2 hmac gmp random pubkey xcbc x509 stroke plugins { - + sql { - # loglevel to log into sql database loglevel = -1 @@ -23,3 +22,16 @@ charon { # ... } + +pluto { + + # plugins to load in pluto + # load = aes des sha1 md5 sha2 hmac gmp random pubkey + +} + +libstrongswan { + + # set to no, the DH exponent size is optimized + # dh_exponent_ansi_x9_42 = no +} |