pluto and scepclient use private and public key plugins of libstrongswan
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 5 Jun 2009 19:14:31 +0000 (21:14 +0200)
committerMartin Willi <martin@strongswan.org>
Tue, 9 Jun 2009 09:03:32 +0000 (11:03 +0200)
49 files changed:
src/libstrongswan/Makefile.am
src/libstrongswan/asn1/asn1.c
src/libstrongswan/asn1/asn1.h
src/libstrongswan/credentials/builder.c
src/libstrongswan/credentials/builder.h
src/libstrongswan/credentials/credential_factory.c
src/libstrongswan/credentials/keys/private_key.h
src/libstrongswan/credentials/keys/public_key.c
src/libstrongswan/credentials/keys/public_key.h
src/libstrongswan/pgp/pgp.c [new file with mode: 0644]
src/libstrongswan/pgp/pgp.h [new file with mode: 0644]
src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
src/libstrongswan/plugins/x509/x509_cert.c
src/pluto/Makefile.am
src/pluto/ac.c
src/pluto/ca.c
src/pluto/certs.c
src/pluto/certs.h
src/pluto/connections.c
src/pluto/crl.c
src/pluto/dnskey.c
src/pluto/ipsec_doi.c
src/pluto/kernel.c
src/pluto/keys.c
src/pluto/keys.h
src/pluto/ocsp.c
src/pluto/pgp.c [deleted file]
src/pluto/pgp.h [deleted file]
src/pluto/pgpcert.c [new file with mode: 0644]
src/pluto/pgpcert.h [new file with mode: 0644]
src/pluto/pkcs1.c [deleted file]
src/pluto/pkcs1.h [deleted file]
src/pluto/pkcs7.c
src/pluto/pkcs7.h
src/pluto/rcv_whack.c
src/pluto/x509.c
src/pluto/x509.h
src/scepclient/Makefile.am
src/scepclient/pkcs10.c
src/scepclient/pkcs10.h
src/scepclient/rsakey.c [deleted file]
src/scepclient/rsakey.h [deleted file]
src/scepclient/scep.c
src/scepclient/scep.h
src/scepclient/scepclient.c
src/strongswan.conf

index 089d089..c2a1a5a 100644 (file)
@@ -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 \
index 85f906c..d57444d 100644 (file)
@@ -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').
  */
index 1239059..6a2b594 100644 (file)
@@ -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
index 0bca198..701cbcd 100644 (file)
@@ -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",
index 4b3fb1a..01ccf2a 100644 (file)
@@ -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* */
index 76438a5..2e9a541 100644 (file)
@@ -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;
index 62f1167..f38af8f 100644 (file)
@@ -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
index f08b2dc..c5b5d6f 100644 (file)
 
 #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",
index 86571b0..d78791a 100644 (file)
@@ -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/libstrongswan/pgp/pgp.c b/src/libstrongswan/pgp/pgp.c
new file mode 100644 (file)
index 0000000..f1f9247
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include "pgp.h"
+
+ENUM(pgp_sym_alg_names, PGP_SYM_ALG_PLAIN, PGP_SYM_ALG_TWOFISH,
+       "PLAINTEXT",
+       "IDEA",
+       "3DES",
+       "CAST5",
+       "BLOWFISH",
+       "SAFER",
+       "DES",
+       "AES_128",
+       "AES_192",
+       "AES_256",
+       "TWOFISH"
+);
+
+/*
+ * Defined in header.
+ */
+size_t pgp_length(chunk_t *blob, size_t len)
+{
+       size_t size = 0;
+
+       if (len > blob->len)
+       {
+               return PGP_INVALID_LENGTH;
+       }
+       blob->len -= len;
+
+       while (len-- > 0)
+       {
+               size = 256*size + *blob->ptr++;
+       }
+       return size;
+}
+
diff --git a/src/libstrongswan/pgp/pgp.h b/src/libstrongswan/pgp/pgp.h
new file mode 100644 (file)
index 0000000..b120319
--- /dev/null
@@ -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_ @}*/
index e3244cc..bfe9d3c 100644 (file)
@@ -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;
                        }               
index acb44a1..4c77970 100644 (file)
 #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;
                        }
index 4004e09..12040f2 100644 (file)
@@ -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;
index 8803b79..d0fd562 100644 (file)
@@ -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;
index 57fef94..34c121d 100644 (file)
@@ -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",
index 2c91c3d..2694011 100644 (file)
@@ -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 \
index 3c886f9..3b5df97 100644 (file)
@@ -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;
index 363a78b..4fdb8cf 100644 (file)
@@ -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");
index 7d78f22..29e7dbf 100644 (file)
@@ -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
 
 #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;
 }
 
 /**
index 1d9e984..a88fc15 100644 (file)
@@ -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
 #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);
index 960884e..bdfdc10 100644 (file)
 #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;
 
index 1d9b544..c800f2a 100644 (file)
@@ -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");
 
index bd19053..ed901ad 100644 (file)
@@ -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
                                {
index 52f5553..49f40e3 100644 (file)
@@ -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;
index fdc2c4c..f698de2 100644 (file)
@@ -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));
index 031d00a..c0eb6ae 100644 (file)
 
 #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;
        }
index 84d941f..8bc94d8 100644 (file)
@@ -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
index 1445f4b..80164fa 100644 (file)
@@ -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/pgp.c
deleted file mode 100644 (file)
index e80b2cc..0000000
+++ /dev/null
@@ -1,654 +0,0 @@
-/* Support of OpenPGP certificates
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <freeswan.h>
-
-#include <library.h>
-#include <crypto/hashers/hasher.h>
-
-#include "constants.h"
-#include "defs.h"
-#include "mp_defs.h"
-#include "log.h"
-#include "id.h"
-#include "pgp.h"
-#include "certs.h"
-#include "whack.h"
-#include "pkcs1.h"
-#include "keys.h"
-
-/*
- * chained list of OpenPGP end certificates
- */
-static pgpcert_t *pgpcerts   = NULL;
-
-/*
- * OpenPGP packet tags defined in section 4.3 of RFC 2440
- */
-#define PGP_PKT_RESERVED                 0
-#define PGP_PKT_PUBKEY_ENC_SESSION_KEY   1
-#define PGP_PKT_SIGNATURE                2
-#define PGP_PKT_SYMKEY_ENC_SESSION_KEY   3
-#define PGP_PKT_ONE_PASS_SIGNATURE_PKT   4
-#define PGP_PKT_SECRET_KEY               5
-#define PGP_PKT_PUBLIC_KEY               6
-#define PGP_PKT_SECRET_SUBKEY            7
-#define PGP_PKT_COMPRESSED_DATA          8
-#define PGP_PKT_SYMKEY_ENC_DATA          9
-#define PGP_PKT_MARKER                  10
-#define PGP_PKT_LITERAL_DATA            11
-#define PGP_PKT_TRUST                   12
-#define PGP_PKT_USER_ID                 13
-#define PGP_PKT_PUBLIC_SUBKEY           14
-#define PGP_PKT_ROOF                    15
-
-static const char *const pgp_packet_type_name[] = {
-       "Reserved",
-       "Public-Key Encrypted Session Key Packet",
-       "Signature Packet",
-       "Symmetric-Key Encrypted Session Key Packet",
-       "One-Pass Signature Packet",
-       "Secret Key Packet",
-       "Public Key Packet",
-       "Secret Subkey Packet",
-       "Compressed Data Packet",
-       "Symmetrically Encrypted Data Packet",
-       "Marker Packet",
-       "Literal Data Packet",
-       "Trust Packet",
-       "User ID Packet",
-       "Public Subkey Packet"
-};
-
-/*
- * OpenPGP public key algorithms defined in section 9.1 of RFC 2440
- */
-#define PGP_PUBKEY_ALG_RSA               1
-#define PGP_PUBKEY_ALG_RSA_ENC_ONLY      2
-#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY     3
-#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16
-#define PGP_PUBKEY_ALG_DSA              17
-#define PGP_PUBKEY_ALG_ECC              18
-#define PGP_PUBKEY_ALG_ECDSA            19
-#define PGP_PUBKEY_ALG_ELGAMAL          20
-
-/*
- * OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440
-  */
-#define PGP_SYM_ALG_PLAIN        0
-#define PGP_SYM_ALG_IDEA         1
-#define PGP_SYM_ALG_3DES         2
-#define PGP_SYM_ALG_CAST5        3
-#define PGP_SYM_ALG_BLOWFISH     4
-#define PGP_SYM_ALG_SAFER        5
-#define PGP_SYM_ALG_DES          6
-#define PGP_SYM_ALG_AES          7
-#define PGP_SYM_ALG_AES_192      8
-#define PGP_SYM_ALG_AES_256      9
-#define PGP_SYM_ALG_TWOFISH     10
-#define PGP_SYM_ALG_ROOF        11
-
-static const char *const pgp_sym_alg_name[] = {
-       "Plaintext",
-       "IDEA",
-       "3DES",
-       "CAST5",
-       "Blowfish",
-       "SAFER",
-       "DES",
-       "AES",
-       "AES-192",
-       "AES-256",
-       "Twofish"
-};
-
-/*
- * Size of PGP Key ID
- */
-#define PGP_KEYID_SIZE          8
-
-const pgpcert_t empty_pgpcert = {
-         NULL     , /* *next */
-                       0  , /* installed */
-                       0  , /* count */
-       { NULL, 0 }, /* certificate */
-                       0  , /* created */
-                       0  , /* until */
-                       0  , /* pubkeyAlgorithm */
-       { NULL, 0 }, /* modulus */
-       { NULL, 0 }, /* publicExponent */
-          ""        /* fingerprint */
-};
-
-static size_t
-pgp_size(chunk_t *blob, int len)
-{
-       size_t size = 0;
-
-       blob->len -= len;
-       while (len-- > 0)
-               size = 256*size + *blob->ptr++;
-       return size;
-}
-
-/*
- * extracts the length of a PGP packet
- */
-static size_t
-pgp_old_packet_length(chunk_t *blob)
-{
-       /* bits 0 and 1 define the packet length type */
-       int len_type = 0x03 & *blob->ptr++;
-
-       blob->len--;
-
-       /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
-       return pgp_size(blob, (len_type == 0)? 1: len_type << 1);
-}
-
-/*
- * extracts PGP packet version (V3 or V4)
- */
-static u_char
-pgp_version(chunk_t *blob)
-{
-       u_char version = *blob->ptr++;
-       blob->len--;
-       DBG(DBG_PARSING,
-               DBG_log("L3 - version:");
-               DBG_log("  V%d", version)
-       )
-       return version;
-}
-
-/*
- * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
- */
-static bool
-parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
-{
-       u_char version = pgp_version(packet);
-
-       if (version < 3 || version > 4)
-       {
-               plog("PGP packet version V%d not supported", version);
-               return FALSE;
-       }
-
-       /* creation date - 4 bytes */
-       cert->created = (time_t)pgp_size(packet, 4);
-       DBG(DBG_PARSING,
-               DBG_log("L3 - created:");
-               DBG_log("  %T", &cert->created, TRUE)
-       )
-
-       if (version == 3)
-       {
-               /* validity in days - 2 bytes */
-               cert->until   = (time_t)pgp_size(packet, 2);
-
-               /* validity of 0 days means that the key never expires */
-               if (cert->until > 0)
-                       cert->until = cert->created + 24*3600*cert->until;
-
-               DBG(DBG_PARSING,
-                       DBG_log("L3 - until:");
-                       DBG_log("  %T", &cert->until, TRUE);
-               )
-       }
-
-       /* public key algorithm - 1 byte */
-       DBG(DBG_PARSING,
-               DBG_log("L3 - public key algorithm:")
-       )
-
-       switch (pgp_size(packet, 1))
-       {
-       case PGP_PUBKEY_ALG_RSA:
-       case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
-               cert->pubkeyAlg = PUBKEY_ALG_RSA;
-               DBG(DBG_PARSING,
-                       DBG_log("  RSA")
-               )
-               /* modulus n */
-               cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
-               cert->modulus.ptr = packet->ptr;
-               packet->ptr += cert->modulus.len;
-               packet->len -= cert->modulus.len;
-               DBG(DBG_PARSING,
-                       DBG_log("L3 - modulus:")
-               )
-               DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus);
-
-               /* public exponent e */
-               cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
-               cert->publicExponent.ptr = packet->ptr;
-               packet->ptr += cert->publicExponent.len;
-               packet->len -= cert->publicExponent.len;
-               DBG(DBG_PARSING,
-                       DBG_log("L3 - public exponent:")
-               )
-               DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent);
-
-               if (version == 3)
-               {
-                       hasher_t *hasher;
-
-                       /* a V3 fingerprint is the MD5 hash of modulus and public exponent */
-
-                       hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);     
-                       if (hasher == NULL)
-                       {
-                               plog("  computation of V3 key ID failed, no MD5 hasher is available");
-                               return FALSE;
-                       }
-                       hasher->get_hash(hasher, cert->modulus, NULL);
-                       hasher->get_hash(hasher, cert->publicExponent, cert->fingerprint);
-                       hasher->destroy(hasher);
-               }
-               else
-               {
-                       plog("  computation of V4 key ID not implemented yet");
-               }
-               break;
-       case PGP_PUBKEY_ALG_DSA:
-               cert->pubkeyAlg = PUBKEY_ALG_DSA;
-               DBG(DBG_PARSING,
-                       DBG_log("  DSA")
-               )
-               plog("  DSA public keys not supported");
-               return FALSE;
-        default:
-               cert->pubkeyAlg = 0;
-               DBG(DBG_PARSING,
-                       DBG_log("  other")
-               )
-               plog(" exotic not RSA public keys not supported");
-               return FALSE;
-       }
-       return TRUE;
-}
-
-/*
- * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440
- */
-static bool
-parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key)
-{
-       int i, s2k;
-       pgpcert_t cert = empty_pgpcert;
-
-       if (!parse_pgp_pubkey_packet(packet, &cert))
-               return FALSE;
-
-       init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent
-                                                                                          , cert.modulus);
-
-       /* string-to-key usage */
-       s2k = pgp_size(packet, 1);
-
-       DBG(DBG_PARSING,
-               DBG_log("L3 - string-to-key:  %d", s2k)
-       )
-
-       if (s2k == 255)
-       {
-               plog("  string-to-key specifiers not supported");
-               return FALSE;
-       }
-
-       if (s2k >= PGP_SYM_ALG_ROOF)
-       {
-               plog("  undefined symmetric key algorithm");
-               return FALSE;
-       }
-
-       /* a known symmetric key algorithm is specified*/
-       DBG(DBG_PARSING,
-               DBG_log("  %s", pgp_sym_alg_name[s2k])
-       )
-
-       /* private key is unencrypted */
-       if (s2k == PGP_SYM_ALG_PLAIN)
-       {
-               for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++)
-               {
-                       mpz_t u;  /* auxiliary variable */
-
-                       /* compute offset to private key component i*/
-                       MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset);
-
-                       switch (i)
-                       {
-                       case 2:
-                       case 3:
-                       case 4:
-                               {
-                                       size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
-
-                                       n_to_mpz(n, packet->ptr, len);
-                                       DBG(DBG_PARSING,
-                                               DBG_log("L3 - %s:", RSA_private_field[i].name)
-                                       )
-                                       DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len);
-                                       packet->ptr += len;
-                                       packet->len -= len;
-                               }
-                               break;
-                       case 5:             /* dP = d mod (p-1) */
-                               mpz_init(u);
-                               mpz_sub_ui(u, &key->p, 1);
-                               mpz_mod(n, &key->d, u);
-                               mpz_clear(u);
-                               break;
-                       case 6:             /* dQ = d mod (q-1) */
-                               mpz_init(u);
-                               mpz_sub_ui(u, &key->q, 1);
-                               mpz_mod(n, &key->d, u);
-                               mpz_clear(u);
-                               break;
-                       case 7:             /* qInv = (q^-1) mod p */
-                               mpz_invert(n, &key->q, &key->p);
-                               if (mpz_cmp_ui(n, 0) < 0)
-                                       mpz_add(n, n, &key->p);
-                               passert(mpz_cmp(n, &key->p) < 0);
-                               break;
-                       }
-               }
-               return TRUE;
-       }
-
-       plog("  %s encryption not supported",  pgp_sym_alg_name[s2k]);
-       return FALSE;
-}
-
-/*
- * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
- */
-static bool
-parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
-{
-       time_t created;
-       chunk_t keyid;
-       u_char  sig_type;
-       u_char version = pgp_version(packet);
-
-       /* we parse only V3 signature packets */
-       if (version != 3)
-               return TRUE;
-
-       /* size byte must have the value 5 */
-       if (pgp_size(packet, 1) != 5)
-       {
-               plog(" size must be 5");
-               return FALSE;
-       }
-
-       /* signature type - 1 byte */
-       sig_type = (u_char)pgp_size(packet, 1);
-       DBG(DBG_PARSING,
-               DBG_log("L3 - signature type:  0x%2x", sig_type)
-       )
-
-       /* creation date - 4 bytes */
-       created = (time_t)pgp_size(packet, 4);
-       DBG(DBG_PARSING,
-               DBG_log("L3 - created:");
-               DBG_log("  %T", &cert->created, TRUE)
-       )
-
-       /* key ID of signer - 8 bytes */
-       keyid.ptr = packet->ptr;
-       keyid.len = PGP_KEYID_SIZE;
-       DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
-
-   return TRUE;
-}
-
-bool
-parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
-{
-       DBG(DBG_PARSING,
-               DBG_log("L0 - PGP file:")
-       )
-       DBG_cond_dump_chunk(DBG_RAW, "", blob);
-
-       if (cert != NULL)
-       {
-               /* parse a PGP certificate file */
-               cert->certificate = blob;
-               time(&cert->installed);
-       }
-       else if (key == NULL)
-       {
-               /* should not occur, nothing to parse */
-               return FALSE;
-       }
-
-       while (blob.len > 0)
-       {
-               chunk_t packet = chunk_empty;
-               u_char packet_tag = *blob.ptr;
-
-               DBG(DBG_PARSING,
-                       DBG_log("L1 - PGP packet:  tag= 0x%2x", packet_tag)
-               )
-
-               /* bit 7 must be set */
-               if (!(packet_tag & 0x80))
-               {
-                       plog("  incorrect Packet Tag");
-                       return FALSE;
-               }
-
-               /* bit 6 set defines new packet format */
-               if (packet_tag & 0x40)
-               {
-                       plog("  new PGP packet format not supported");
-                       return FALSE;
-               }
-               else
-               {
-                       int packet_type = (packet_tag & 0x3C) >> 2;
-
-                       packet.len = pgp_old_packet_length(&blob);
-                       packet.ptr = blob.ptr;
-                       blob.ptr += packet.len;
-                       blob.len -= packet.len;
-                       DBG(DBG_PARSING,
-                               DBG_log("  %s (%d), old format, %d bytes",
-                                       (packet_type < PGP_PKT_ROOF) ?
-                                       pgp_packet_type_name[packet_type] :
-                                       "Undefined Packet Type", packet_type, (int)packet.len);
-                               DBG_log("L2 - body:")
-                       )
-                       DBG_cond_dump_chunk(DBG_RAW, "", packet);
-
-                       if (cert != NULL)
-                       {
-                               /* parse a PGP certificate */
-                               switch (packet_type)
-                               {
-                               case PGP_PKT_PUBLIC_KEY:
-                                       if (!parse_pgp_pubkey_packet(&packet, cert))
-                                               return FALSE;
-                                       break;
-                               case PGP_PKT_SIGNATURE:
-                                       if (!parse_pgp_signature_packet(&packet, cert))
-                                               return FALSE;
-                                       break;
-                               case PGP_PKT_USER_ID:
-                                       DBG(DBG_PARSING,
-                                               DBG_log("L3 - user ID:");
-                                               DBG_log("  '%.*s'", (int)packet.len, packet.ptr)
-                                       )
-                                       break;
-                               default:
-                                       break;
-                               }
-                       }
-                       else
-                       {
-                               /* parse a PGP private key file */
-                               switch (packet_type)
-                               {
-                               case PGP_PKT_SECRET_KEY:
-                                       if (!parse_pgp_secretkey_packet(&packet, key))
-                                               return FALSE;
-                                       break;
-                               default:
-                                       break;
-                               }
-                       }
-               }
-       }
-       return TRUE;
-}
-
-/*
- *  compare two OpenPGP certificates
- */
-static bool
-same_pgpcert(pgpcert_t *a, pgpcert_t *b)
-{
-       return a->certificate.len == b->certificate.len &&
-               memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
-}
-
-/*
- * for each link pointing to the certificate increase the count by one
- */
-void
-share_pgpcert(pgpcert_t *cert)
-{
-       if (cert != NULL)
-       {
-               cert->count++;
-       }
-}
-
-/*
- * select the OpenPGP keyid as ID
- */
-void
-select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
-{
-       end_id->kind = ID_KEY_ID;
-       end_id->name.len = PGP_FINGERPRINT_SIZE;
-       end_id->name.ptr = cert->fingerprint;
-       end_id->name.ptr = temporary_cyclic_buffer();
-       memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE);
-}
-
-/*
- *  add an OpenPGP user/host certificate to the chained list
- */
-pgpcert_t*
-add_pgpcert(pgpcert_t *cert)
-{
-       pgpcert_t *c = pgpcerts;
-
-       while (c != NULL)
-       {
-               if (same_pgpcert(c, cert)) /* already in chain, free cert */
-               {
-                       free_pgpcert(cert);
-                       return c;
-               }
-               c = c->next;
-       }
-
-       /* insert new cert at the root of the chain */
-       cert->next = pgpcerts;
-       pgpcerts = cert;
-       DBG(DBG_CONTROL | DBG_PARSING,
-               DBG_log("  pgp cert inserted")
-       )
-       return cert;
-}
-
-/*  release of a certificate decreases the count by one
- "  the certificate is freed when the counter reaches zero
- */
-void
-release_pgpcert(pgpcert_t *cert)
-{
-       if (cert != NULL && --cert->count == 0)
-       {
-               pgpcert_t **pp = &pgpcerts;
-               while (*pp != cert)
-                       pp = &(*pp)->next;
-               *pp = cert->next;
-               free_pgpcert(cert);
-       }
-}
-
-/*
- *  free a PGP certificate
- */
-void
-free_pgpcert(pgpcert_t *cert)
-{
-       if (cert != NULL)
-       {
-               free(cert->certificate.ptr);
-               free(cert);
-       }
-}
-
-/*
- *  list all PGP end certificates in a chained list
- */
-void
-list_pgp_end_certs(bool utc)
-{
-   pgpcert_t *cert = pgpcerts;
-   time_t now;
-
-       /* determine the current time */
-       time(&now);
-
-       if (cert != NULL)
-       {
-               whack_log(RC_COMMENT, " ");
-               whack_log(RC_COMMENT, "List of PGP End certificates:");
-               whack_log(RC_COMMENT, " ");
-       }
-
-       while (cert != NULL)
-       {
-               unsigned keysize;
-               char buf[BUF_LEN];
-               cert_t c;
-
-               c.type = CERT_PGP;
-               c.u.pgp = cert;
-
-               whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
-               datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN);
-               whack_log(RC_COMMENT, "       fingerprint:  %s", buf);
-               form_keyid(cert->publicExponent, cert->modulus, buf, &keysize);
-               whack_log(RC_COMMENT, "       pubkey:   %4d RSA Key %s%s", 8*keysize, buf,
-                               (has_private_key(c))? ", has private key" : "");
-               whack_log(RC_COMMENT, "       created:  %T", &cert->created, utc);
-               whack_log(RC_COMMENT, "       until:    %T %s", &cert->until, utc,
-                               check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
-               cert = cert->next;
-       }
-}
-
diff --git a/src/pluto/pgp.h b/src/pluto/pgp.h
deleted file mode 100644 (file)
index 4519022..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Support of OpenPGP certificates
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#ifndef _PGP_H
-#define _PGP_H
-
-#include <crypto/hashers/hasher.h>
-
-#include "pkcs1.h"
-
-/*
- * Length of PGP V3 fingerprint
- */
-#define PGP_FINGERPRINT_SIZE    HASH_SIZE_MD5
-
-typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
-
-/* access structure for an OpenPGP certificate */
-
-typedef struct pgpcert pgpcert_t;
-
-struct pgpcert {
-  pgpcert_t         *next;
-  time_t            installed;
-  int               count;
-  chunk_t           certificate;
-  time_t            created;
-  time_t            until;
-  enum pubkey_alg   pubkeyAlg;
-  chunk_t           modulus;
-  chunk_t           publicExponent;
-  fingerprint_t     fingerprint;
-};
-
-extern const pgpcert_t empty_pgpcert;
-extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key);
-extern void share_pgpcert(pgpcert_t *cert);
-extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
-extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
-extern void list_pgp_end_certs(bool utc);
-extern void release_pgpcert(pgpcert_t *cert);
-extern void free_pgpcert(pgpcert_t *cert);
-
-#endif /* _PGP_H */
diff --git a/src/pluto/pgpcert.c b/src/pluto/pgpcert.c
new file mode 100644 (file)
index 0000000..bfa0482
--- /dev/null
@@ -0,0 +1,502 @@
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <freeswan.h>
+
+#include <library.h>
+#include <pgp/pgp.h>
+#include <crypto/hashers/hasher.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "mp_defs.h"
+#include "log.h"
+#include "id.h"
+#include "pgpcert.h"
+#include "certs.h"
+#include "whack.h"
+#include "keys.h"
+
+/*
+ * chained list of OpenPGP end certificates
+ */
+static pgpcert_t *pgpcerts   = NULL;
+
+/*
+ * OpenPGP packet tags defined in section 4.3 of RFC 2440
+ */
+#define PGP_PKT_RESERVED                 0
+#define PGP_PKT_PUBKEY_ENC_SESSION_KEY   1
+#define PGP_PKT_SIGNATURE                2
+#define PGP_PKT_SYMKEY_ENC_SESSION_KEY   3
+#define PGP_PKT_ONE_PASS_SIGNATURE_PKT   4
+#define PGP_PKT_SECRET_KEY               5
+#define PGP_PKT_PUBLIC_KEY               6
+#define PGP_PKT_SECRET_SUBKEY            7
+#define PGP_PKT_COMPRESSED_DATA          8
+#define PGP_PKT_SYMKEY_ENC_DATA          9
+#define PGP_PKT_MARKER                  10
+#define PGP_PKT_LITERAL_DATA            11
+#define PGP_PKT_TRUST                   12
+#define PGP_PKT_USER_ID                 13
+#define PGP_PKT_PUBLIC_SUBKEY           14
+#define PGP_PKT_ROOF                    15
+
+static const char *const pgp_packet_type_name[] = {
+       "Reserved",
+       "Public-Key Encrypted Session Key Packet",
+       "Signature Packet",
+       "Symmetric-Key Encrypted Session Key Packet",
+       "One-Pass Signature Packet",
+       "Secret Key Packet",
+       "Public Key Packet",
+       "Secret Subkey Packet",
+       "Compressed Data Packet",
+       "Symmetrically Encrypted Data Packet",
+       "Marker Packet",
+       "Literal Data Packet",
+       "Trust Packet",
+       "User ID Packet",
+       "Public Subkey Packet"
+};
+
+/*
+ * OpenPGP public key algorithms defined in section 9.1 of RFC 2440
+ */
+#define PGP_PUBKEY_ALG_RSA               1
+#define PGP_PUBKEY_ALG_RSA_ENC_ONLY      2
+#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY     3
+#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16
+#define PGP_PUBKEY_ALG_DSA              17
+#define PGP_PUBKEY_ALG_ECC              18
+#define PGP_PUBKEY_ALG_ECDSA            19
+#define PGP_PUBKEY_ALG_ELGAMAL          20
+
+/*
+ * Size of PGP Key ID
+ */
+#define PGP_KEYID_SIZE          8
+
+const pgpcert_t empty_pgpcert = {
+         NULL     , /* *next */
+                       0  , /* installed */
+                       0  , /* count */
+       { NULL, 0 }, /* certificate */
+                       0  , /* created */
+                       0  , /* until */
+         NULL     , /* public key */
+         NULL       /* fingerprint */
+};
+
+
+/*
+ * extracts the length of a PGP packet
+ */
+static size_t pgp_old_packet_length(chunk_t *blob)
+{
+       /* bits 0 and 1 define the packet length type */
+       int len_type = 0x03 & *blob->ptr++;
+
+       blob->len--;
+
+       /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
+       return pgp_length(blob, (len_type == 0)? 1: len_type << 1);
+}
+
+/*
+ * extracts PGP packet version (V3 or V4)
+ */
+static u_char pgp_version(chunk_t *blob)
+{
+       u_char version = *blob->ptr++;
+       blob->len--;
+       DBG(DBG_PARSING,
+               DBG_log("L3 - version:");
+               DBG_log("  V%d", version)
+       )
+       return version;
+}
+
+/*
+ * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
+ */
+static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
+{
+       u_char version = pgp_version(packet);
+       public_key_t *key;
+
+       if (version < 3 || version > 4)
+       {
+               plog("PGP packet version V%d not supported", version);
+               return FALSE;
+       }
+
+       /* creation date - 4 bytes */
+       cert->created = (time_t)pgp_length(packet, 4);
+       DBG(DBG_PARSING,
+               DBG_log("L3 - created:");
+               DBG_log("  %T", &cert->created, TRUE)
+       )
+
+       if (version == 3)
+       {
+               /* validity in days - 2 bytes */
+               cert->until   = (time_t)pgp_length(packet, 2);
+
+               /* validity of 0 days means that the key never expires */
+               if (cert->until > 0)
+               {
+                       cert->until = cert->created + 24*3600*cert->until;
+               }
+               DBG(DBG_PARSING,
+                       DBG_log("L3 - until:");
+                       DBG_log("  %T", &cert->until, TRUE);
+               )
+       }
+
+       /* public key algorithm - 1 byte */
+       DBG(DBG_PARSING,
+               DBG_log("L3 - public key algorithm:")
+       )
+
+       switch (pgp_length(packet, 1))
+       {
+       case PGP_PUBKEY_ALG_RSA:
+       case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
+               DBG(DBG_PARSING,
+                       DBG_log("  RSA")
+               )
+               key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
+                                                                                        BUILD_BLOB_PGP, *packet,
+                                                                                        BUILD_END);
+               if (key == NULL)
+               {
+                       return FALSE;
+               }
+               cert->public_key = key;
+
+               if (version == 3)
+               {
+                       cert->fingerprint = key->get_id(key, ID_KEY_ID);
+                       if (cert->fingerprint == NULL)
+                       {
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       plog("  computation of V4 key ID not implemented yet");
+               }
+               break;
+       case PGP_PUBKEY_ALG_DSA:
+               DBG(DBG_PARSING,
+                       DBG_log("  DSA")
+               )
+               plog("  DSA public keys not supported");
+               return FALSE;
+        default:
+               DBG(DBG_PARSING,
+                       DBG_log("  other")
+               )
+               plog(" exotic not RSA public keys not supported");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/*
+ * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
+ */
+static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
+{
+       time_t created;
+       chunk_t keyid;
+       u_char  sig_type;
+       u_char version = pgp_version(packet);
+
+       /* we parse only V3 signature packets */
+       if (version != 3)
+               return TRUE;
+
+       /* size byte must have the value 5 */
+       if (pgp_length(packet, 1) != 5)
+       {
+               plog(" size must be 5");
+               return FALSE;
+       }
+
+       /* signature type - 1 byte */
+       sig_type = (u_char)pgp_length(packet, 1);
+       DBG(DBG_PARSING,
+               DBG_log("L3 - signature type:  0x%2x", sig_type)
+       )
+
+       /* creation date - 4 bytes */
+       created = (time_t)pgp_length(packet, 4);
+       DBG(DBG_PARSING,
+               DBG_log("L3 - created:");
+               DBG_log("  %T", &cert->created, TRUE)
+       )
+
+       /* key ID of signer - 8 bytes */
+       keyid.ptr = packet->ptr;
+       keyid.len = PGP_KEYID_SIZE;
+       DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid);
+
+   return TRUE;
+}
+
+bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key)
+{
+       DBG(DBG_PARSING,
+               DBG_log("L0 - PGP file:")
+       )
+       DBG_cond_dump_chunk(DBG_RAW, "", blob);
+
+       if (cert != NULL)
+       {
+               /* parse a PGP certificate file */
+               cert->certificate = blob;
+               time(&cert->installed);
+       }
+       else if (key == NULL)
+       {
+               /* should not occur, nothing to parse */
+               return FALSE;
+       }
+
+       while (blob.len > 0)
+       {
+               chunk_t packet = chunk_empty;
+               u_char packet_tag = *blob.ptr;
+
+               DBG(DBG_PARSING,
+                       DBG_log("L1 - PGP packet:  tag= 0x%2x", packet_tag)
+               )
+
+               /* bit 7 must be set */
+               if (!(packet_tag & 0x80))
+               {
+                       plog("  incorrect Packet Tag");
+                       return FALSE;
+               }
+
+               /* bit 6 set defines new packet format */
+               if (packet_tag & 0x40)
+               {
+                       plog("  new PGP packet format not supported");
+                       return FALSE;
+               }
+               else
+               {
+                       int packet_type = (packet_tag & 0x3C) >> 2;
+
+                       packet.len = pgp_old_packet_length(&blob);
+                       packet.ptr = blob.ptr;
+                       blob.ptr += packet.len;
+                       blob.len -= packet.len;
+                       DBG(DBG_PARSING,
+                               DBG_log("  %s (%d), old format, %d bytes",
+                                       (packet_type < PGP_PKT_ROOF) ?
+                                       pgp_packet_type_name[packet_type] :
+                                       "Undefined Packet Type", packet_type, (int)packet.len);
+                               DBG_log("L2 - body:")
+                       )
+                       DBG_cond_dump_chunk(DBG_RAW, "", packet);
+
+                       if (cert != NULL)
+                       {
+                               /* parse a PGP certificate */
+                               switch (packet_type)
+                               {
+                               case PGP_PKT_PUBLIC_KEY:
+                                       if (!parse_pgp_pubkey_packet(&packet, cert))
+                                       {
+                                               return FALSE;
+                                       }
+                                       break;
+                               case PGP_PKT_SIGNATURE:
+                                       if (!parse_pgp_signature_packet(&packet, cert))
+                                       {
+                                               return FALSE;
+                                       }
+                                       break;
+                               case PGP_PKT_USER_ID:
+                                       DBG(DBG_PARSING,
+                                               DBG_log("L3 - user ID:");
+                                               DBG_log("  '%.*s'", (int)packet.len, packet.ptr)
+                                       )
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               /* parse a PGP private key file */
+                               switch (packet_type)
+                               {
+                               case PGP_PKT_SECRET_KEY:
+                                       *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+                                                                                         BUILD_BLOB_PGP, packet,
+                                                                                         BUILD_END);
+                                       break;
+                               default:
+                                       break;
+                               }
+                               if (*key == NULL)
+                               {
+                                       return FALSE;
+                               }
+
+                       }
+               }
+       }
+       return TRUE;
+}
+
+/*
+ *  compare two OpenPGP certificates
+ */
+static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b)
+{
+       return a->certificate.len == b->certificate.len &&
+               memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
+}
+
+/*
+ * for each link pointing to the certificate increase the count by one
+ */
+void share_pgpcert(pgpcert_t *cert)
+{
+       if (cert != NULL)
+       {
+               cert->count++;
+       }
+}
+
+/*
+ * select the OpenPGP keyid as ID
+ */
+void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
+{
+       end_id->kind = ID_KEY_ID;
+       end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
+       end_id->name = chunk_clone(end_id->name);
+}
+
+/*
+ *  add an OpenPGP user/host certificate to the chained list
+ */
+pgpcert_t* add_pgpcert(pgpcert_t *cert)
+{
+       pgpcert_t *c = pgpcerts;
+
+       while (c != NULL)
+       {
+               if (same_pgpcert(c, cert)) /* already in chain, free cert */
+               {
+                       free_pgpcert(cert);
+                       return c;
+               }
+               c = c->next;
+       }
+
+       /* insert new cert at the root of the chain */
+       cert->next = pgpcerts;
+       pgpcerts = cert;
+       DBG(DBG_CONTROL | DBG_PARSING,
+               DBG_log("  pgp cert inserted")
+       )
+       return cert;
+}
+
+/*  release of a certificate decreases the count by one
+ "  the certificate is freed when the counter reaches zero
+ */
+void release_pgpcert(pgpcert_t *cert)
+{
+       if (cert != NULL && --cert->count == 0)
+       {
+               pgpcert_t **pp = &pgpcerts;
+               while (*pp != cert)
+               {
+                       pp = &(*pp)->next;
+               }
+               *pp = cert->next;
+               free_pgpcert(cert);
+       }
+}
+
+/*
+ *  free a PGP certificate
+ */
+void free_pgpcert(pgpcert_t *cert)
+{
+       if (cert != NULL)
+       {
+               DESTROY_IF(cert->public_key);
+               DESTROY_IF(cert->fingerprint);
+               free(cert->certificate.ptr);
+               free(cert);
+       }
+}
+
+/*
+ *  list all PGP end certificates in a chained list
+ */
+void list_pgp_end_certs(bool utc)
+{
+   pgpcert_t *cert = pgpcerts;
+   time_t now;
+
+       /* determine the current time */
+       time(&now);
+
+       if (cert != NULL)
+       {
+               whack_log(RC_COMMENT, " ");
+               whack_log(RC_COMMENT, "List of PGP End certificates:");
+               whack_log(RC_COMMENT, " ");
+       }
+
+       while (cert != NULL)
+       {
+               public_key_t *key = cert->public_key;
+               cert_t c;
+
+               c.type = CERT_PGP;
+               c.u.pgp = cert;
+
+               whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
+               whack_log(RC_COMMENT, "       fingerprint:  %Y", cert->fingerprint);
+               whack_log(RC_COMMENT, "       pubkey:   %N %4d bits%s",
+                               key_type_names, key->get_type(key),
+                               key->get_keysize(key) * BITS_PER_BYTE,                          
+                               has_private_key(c)? ", has private key" : "");
+               whack_log(RC_COMMENT, "       keyid:    %Y",
+                               key->get_id(key, ID_PUBKEY_INFO_SHA1));
+               whack_log(RC_COMMENT, "       created:  %T", &cert->created, utc);
+               whack_log(RC_COMMENT, "       until:    %T %s", &cert->until, utc,
+                               check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+               cert = cert->next;
+       }
+}
+
diff --git a/src/pluto/pgpcert.h b/src/pluto/pgpcert.h
new file mode 100644 (file)
index 0000000..9d8912e
--- /dev/null
@@ -0,0 +1,55 @@
+/* Support of OpenPGP certificates
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _PGPCERT_H
+#define _PGPCERT_H
+
+#include <crypto/hashers/hasher.h>
+#include <credentials/keys/private_key.h>
+#include <credentials/keys/public_key.h>
+
+/*
+ * Length of PGP V3 fingerprint
+ */
+#define PGP_FINGERPRINT_SIZE    HASH_SIZE_MD5
+
+typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
+
+/* access structure for an OpenPGP certificate */
+
+typedef struct pgpcert pgpcert_t;
+
+struct pgpcert {
+       pgpcert_t        *next;
+       time_t           installed;
+       int              count;
+       chunk_t          certificate;
+       time_t           created;
+       time_t           until;
+       public_key_t     *public_key;
+       identification_t *fingerprint;
+};
+
+extern const pgpcert_t empty_pgpcert;
+extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key);
+extern void share_pgpcert(pgpcert_t *cert);
+extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
+extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
+extern void list_pgp_end_certs(bool utc);
+extern void release_pgpcert(pgpcert_t *cert);
+extern void free_pgpcert(pgpcert_t *cert);
+
+#endif /* _PGPCERT_H */
diff --git a/src/pluto/pkcs1.c b/src/pluto/pkcs1.c
deleted file mode 100644 (file)
index 51c90a2..0000000
+++ /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 (file)
index 4aaa8c4..0000000
+++ /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 */
index c793d28..ab4362c 100644 (file)
@@ -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;
index 09ffd65..028822d 100644 (file)
@@ -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);
 
index d40a4e2..01f721e 100644 (file)
@@ -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");
+                       }
                }
        }
 }
index 9a5714b..ca926a9 100644 (file)
@@ -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,
-                                      &nb