pluto and scepclient use private and public key plugins of libstrongswan

This commit is contained in:
Andreas Steffen
2009-06-09 11:03:32 +02:00
committed by Martin Willi
parent b00fbdb55a
commit 8b799d55ce
46 changed files with 1803 additions and 2597 deletions
+2 -1
View File
@@ -41,8 +41,9 @@ credentials/certificates/ac.h \
credentials/certificates/crl.h credentials/certificates/crl.c \ credentials/certificates/crl.h credentials/certificates/crl.c \
credentials/certificates/ocsp_request.h \ credentials/certificates/ocsp_request.h \
credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ 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 \ 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.h utils.c \
utils/host.c utils/host.h \ utils/host.c utils/host.h \
utils/identification.c utils/identification.h \ utils/identification.c utils/identification.h \
+37 -2
View File
@@ -255,7 +255,7 @@ chunk_t asn1_build_known_oid(int n)
/* /*
* Defined in header. * Defined in header.
*/ */
u_int asn1_length(chunk_t *blob) size_t asn1_length(chunk_t *blob)
{ {
u_char n; u_char n;
size_t len; 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) chunk_t asn1_bitstring(const char *mode, chunk_t content)
{ {
@@ -691,6 +691,41 @@ chunk_t asn1_bitstring(const char *mode, chunk_t content)
return object; return object;
} }
/**
* 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. * Build an ASN.1 object from a variable number of individual chunks.
* Depending on the mode, chunks either are moved ('m') or copied ('c'). * Depending on the mode, chunks either are moved ('m') or copied ('c').
+10 -1
View File
@@ -120,7 +120,7 @@ chunk_t asn1_build_known_oid(int n);
* @param blob pointer to an ASN.1 coded blob * @param blob pointer to an ASN.1 coded blob
* @return length of ASN.1 object * @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 * Parses an ASN.1 algorithmIdentifier object
@@ -227,6 +227,15 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content);
*/ */
chunk_t asn1_bitstring(const char *mode, 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 * Build an ASN.1 object from a variable number of individual chunks
* *
+2
View File
@@ -20,6 +20,8 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_AGENT_SOCKET", "BUILD_AGENT_SOCKET",
"BUILD_BLOB_ASN1_DER", "BUILD_BLOB_ASN1_DER",
"BUILD_BLOB_ASN1_PEM", "BUILD_BLOB_ASN1_PEM",
"BUILD_BLOB_PGP",
"BUILD_BLOB_RFC_3110",
"BUILD_KEY_SIZE", "BUILD_KEY_SIZE",
"BUILD_SIGNING_KEY", "BUILD_SIGNING_KEY",
"BUILD_SIGNING_CERT", "BUILD_SIGNING_CERT",
+7 -3
View File
@@ -38,14 +38,18 @@ typedef builder_t* (*builder_constructor_t)(int subtype);
* Parts to build credentials from. * Parts to build credentials from.
*/ */
enum builder_part_t { 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, BUILD_FROM_FILE,
/** unix socket of a ssh/pgp agent, char* */ /** unix socket of a ssh/pgp agent, char* */
BUILD_AGENT_SOCKET, BUILD_AGENT_SOCKET,
/** DER encoded ASN1 blob, chunk_t */ /** DER encoded ASN.1 blob, chunk_t */
BUILD_BLOB_ASN1_DER, BUILD_BLOB_ASN1_DER,
/** PEM encoded ASN1 blob, null terminated char* */ /** PEM encoded ASN.1 blob, null terminated char* */
BUILD_BLOB_ASN1_PEM, 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 */ /** key size in bits, as used for key generation, u_int */
BUILD_KEY_SIZE, BUILD_KEY_SIZE,
/** private key to use for signing, private_key_t* */ /** private key to use for signing, private_key_t* */
@@ -156,6 +156,8 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
case BUILD_END: case BUILD_END:
break; break;
case BUILD_BLOB_ASN1_DER: case BUILD_BLOB_ASN1_DER:
case BUILD_BLOB_PGP:
case BUILD_BLOB_RFC_3110:
case BUILD_SERIAL: case BUILD_SERIAL:
builder->add(builder, part, va_arg(args, chunk_t)); builder->add(builder, part, va_arg(args, chunk_t));
continue; continue;
@@ -79,6 +79,14 @@ struct private_key_t {
*/ */
public_key_t* (*get_public_key)(private_key_t *this); 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. * Check if a private key belongs to a public key.
* *
@@ -15,13 +15,15 @@
#include "public_key.h" #include "public_key.h"
ENUM(key_type_names, KEY_RSA, KEY_ECDSA, ENUM(key_type_names, KEY_RSA, KEY_DSA,
"RSA", "RSA",
"ECDSA" "ECDSA",
"DSA"
); );
ENUM(signature_scheme_names, SIGN_DEFAULT, SIGN_ECDSA_521, ENUM(signature_scheme_names, SIGN_DEFAULT, SIGN_ECDSA_521,
"DEFAULT", "DEFAULT",
"RSA_EMSA_PKCS1_NULL",
"RSA_EMSA_PKCS1_MD5", "RSA_EMSA_PKCS1_MD5",
"RSA_EMSA_PKCS1_SHA1", "RSA_EMSA_PKCS1_SHA1",
"RSA_EMSA_PKCS1_SHA256", "RSA_EMSA_PKCS1_SHA256",
+33 -19
View File
@@ -34,12 +34,14 @@ typedef enum signature_scheme_t signature_scheme_t;
*/ */
enum key_type_t { enum key_type_t {
/** key type wildcard */ /** key type wildcard */
KEY_ANY, KEY_ANY = 0,
/** RSA crypto system as in PKCS#1 */ /** RSA crypto system as in PKCS#1 */
KEY_RSA, KEY_RSA = 1,
/** ECDSA as in ANSI X9.62 */ /** ECDSA as in ANSI X9.62 */
KEY_ECDSA, KEY_ECDSA = 2,
/** DSS, ElGamal, ... */ /** DSA */
KEY_DSA = 3,
/** ElGamal, ... */
}; };
/** /**
@@ -50,29 +52,33 @@ extern enum_name_t *key_type_names;
/** /**
* Signature scheme for signature creation * Signature scheme for signature creation
* *
* EMSA-PKCS1 signatures are from the PKCS#1 standard. They include * EMSA-PKCS1 signatures are defined in PKCS#1 standard.
* the ASN1-OID of the used hash algorithm. * 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 { enum signature_scheme_t {
/** default scheme of that underlying crypto system */ /** Default scheme of the underlying crypto system */
SIGN_DEFAULT, 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, 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, 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, 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, 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, SIGN_RSA_EMSA_PKCS1_SHA512,
/** ECDSA using SHA-1 as hash. */ /** ECDSA with SHA-1 */
SIGN_ECDSA_WITH_SHA1, 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, 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, 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, SIGN_ECDSA_521,
}; };
@@ -107,12 +113,20 @@ struct public_key_t {
/** /**
* Encrypt a chunk of data. * Encrypt a chunk of data.
* *
* @param crypto chunk containing plaintext data * @param plain chunk containing plaintext data
* @param plain where to allocate encrypted data * @param crypto where to allocate encrypted data
* @return TRUE if data successfully encrypted * @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. * Get the strength of the key in bytes.
* *
@@ -1,11 +1,6 @@
/** /*
* @file rsakey.h * Copyright (C) 2002-2009 Andreas Steffen
* @brief Functions for RSA key generation *
*/
/*
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -18,12 +13,40 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. * for more details.
*/ */
#include "pgp.h"
#ifndef RSAKEY_H_ ENUM(pgp_sym_alg_names, PGP_SYM_ALG_PLAIN, PGP_SYM_ALG_TWOFISH,
#define RSAKEY_H_ "PLAINTEXT",
"IDEA",
"3DES",
"CAST5",
"BLOWFISH",
"SAFER",
"DES",
"AES_128",
"AES_192",
"AES_256",
"TWOFISH"
);
#include "../pluto/pkcs1.h" /*
* Defined in header.
*/
size_t pgp_length(chunk_t *blob, size_t len)
{
size_t size = 0;
extern err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key); if (len > blob->len)
{
return PGP_INVALID_LENGTH;
}
blob->len -= len;
while (len-- > 0)
{
size = 256*size + *blob->ptr++;
}
return size;
}
#endif // RSAKEY_H_
+64
View File
@@ -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_ @}*/
@@ -26,6 +26,7 @@
#include <asn1/oid.h> #include <asn1/oid.h>
#include <asn1/asn1.h> #include <asn1/asn1.h>
#include <asn1/asn1_parser.h> #include <asn1/asn1_parser.h>
#include <pgp/pgp.h>
/** /**
* Public exponent to use for key generation. * 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, extern bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e,
identification_t **keyid_info); identification_t **keyid,
gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e); 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 * 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, hash_algorithm_t hash_algorithm,
chunk_t data, chunk_t *signature) chunk_t data, chunk_t *signature)
{ {
hasher_t *hasher; chunk_t digestInfo = chunk_empty;
chunk_t em, digestInfo, hash; chunk_t em;
int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
if (hash_oid == OID_UNKNOWN)
{
return FALSE;
}
/* get hasher */ if (hash_algorithm != HASH_UNKNOWN)
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
if (hasher == NULL)
{ {
return FALSE; hasher_t *hasher;
chunk_t hash;
int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
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);
data = digestInfo;
} }
/* build hash */
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 chunk to rsa-decrypt: /* build chunk to rsa-decrypt:
* EM = 0x00 || 0x01 || PS || 0x00 || T. * 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 */ /* set magic bytes */
*(em.ptr) = 0x00; *(em.ptr) = 0x00;
*(em.ptr+1) = 0x01; *(em.ptr+1) = 0x01;
*(em.ptr + em.len - digestInfo.len - 1) = 0x00; *(em.ptr + em.len - data.len - 1) = 0x00;
/* set DER-encoded hash */ /* 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 */ /* build signature */
*signature = rsasp1(this, em); *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) 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, static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme,
chunk_t data, chunk_t *signature) chunk_t data, chunk_t *signature)
{ {
switch (scheme) switch (scheme)
{ {
case SIGN_RSA_EMSA_PKCS1_NULL:
return build_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
case SIGN_DEFAULT: case SIGN_DEFAULT:
/* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1: case SIGN_RSA_EMSA_PKCS1_SHA1:
return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256: 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, static bool decrypt(private_gmp_rsa_private_key_t *this,
chunk_t crypto, chunk_t *plain) 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) 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, static identification_t* get_id(private_gmp_rsa_private_key_t *this,
id_type_t type) 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) 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; 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); n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value);
if (n.ptr == NULL) if (n.ptr == NULL)
{ /* if we have zero in "value", gmp returns NULL */ { /* if we have zero in "value", gmp returns NULL */
n.len = 0; 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) 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. /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
* We actually require more (for security). * We actually require more (for security).
*/ */
if (this->k < 512/8) if (this->k < 512 / BITS_PER_BYTE)
{ {
DBG1("key shorter than 512 bits"); DBG1("key shorter than 512 bits");
return FAILED; return FAILED;
} }
/* we picked a max modulus size to simplify buffer allocation */ /* 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"); DBG1("key larger than 8192 bits");
return FAILED; 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); 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.get_type = (key_type_t (*) (private_key_t*))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.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign;
this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt; this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt;
this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize; this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize;
this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id; 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 *this))get_public_key; this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key;
this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to; this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals;
this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding; this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to;
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref; this->public.interface.get_encoding = (chunk_t (*) (private_key_t*))get_encoding;
this->public.interface.destroy = (void (*)(private_key_t *this))destroy; 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 = NULL;
this->keyid_info = 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; mpz_t m, q1, t;
private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); 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 */ /* Get values of primes p and q */
if (compute_prime(this, key_size/2, &p) != SUCCESS) 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 * 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; asn1_parser_t *parser;
chunk_t object; chunk_t object;
@@ -706,6 +750,7 @@ static gmp_rsa_private_key_t *load(chunk_t blob)
case PRIV_KEY_VERSION: case PRIV_KEY_VERSION:
if (object.len > 0 && *object.ptr != 0) if (object.len > 0 && *object.ptr != 0)
{ {
DBG1("PKCS#1 private key format is not version 1");
goto end; goto end;
} }
break; break;
@@ -755,7 +800,6 @@ end:
destroy(this); destroy(this);
return NULL; return NULL;
} }
if (check(this) != SUCCESS) if (check(this) != SUCCESS)
{ {
destroy(this); destroy(this);
@@ -764,6 +808,125 @@ end:
return &this->public; 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; typedef struct private_builder_t private_builder_t;
/** /**
* Builder implementation for key loading/generation * Builder implementation for key loading/generation
@@ -802,7 +965,15 @@ static void add(private_builder_t *this, builder_part_t part, ...)
{ {
va_start(args, part); va_start(args, part);
chunk = va_arg(args, chunk_t); 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); va_end(args);
return; return;
} }
@@ -28,11 +28,7 @@
#include <asn1/asn1_parser.h> #include <asn1/asn1_parser.h>
#include <asn1/pem.h> #include <asn1/pem.h>
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include <pgp/pgp.h>
/**
* defined in gmp_rsa_private_key.c
*/
extern chunk_t gmp_mpz_to_asn1(const mpz_t value);
typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t; typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
@@ -76,6 +72,12 @@ struct private_gmp_rsa_public_key_t {
refcount_t ref; refcount_t ref;
}; };
/**
* 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. * RSAEP algorithm specified in PKCS#1.
*/ */
@@ -189,13 +191,24 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
goto end; 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; asn1_parser_t *parser;
chunk_t object; chunk_t object;
int objectID; int objectID;
hash_algorithm_t hash_algorithm = HASH_UNKNOWN; hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
DBG2("signature verification:");
parser = asn1_parser_create(digestInfoObjects, em); parser = asn1_parser_create(digestInfoObjects, em);
while (parser->iterate(parser, &objectID, &object)) 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); parser->get_level(parser)+1, NULL);
hash_algorithm = hasher_algorithm_from_oid(hash_oid); hash_algorithm = hasher_algorithm_from_oid(hash_oid);
if (hash_algorithm == HASH_UNKNOWN || if (hash_algorithm == HASH_UNKNOWN || hash_algorithm != algorithm)
(algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
{ {
DBG1("expected hash algorithm %N, but found %N (OID: %#B)", DBG1("expected hash algorithm %N, but found %N (OID: %#B)",
hash_algorithm_names, algorithm, hash_algorithm_names, algorithm,
@@ -287,7 +299,8 @@ static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme
{ {
switch (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); return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
case SIGN_RSA_EMSA_PKCS1_MD5: case SIGN_RSA_EMSA_PKCS1_MD5:
return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature); return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
@@ -315,6 +328,34 @@ static bool encrypt_(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t
return FALSE; return FALSE;
} }
/**
* 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. * Implementation of public_key_t.get_keysize.
*/ */
@@ -323,6 +364,34 @@ static size_t get_keysize(private_gmp_rsa_public_key_t *this)
return this->k; return this->k;
} }
/**
* 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. * Implementation of public_key_t.get_id.
*/ */
@@ -335,6 +404,8 @@ static identification_t *get_id(private_gmp_rsa_public_key_t *this,
return this->keyid_info; return this->keyid_info;
case ID_PUBKEY_SHA1: case ID_PUBKEY_SHA1:
return this->keyid; return this->keyid;
case ID_KEY_ID:
return gmp_rsa_build_pgp_v3_keyid(this->n, this->e);
default: default:
return NULL; 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); 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.get_type = (key_type_t (*) (public_key_t*))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.verify = (bool (*) (public_key_t*, signature_scheme_t, chunk_t, chunk_t))verify;
this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_; this->public.interface.encrypt = (bool (*) (public_key_t*, chunk_t, chunk_t*))encrypt_;
this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize; this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals;
this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id; this->public.interface.get_keysize = (size_t (*) (public_key_t*))get_keysize;
this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding; this->public.interface.get_id = (identification_t* (*) (public_key_t*, id_type_t))get_id;
this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref; this->public.interface.get_encoding = (chunk_t(*) (public_key_t*))get_encoding;
this->public.interface.destroy = (void (*)(public_key_t *this))destroy; 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 = NULL;
this->keyid_info = 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->n, n);
mpz_init_set(this->e, e); 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, if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info)) &this->keyid, &this->keyid_info))
{ {
@@ -467,9 +539,9 @@ static const asn1Object_t pubkeyObjects[] = {
#define PUB_KEY_EXPONENT 2 #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; asn1_parser_t *parser;
chunk_t object; chunk_t object;
@@ -505,7 +577,7 @@ static gmp_rsa_public_key_t *load(chunk_t blob)
return NULL; 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, if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info)) &this->keyid, &this->keyid_info))
@@ -516,6 +588,125 @@ static gmp_rsa_public_key_t *load(chunk_t blob)
return &this->public; 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))
{
destroy(this);
return NULL;
}
return &this->public;
end:
free(blob.ptr);
destroy(this);
return NULL;
}
typedef struct private_builder_t private_builder_t; typedef struct private_builder_t private_builder_t;
/** /**
* Builder implementation for key loading * Builder implementation for key loading
@@ -554,7 +745,23 @@ static void add(private_builder_t *this, builder_part_t part, ...)
{ {
va_start(args, part); va_start(args, part);
chunk = va_arg(args, chunk_t); 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); va_end(args);
return; return;
} }
@@ -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) 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, static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t scheme,
chunk_t data, chunk_t *signature) 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) switch (scheme)
{ {
case SIGN_DEFAULT: case SIGN_DEFAULT:
/* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1: case SIGN_RSA_EMSA_PKCS1_SHA1:
return build_emsa_pkcs1_signature(this, NID_sha1, data, signature); return build_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256: 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, static bool decrypt(private_openssl_rsa_private_key_t *this,
chunk_t crypto, chunk_t *plain) 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) 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, static identification_t* get_id(private_openssl_rsa_private_key_t *this,
id_type_t type) 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) 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) 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) 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); 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.get_type = (key_type_t (*) (private_key_t*))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.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign;
this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt; this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt;
this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize; this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize;
this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id; 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 *this))get_public_key; this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key;
this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to; this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals;
this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding; this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to;
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref; this->public.interface.get_encoding = (chunk_t(*) (private_key_t*))get_encoding;
this->public.interface.destroy = (void (*)(private_key_t *this))destroy; 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->engine = FALSE;
this->keyid = NULL; this->keyid = NULL;
@@ -124,7 +124,6 @@ static bool verify(private_openssl_rsa_public_key_t *this, signature_scheme_t sc
switch (scheme) switch (scheme)
{ {
case SIGN_DEFAULT: case SIGN_DEFAULT:
/* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1: case SIGN_RSA_EMSA_PKCS1_SHA1:
return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature); return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256: case SIGN_RSA_EMSA_PKCS1_SHA256:
@@ -151,6 +150,34 @@ static bool encrypt_(private_openssl_rsa_public_key_t *this, chunk_t crypto, chu
return FALSE; return FALSE;
} }
/**
* 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. * Implementation of public_key_t.get_keysize.
*/ */
@@ -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.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.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.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_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_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_encoding = (chunk_t(*)(public_key_t*))get_encoding;
+14 -15
View File
@@ -730,7 +730,6 @@ static bool parse_certificate(private_x509_cert_t *this)
KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
if (this->public_key == NULL) if (this->public_key == NULL)
{ {
DBG1("could not create public key");
goto end; goto end;
} }
break; break;
@@ -1123,19 +1122,19 @@ static private_x509_cert_t* create_empty(void)
{ {
private_x509_cert_t *this = malloc_thing(private_x509_cert_t); 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_type = (certificate_type_t (*) (certificate_t*))get_type;
this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject; this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject;
this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; 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 *subject))has_subject; 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 *issuer))has_issuer; this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_issuer;
this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by; 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 *this))get_public_key; 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 *when, time_t *, time_t*))get_validity; 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.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.get_encoding = (chunk_t (*) (certificate_t*))get_encoding;
this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals; this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals;
this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref;
this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy; 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_flags = (x509_flag_t (*)(x509_t*))get_flags;
this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial; this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial;
this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier; 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", this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2), 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), asn1_algorithmIdentifier(this->cert->algorithm),
issuer->get_encoding(issuer), issuer->get_encoding(issuer),
asn1_wrap(ASN1_SEQUENCE, "mm", asn1_wrap(ASN1_SEQUENCE, "mm",
+1 -2
View File
@@ -38,8 +38,7 @@ nat_traversal.c nat_traversal.h \
ocsp.c ocsp.h \ ocsp.c ocsp.h \
packet.c packet.h \ packet.c packet.h \
pem.c pem.h \ pem.c pem.h \
pgp.c pgp.h \ pgpcert.c pgpcert.h \
pkcs1.c pkcs1.h \
pkcs7.c pkcs7.h \ pkcs7.c pkcs7.h \
plutomain.c \ plutomain.c \
rcv_whack.c rcv_whack.h \ rcv_whack.c rcv_whack.h \
+2 -2
View File
@@ -783,8 +783,8 @@ bool verify_x509acert(x509acert_t *ac, bool strict)
DBG_log("issuer aacert found") DBG_log("issuer aacert found")
) )
if (!check_signature(ac->certificateInfo, ac->signature if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm,
, ac->algorithm, ac->algorithm, aacert)) aacert))
{ {
plog("attribute certificate signature is invalid"); plog("attribute certificate signature is invalid");
return FALSE; return FALSE;
+2 -2
View File
@@ -385,8 +385,8 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain)
} }
} }
if (!check_signature(cert->tbsCertificate, cert->signature if (!x509_check_signature(cert->tbsCertificate, cert->signature,
, cert->algorithm, cert->algorithm, authcert)) cert->algorithm, authcert))
{ {
plog("certificate signature is invalid"); plog("certificate signature is invalid");
unlock_authcert_list("trust_authcert_candidate"); unlock_authcert_list("trust_authcert_candidate");
+20 -16
View File
@@ -1,5 +1,7 @@
/* Certificate support for IKE authentication /* 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 * 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 * under the terms of the GNU General Public License as published by the
@@ -18,17 +20,15 @@
#include <freeswan.h> #include <freeswan.h>
#include "library.h"
#include "asn1/asn1.h" #include "asn1/asn1.h"
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h" #include "id.h"
#include "x509.h"
#include "pgp.h"
#include "pem.h" #include "pem.h"
#include "certs.h" #include "certs.h"
#include "pkcs1.h"
/** /**
* used for initializatin of certs * 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, private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
RSA_private_key_t *key) key_type_t type)
{ {
err_t ugh = NULL; private_key_t *key = NULL;
bool pgp = FALSE;
chunk_t blob = chunk_empty; chunk_t blob = chunk_empty;
bool pgp = FALSE;
char *path = concatenate_paths(PRIVATE_KEY_PATH, filename); 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 (pgp)
{ {
if (!parse_pgp(blob, NULL, key)) parse_pgp(blob, NULL, &key);
ugh = "syntax error in PGP private key file";
} }
else else
{ {
if (!pkcs1_parse_private_key(blob, key)) key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
ugh = "syntax error in PKCS#1 private key file"; BUILD_BLOB_ASN1_DER, blob, BUILD_END);
} }
if (key == NULL)
{
plog("syntax error in %s private key file", pgp ? "PGP":"PKCS#");
}
free(blob.ptr); free(blob.ptr);
} }
else else
ugh = "error loading RSA private key file"; {
plog("error loading RSA private key file");
return ugh; }
return key;
} }
/** /**
+10 -7
View File
@@ -1,5 +1,7 @@
/* Certificate support for IKE authentication /* 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 * 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 * under the terms of the GNU General Public License as published by the
@@ -15,9 +17,10 @@
#ifndef _CERTS_H #ifndef _CERTS_H
#define _CERTS_H #define _CERTS_H
#include "pkcs1.h" #include <credentials/keys/private_key.h>
#include "x509.h" #include "x509.h"
#include "pgp.h" #include "pgpcert.h"
/* path definitions for private keys, end certs, /* path definitions for private keys, end certs,
* cacerts, attribute certs and crls * cacerts, attribute certs and crls
@@ -59,11 +62,11 @@ extern const cert_t empty_cert;
*/ */
extern bool no_cr_send; extern bool no_cr_send;
extern err_t load_rsa_private_key(char* filename, prompt_pass_t *pass extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
, RSA_private_key_t *key); key_type_t type);
extern chunk_t get_mycert(cert_t cert); extern chunk_t get_mycert(cert_t cert);
extern bool load_coded_file(char *filename, prompt_pass_t *pass extern bool load_coded_file(char *filename, prompt_pass_t *pass,
, const char *type, chunk_t *blob, bool *pgp); const char *type, chunk_t *blob, bool *pgp);
extern bool load_cert(char *filename, const char *label, cert_t *cert); 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_host_cert(char *filename, cert_t *cert);
extern bool load_ca_cert(char *filename, cert_t *cert); extern bool load_ca_cert(char *filename, cert_t *cert);
+29 -25
View File
@@ -29,13 +29,15 @@
#include <freeswan.h> #include <freeswan.h>
#include "kameipsec.h" #include "kameipsec.h"
#include <credentials/keys/private_key.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "id.h" #include "id.h"
#include "x509.h" #include "x509.h"
#include "ca.h" #include "ca.h"
#include "crl.h" #include "crl.h"
#include "pgp.h" #include "pgpcert.h"
#include "certs.h" #include "certs.h"
#include "ac.h" #include "ac.h"
#include "smartcard.h" #include "smartcard.h"
@@ -2155,17 +2157,16 @@ check_key_recs(enum myid_state try_state
* If so, treat as a kind of failure. * If so, treat as a kind of failure.
*/ */
enum myid_state old_myid_state = myid_state; enum myid_state old_myid_state = myid_state;
const struct RSA_private_key *our_RSA_pri; private_key_t *private;
err_t ugh = NULL; err_t ugh = NULL;
myid_state = try_state; myid_state = try_state;
if (old_myid_state != myid_state if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED)
&& old_myid_state == MYID_SPECIFIED)
{ {
ugh = "%myid was specified while we were guessing"; ugh = "%myid was specified while we were guessing";
} }
else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL) else if ((private = get_private_key(c)) == NULL)
{ {
ugh = "we don't know our own RSA key"; ugh = "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"; ugh = "all our KEY RRs have the wrong public key";
if (kr->key->alg == PUBKEY_ALG_RSA 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! */ ugh = NULL; /* good! */
break; break;
@@ -2198,10 +2199,9 @@ check_key_recs(enum myid_state try_state
} }
#endif /* USE_KEYRR */ #endif /* USE_KEYRR */
static err_t static err_t check_txt_recs(enum myid_state try_state,
check_txt_recs(enum myid_state try_state const struct connection *c,
, const struct connection *c struct adns_continuation *ac)
, struct adns_continuation *ac)
{ {
/* Check if TXT lookup yielded good results. /* Check if TXT lookup yielded good results.
* Looking up based on our ID. Used if * 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. * If so, treat as a kind of failure.
*/ */
enum myid_state old_myid_state = myid_state; enum myid_state old_myid_state = myid_state;
const struct RSA_private_key *our_RSA_pri; private_key_t *private;
err_t ugh = NULL; err_t ugh = NULL;
myid_state = try_state; myid_state = try_state;
@@ -2221,7 +2221,7 @@ check_txt_recs(enum myid_state try_state
{ {
ugh = "%myid was specified while we were guessing"; ugh = "%myid was specified while we were guessing";
} }
else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL) else if ((private = get_private_key(c)) == NULL)
{ {
ugh = "we don't know our own RSA key"; ugh = "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"; ugh = "no TXT RR found for us";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) 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"; ugh = "all our TXT RRs have the wrong public key";
if (gwp->key->alg == PUBKEY_ALG_RSA if (pub_key->get_type(pub_key) == KEY_RSA &&
&& same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa)) private->belongs_to(private, pub_key))
{ {
ugh = NULL; /* good! */ ugh = NULL; /* good! */
break; break;
@@ -2249,7 +2251,9 @@ check_txt_recs(enum myid_state try_state
} }
} }
if (ugh != NULL) if (ugh != NULL)
{
myid_state = old_myid_state; myid_state = old_myid_state;
}
return ugh; return ugh;
} }
@@ -2513,13 +2517,13 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query. * a chance that we did the wrong query.
* If so, treat as a kind of failure. * 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 */ next_step = fos_his_client; /* normal situation */
passert(sr != NULL); passert(sr != NULL);
if (our_RSA_pri == NULL) if (private == NULL)
{ {
ugh = "we don't know our own RSA key"; ugh = "we don't know our own RSA key";
} }
@@ -2560,7 +2564,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
ugh = NULL; /* good! */ ugh = NULL; /* good! */
break; 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! */ ugh = NULL; /* good! */
break; break;
@@ -2579,11 +2583,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query. * a chance that we did the wrong query.
* If so, treat as a kind of failure. * 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 */ 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"; 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)); passert(same_id(&gwp->gw_id, &sr->this.id));
ugh = "TXT RR for us has wrong key"; ugh = "TXT RR for us has wrong key";
if (gwp->gw_key_present if (gwp->gw_key_present &&
&& same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa)) private->belongs_to(private, gwp->key->public_key))
{ {
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("initiate on demand found TXT with right public key at: %s" 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. * a chance that we did the wrong query.
* If so, treat as a kind of failure. * 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 */ next_step = fos_his_client; /* always */
if (our_RSA_pri == NULL) if (private == NULL)
{ {
ugh = "we don't know our own RSA key"; 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)"; ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)";
if (kr->key->alg == PUBKEY_ALG_RSA 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 */ /* do this only once a day */
if (!logged_txt_warning) 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 * We must at least be able to find our private key
.*/ .*/
if (d->spd.this.sc == NULL /* no smartcard */ 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; continue;
break; break;
+4 -4
View 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 */ /* check the issuer's signature of the crl */
valid_sig = check_signature(crl->tbsCertList, crl->signature valid_sig = x509_check_signature(crl->tbsCertList, crl->signature,
, crl->algorithm, crl->algorithm, issuer_cert); crl->algorithm, issuer_cert);
unlock_authcert_list("insert_crl"); unlock_authcert_list("insert_crl");
if (!valid_sig) 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 issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
, crl->authKeyID, AUTH_CA); , crl->authKeyID, AUTH_CA);
valid = check_signature(crl->tbsCertList, crl->signature valid = x509_check_signature(crl->tbsCertList, crl->signature,
, crl->algorithm, crl->algorithm, issuer_cert); crl->algorithm, issuer_cert);
unlock_authcert_list("verify_by_crl"); unlock_authcert_list("verify_by_crl");
+74 -31
View File
@@ -29,6 +29,9 @@
#include <freeswan.h> #include <freeswan.h>
#include <utils/identification.h>
#include <credentials/keys/public_key.h>
#include "constants.h" #include "constants.h"
#include "adns.h" /* needs <resolv.h> */ #include "adns.h" /* needs <resolv.h> */
#include "defs.h" #include "defs.h"
@@ -83,7 +86,9 @@ init_adns(void)
{ {
strcpy(adns_path_space, helper_bin_dir); strcpy(adns_path_space, helper_bin_dir);
if (n > 0 && adns_path_space[n -1] != '/') if (n > 0 && adns_path_space[n -1] != '/')
{
adns_path_space[n++] = '/'; adns_path_space[n++] = '/';
}
} }
} }
else else
@@ -95,25 +100,33 @@ init_adns(void)
n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space)); n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));
if (n < 0) if (n < 0)
{
exit_log_errno((e exit_log_errno((e
, "readlink(\"/proc/self/exe\") failed in init_adns()")); , "readlink(\"/proc/self/exe\") failed in init_adns()"));
}
} }
if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name)) if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))
{
exit_log("path to %s is too long", adns_name); exit_log("path to %s is too long", adns_name);
}
while (n > 0 && adns_path_space[n - 1] != '/') while (n > 0 && adns_path_space[n - 1] != '/')
{
n--; n--;
}
strcpy(adns_path_space + n, adns_name); strcpy(adns_path_space + n, adns_name);
adns_path = adns_path_space; adns_path = adns_path_space;
} }
if (access(adns_path, X_OK) < 0) if (access(adns_path, X_OK) < 0)
{
exit_log_errno((e, "%s missing or not executable", adns_path)); exit_log_errno((e, "%s missing or not executable", adns_path));
}
if (pipe(qfds) != 0 || pipe(afds) != 0) if (pipe(qfds) != 0 || pipe(afds) != 0)
{
exit_log_errno((e, "pipe(2) failed in init_adns()")); exit_log_errno((e, "pipe(2) failed in init_adns()"));
}
adns_pid = fork(); adns_pid = fork();
switch (adns_pid) switch (adns_pid)
@@ -128,7 +141,9 @@ init_adns(void)
* Take care to handle case where pipes already use these fds. * Take care to handle case where pipes already use these fds.
*/ */
if (afds[1] == 0) if (afds[1] == 0)
{
afds[1] = dup(afds[1]); /* avoid being overwritten */ afds[1] = dup(afds[1]); /* avoid being overwritten */
}
if (qfds[0] != 0) if (qfds[0] != 0)
{ {
dup2(qfds[0], 0); dup2(qfds[0], 0);
@@ -140,16 +155,18 @@ init_adns(void)
close(qfds[1]); close(qfds[1]);
} }
if (afds[0] > 1) if (afds[0] > 1)
{
close(afds[0]); close(afds[0]);
}
if (afds[1] > 1) if (afds[1] > 1)
{
close(afds[1]); close(afds[1]);
}
DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL)); DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));
execlp(adns_path, adns_name, NULL); execlp(adns_path, adns_name, NULL);
exit_log_errno((e, "execlp of %s failed", adns_path)); exit_log_errno((e, "execlp of %s failed", adns_path));
} }
default: default:
/* parent */ /* parent */
close(qfds[0]); close(qfds[0]);
@@ -183,8 +200,10 @@ stop_adns(void)
else if (WIFEXITED(status)) else if (WIFEXITED(status))
{ {
if (WEXITSTATUS(status) != 0) if (WEXITSTATUS(status) != 0)
{
plog("ADNS process exited with status %d" plog("ADNS process exited with status %d"
, (int) WEXITSTATUS(status)); , (int) WEXITSTATUS(status));
}
} }
else if (WIFSIGNALED(status)) else if (WIFSIGNALED(status))
{ {
@@ -227,8 +246,9 @@ decode_iii(u_char **pp, struct id *gw_id)
u_char under = *e; u_char under = *e;
if (p == e) if (p == e)
{
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
}
*e = '\0'; *e = '\0';
if (*p == '@') if (*p == '@')
{ {
@@ -236,8 +256,10 @@ decode_iii(u_char **pp, struct id *gw_id)
err_t ugh = atoid(p, gw_id, FALSE); err_t ugh = atoid(p, gw_id, FALSE);
if (ugh != NULL) if (ugh != NULL)
{
return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s" return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
, ugh); , ugh);
}
} }
else else
{ {
@@ -248,12 +270,14 @@ decode_iii(u_char **pp, struct id *gw_id)
, &ip); , &ip);
if (ugh != NULL) if (ugh != NULL)
{
return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s" return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
, ugh); , ugh);
}
if (isanyaddr(&ip)) if (isanyaddr(&ip))
{
return "gateway address must not be 0.0.0.0 or 0::0"; return "gateway address must not be 0.0.0.0 or 0::0";
}
iptoid(&ip, gw_id); iptoid(&ip, gw_id);
} }
@@ -278,14 +302,18 @@ process_txt_rr_body(u_char *str
/* is this for us? */ /* is this for us? */
if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0) if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)
{
return NULL; /* neither interesting nor bad */ return NULL; /* neither interesting nor bad */
}
p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */ p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */
p += strspn(p, " \t"); /* ignore leading whitespace */ p += strspn(p, " \t"); /* ignore leading whitespace */
/* decode '(' nnn ')' */ /* decode '(' nnn ')' */
if (*p != '(') if (*p != '(')
{
return "X-IPsec-Server missing '('"; return "X-IPsec-Server missing '('";
}
{ {
char *e; char *e;
@@ -293,25 +321,30 @@ process_txt_rr_body(u_char *str
p++; p++;
pref = strtoul(p, &e, 0); pref = strtoul(p, &e, 0);
if ((u_char *)e == p) if ((u_char *)e == p)
{
return "malformed X-IPsec-Server priority"; return "malformed X-IPsec-Server priority";
}
p = e + strspn(e, " \t"); p = e + strspn(e, " \t");
if (*p != ')') if (*p != ')')
{
return "X-IPsec-Server priority missing ')'"; return "X-IPsec-Server priority missing ')'";
}
p++; p++;
p += strspn(p, " \t"); p += strspn(p, " \t");
if (pref > 0xFFFF) if (pref > 0xFFFF)
{
return "X-IPsec-Server priority larger than 0xFFFF"; return "X-IPsec-Server priority larger than 0xFFFF";
}
} }
/* time for '=' */ /* time for '=' */
if (*p != '=') if (*p != '=')
{
return "X-IPsec-Server priority missing '='"; return "X-IPsec-Server priority missing '='";
}
p++; p++;
p += strspn(p, " \t"); p += strspn(p, " \t");
@@ -384,29 +417,34 @@ process_txt_rr_body(u_char *str
/* Decode base 64 encoding of key. /* Decode base 64 encoding of key.
* Similar code is in process_lwdnsq_key. * Similar code is in process_lwdnsq_key.
*/ */
u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
chunk_t kbc; size_t sz;
struct RSA_public_key r; err_t ugh;
chunk_t rfc3110_chunk;
public_key_t *key;
err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz,
, diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
if (ugh)
if (ugh != NULL) {
return builddiag("malformed key data: %s", ugh); return builddiag("malformed key data: %s", ugh);
}
if (kbc.len > sizeof(kb)) if (sz > sizeof(buf))
return builddiag("key data larger than %lu bytes" {
, (unsigned long) sizeof(kb)); return builddiag("key data larger than %lu bytes",
(unsigned long) sizeof(buf));
kbc.ptr = kb; }
ugh = unpack_RSA_public_key(&r, &kbc); rfc3110_chunk = chunk_create(buf, sz);
if (ugh != NULL) key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
return builddiag("invalid key data: %s", ugh); 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 */ /* now find a key entry to put it in */
gi.key = public_key_from_rsa(&r); gi.key = public_key_from_rsa(key);
free_RSA_public_content(&r);
unreference_key(&cr->last_info); unreference_key(&cr->last_info);
cr->last_info = reference_key(gi.key); cr->last_info = reference_key(gi.key);
@@ -426,13 +464,18 @@ process_txt_rr_body(u_char *str
{ {
char cidb[BUF_LEN]; char cidb[BUF_LEN];
char gwidb[BUF_LEN]; char gwidb[BUF_LEN];
identification_t *keyid;
public_key_t *pub_key;
idtoa(client_id, cidb, sizeof(cidb)); idtoa(client_id, cidb, sizeof(cidb));
idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); 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) if (gi.gw_key_present)
{ {
DBG_log("gateway for %s is %s with key %s" DBG_log("gateway for %s is %s with key %Y"
, cidb, gwidb, gi.key->u.rsa.keyid); , cidb, gwidb, keyid);
} }
else else
{ {
+109 -255
View File
@@ -34,6 +34,8 @@
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h> #include <crypto/prfs/prf.h>
#include <crypto/rngs/rng.h> #include <crypto/rngs/rng.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
@@ -1402,35 +1404,44 @@ static bool generate_skeyids_iv(struct state *st)
return prf_block_size; 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. * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* Use PKCS#1 version 1.5 encryption of hash (called * Use PKCS#1 version 1.5 encryption of hash (called
* RSAES-PKCS1-V1_5) in PKCS#2. * RSAES-PKCS1-V1_5) in PKCS#2.
*/ */
static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS], static size_t sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
const u_char *hash_val, size_t hash_len) u_char *hash_val, size_t hash_len)
{ {
size_t sz = 0; size_t sz = 0;
smartcard_t *sc = c->spd.this.sc; smartcard_t *sc = c->spd.this.sc;
if (sc == NULL) /* no smartcard */ 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 */ 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); 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 */ 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)) if (!scx_establish_context(sc) || !scx_login(sc))
{ {
scx_release_context(sc); scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash"); unlock_certs_and_keys("sign_hash");
return 0; 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"); plog("failed to get keylength from smartcard");
scx_release_context(sc); scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash"); unlock_certs_and_keys("sign_hash");
return 0; 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; sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
if (!pkcs11_keep_state) if (!pkcs11_keep_state)
scx_release_context(sc); scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash"); unlock_certs_and_keys("sign_hash");
} }
return sz; 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. /* Check signature against all RSA public keys we can find.
* If we need keys from DNS KEY records, and they haven't been fetched, * If we need keys from DNS KEY records, and they haven't been fetched,
* return STF_SUSPEND to ask for asynch DNS lookup. * 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. * If only we had coroutines.
*/ */
struct tac_state { struct tac_state {
/* RSA_check_signature's args that take_a_crack needs */
struct state *st; struct state *st;
const u_char *hash_val; chunk_t hash;
size_t hash_len; chunk_t sig;
const pb_stream *sig_pbs;
/* state carried between calls */
err_t best_ugh; /* most successful failure */
int tried_cnt; /* number of keys tried */ 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, static bool take_a_crack(struct tac_state *s, pubkey_t *kr)
const char *story USED_BY_DEBUG)
{ {
err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs public_key_t *pub_key = kr->public_key;
, kr, s->st); identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
const struct RSA_public_key *k = &kr->u.rsa;
s->tried_cnt++; 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(DBG_CRYPT | DBG_CONTROL,
, DBG_log("an RSA Sig check passed with *%s [%s]" DBG_log("signature check passed with keyid %Y", keyid)
, k->keyid, story)); )
unreference_key(&s->st->st_peer_pubkey);
s->st->st_peer_pubkey = reference_key(kr);
return TRUE; return TRUE;
} }
else else
{ {
DBG(DBG_CRYPT DBG(DBG_CRYPT,
, DBG_log("an RSA Sig check failure %s with *%s [%s]" DBG_log("signature check failed with keyid %Y", keyid)
, 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);
}
return FALSE; return FALSE;
} }
} }
static stf_status RSA_check_signature(const struct id* peer, struct state *st, 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, size_t hash_len, const pb_stream *sig_pbs,
#ifdef USE_KEYRR #ifdef USE_KEYRR
const pubkey_list_t *keys_from_dns, 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; const struct connection *c = st->st_connection;
struct tac_state s; struct tac_state s;
err_t dns_ugh = NULL;
s.st = st; s.st = st;
s.hash_val = hash_val; s.hash = chunk_create(hash_val, hash_len);
s.hash_len = hash_len; s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs));
s.sig_pbs = sig_pbs;
s.best_ugh = NULL;
s.tried_cnt = 0; s.tried_cnt = 0;
s.tn = s.tried;
/* try all gateway records hung off c */ /* try all gateway records hung off c */
if (c->policy & POLICY_OPPO) 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) for (gw = c->gw_info; gw != NULL; gw = gw->next)
{ {
/* only consider entries that have a key and are for our peer */ /* only consider entries that have a key and are for our peer */
if (gw->gw_key_present if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id)&&
&& same_id(&gw->gw_id, &c->spd.that.id) take_a_crack(&s, gw->key))
&& take_a_crack(&s, gw->key, "key saved from DNS TXT")) {
return STF_OK; 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) for (p = pubkeys; p != NULL; p = *pp)
{ {
pubkey_t *key = p->key; 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); 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 */ continue; /* continue with next public key */
} }
if (take_a_crack(&s, key, "preloaded key")) if (take_a_crack(&s, key))
return STF_OK; {
return STF_OK;
}
} }
pp = &p->next; pp = &p->next;
} }
} }
/* if no key was found (evidenced by best_ugh == NULL) /* if no key was found and that side of connection is
* and that side of connection is key_from_DNS_on_demand * key_from_DNS_on_demand then go search DNS for keys for peer.
* 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) 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; const struct gw_info *gwp;
for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) 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; return STF_OK;
}
}
} }
#ifdef USE_KEYRR #ifdef USE_KEYRR
else if (keys_from_dns != NULL) 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; const pubkey_list_t *kr;
for (kr = keys_from_dns; kr != NULL; kr = kr->next) 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; return STF_OK;
}
}
} }
#endif /* USE_KEYRR */ #endif /* USE_KEYRR */
else 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 */ 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 public key known for '%s'", id_buf);
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;
} }
else if (s.tried_cnt == 1)
if (s.best_ugh[0] == '9')
{ {
loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1); loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
/* XXX Could send notification back */ " wrong key?; tried %d", id_buf, s.tried_cnt);
return STF_FAIL + INVALID_HASH_INFORMATION; DBG(DBG_CONTROL,
DBG_log("public key for '%s' failed: "
"decrypted SIG payload into a malformed ECB", id_buf)
)
} }
else else
{ {
if (s.tried_cnt == 1) loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
{ "tried %d keys but none worked.", id_buf, s.tried_cnt);
loglog(RC_LOG_SERIOUS DBG(DBG_CONTROL,
, "Signature check (on %s) failed (wrong key?); tried%s" DBG_log("all %d public keys for '%s' failed: "
, id_buf, s.tried); "best decrypted SIG payload into a malformed ECB",
DBG(DBG_CONTROL, s.tried_cnt, id_buf)
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;
} }
return STF_FAIL + INVALID_KEY_INFORMATION;
} }
} }
@@ -2245,6 +2093,7 @@ static void decode_cert(struct msg_digest *md)
{ {
plog("X.509 certificate rejected"); plog("X.509 certificate rejected");
} }
DESTROY_IF(cert.public_key);
free_generalNames(cert.subjectAltName, FALSE); free_generalNames(cert.subjectAltName, FALSE);
free_generalNames(cert.crlDistributionPoints, 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) for (p = pubkeys; p != NULL; p = p->next)
{ {
pubkey_t *key = p->key; pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
if (key->alg == PUBKEY_ALG_RSA && if (type == KEY_RSA && same_id(&c->spd.that.id, &key->id) &&
same_id(&c->spd.that.id, &key->id) &&
key->until_time == UNDEFINED_TIME) key->until_time == UNDEFINED_TIME)
{ {
/* found a preloaded public key */ /* found a preloaded public key */
@@ -3595,12 +3444,12 @@ stf_status main_inR2_outI3(struct msg_digest *md)
{ {
/* SIG_I out */ /* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS]; u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
, sig_val, hash_val, hash_len); hash_len);
if (sig_len == 0) 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; return STF_FAIL + AUTHENTICATION_FAILED;
} }
@@ -3997,12 +3846,12 @@ main_inI3_outR3_tail(struct msg_digest *md
{ {
/* SIG_R out */ /* SIG_R out */
u_char sig_val[RSA_MAX_OCTETS]; u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
, sig_val, hash_val, hash_len); hash_len);
if (sig_len == 0) 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; return STF_FAIL + AUTHENTICATION_FAILED;
} }
@@ -4479,10 +4328,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_client: case vos_our_client:
next_step = vos_his_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; struct gw_info *gwp;
if (pri == NULL) if (private == NULL)
{ {
ugh = "we don't know our own key"; ugh = "we don't know our own key";
break; break;
@@ -4503,7 +4352,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = NULL; /* good! */ ugh = NULL; /* good! */
break; 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! */ ugh = NULL; /* good! */
break; break;
@@ -4515,9 +4364,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_txt: case vos_our_txt:
next_step = vos_his_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);
if (pri == NULL) if (private == NULL)
{ {
ugh = "we don't know our own key"; ugh = "we don't know our own key";
break; 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"; ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
#endif #endif
if (gwp->gw_key_present 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! */ ugh = NULL; /* good! */
break; break;
@@ -4551,9 +4400,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_key: case vos_our_key:
next_step = vos_his_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);
if (pri == NULL) if (private == NULL)
{ {
ugh = "we don't know our own key"; ugh = "we don't know our own key";
break; 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) 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"; 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 */ /* do this only once a day */
if (!logged_txt_warning) if (!logged_txt_warning)
@@ -4585,11 +4434,15 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_his_client: case vos_his_client:
next_step = vos_done; next_step = vos_done;
{ {
public_key_t *pub_key;
identification_t *p1st_keyid;
struct gw_info *gwp; struct gw_info *gwp;
/* check that the public key that authenticated /* check that the public key that authenticated
* the ISAKMP SA (p1st) will do for this gateway. * 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"; ugh = "peer's client does not delegate to peer";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) 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 * it implies fetching a KEY from the same
* place we must have gotten it. * place we must have gotten it.
*/ */
if (!gwp->gw_key_present if (!gwp->gw_key_present || p1st_keyid->equals(p1st_keyid,
|| same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa gwp->key->public_key->get_id(gwp->key->public_key,
, &gwp->key->u.rsa)) ID_PUBKEY_INFO_SHA1))
)
{ {
ugh = NULL; /* good! */ ugh = NULL; /* good! */
break; break;
+3 -2
View File
@@ -488,10 +488,11 @@ static bool do_command(struct connection *c, struct spd_route *sr,
for (p = pubkeys; p != NULL; p = p->next) for (p = pubkeys; p != NULL; p = p->next)
{ {
pubkey_t *key = p->key; pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
int pathlen; int pathlen;
if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id) if (type == KEY_RSA && same_id(&sr->that.id, &key->id) &&
&& trusted_ca(key->issuer, sr->that.ca, &pathlen)) trusted_ca(key->issuer, sr->that.ca, &pathlen))
{ {
dntoa_or_null(peerca_str, BUF_LEN, key->issuer, ""); dntoa_or_null(peerca_str, BUF_LEN, key->issuer, "");
escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str)); escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str));
+265 -366
View File
File diff suppressed because it is too large Load Diff
+15 -20
View File
@@ -1,5 +1,6 @@
/* mechanisms for preshared keys (public, private, and preshared secrets) /* mechanisms for preshared keys (public, private, and preshared secrets)
* Copyright (C) 1998-2002 D. Hugh Redelmeier. * 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 * 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 * under the terms of the GNU General Public License as published by the
@@ -15,9 +16,9 @@
#ifndef _KEYS_H #ifndef _KEYS_H
#define _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" #include "certs.h"
#ifndef SHARED_SECRETS_FILE #ifndef SHARED_SECRETS_FILE
@@ -31,8 +32,7 @@ extern void free_preshared_secrets(void);
enum PrivateKeyKind { enum PrivateKeyKind {
PPK_PSK, PPK_PSK,
/* PPK_DSS, */ /* not implemented */ PPK_PUBKEY,
PPK_RSA,
PPK_XAUTH, PPK_XAUTH,
PPK_PIN PPK_PIN
}; };
@@ -43,9 +43,8 @@ extern void xauth_defaults(void);
struct connection; struct connection;
extern const chunk_t *get_preshared_secret(const struct connection *c); 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 private_key_t *get_private_key(const struct connection *c);
extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c); extern private_key_t *get_x509_private_key(const x509cert_t *cert);
extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
/* public key machinery */ /* public key machinery */
@@ -62,10 +61,7 @@ struct pubkey {
, until_time; , until_time;
chunk_t issuer; chunk_t issuer;
chunk_t serial; chunk_t serial;
enum pubkey_alg alg; public_key_t *public_key;
union {
RSA_public_key_t rsa;
} u;
}; };
typedef struct pubkey_list pubkey_list_t; 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_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 pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
extern void free_public_keys(pubkey_list_t **keys); extern void free_public_keys(pubkey_list_t **keys);
extern void free_remembered_public_keys(void); extern void free_remembered_public_keys(void);
extern void delete_public_keys(const struct id *id, enum pubkey_alg alg extern void delete_public_keys(const struct id *id, key_type_t type,
, chunk_t issuer, chunk_t serial); chunk_t issuer, chunk_t serial);
extern pubkey_t *reference_key(pubkey_t *pk); extern pubkey_t *reference_key(pubkey_t *pk);
extern void unreference_key(pubkey_t **pkp); extern void unreference_key(pubkey_t **pkp);
extern err_t add_public_key(const struct id *id extern bool add_public_key(const struct id *id,
, enum dns_auth_level dns_auth_level enum dns_auth_level dns_auth_level,
, enum pubkey_alg alg enum pubkey_alg alg,
, const chunk_t *key chunk_t rfc3110_key,
, pubkey_list_t **head); pubkey_list_t **head);
extern bool has_private_key(cert_t cert); extern bool has_private_key(cert_t cert);
extern void add_x509_public_key(x509cert_t *cert, time_t until extern void add_x509_public_key(x509cert_t *cert, time_t until
+76 -70
View File
@@ -39,7 +39,6 @@
#include "certs.h" #include "certs.h"
#include "smartcard.h" #include "smartcard.h"
#include "whack.h" #include "whack.h"
#include "pkcs1.h"
#include "keys.h" #include "keys.h"
#include "fetch.h" #include "fetch.h"
#include "ocsp.h" #include "ocsp.h"
@@ -159,7 +158,7 @@ static x509cert_t *ocsp_requestor_cert = NULL;
static smartcard_t *ocsp_requestor_sc = 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 * 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) 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 */ static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */
location->uri = cert->accessLocation; location->uri = cert->accessLocation;
if (location->uri.ptr == NULL) 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); 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->next = NULL;
location->issuer = cert->issuer; location->issuer = cert->issuer;
@@ -660,7 +667,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
/* initialize temporary static storage */ /* initialize temporary static storage */
ocsp_requestor_cert = NULL; ocsp_requestor_cert = NULL;
ocsp_requestor_sc = NULL; ocsp_requestor_sc = NULL;
ocsp_requestor_pri = NULL; ocsp_requestor_key = NULL;
for (;;) for (;;)
{ {
@@ -699,15 +706,15 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
else else
{ {
/* look for a matching private key in the chained list */ /* 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(DBG_CONTROL,
DBG_log("matching private key found") DBG_log("matching private key found")
) )
ocsp_requestor_cert = cert; ocsp_requestor_cert = cert;
ocsp_requestor_pri = pri; ocsp_requestor_key = private;
return TRUE; return TRUE;
} }
} }
@@ -715,50 +722,58 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
return FALSE; return FALSE;
} }
static chunk_t generate_signature(chunk_t digest, smartcard_t *sc, static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc)
const RSA_private_key_t *pri)
{ {
chunk_t sigdata; hasher_t *hasher;
u_char *pos; 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; size_t siglen = 0;
if (sc != NULL) if (!scx_establish_context(sc) || !scx_login(sc))
{ {
/* RSA signature is done on smartcard */ scx_release_context(sc);
return chunk_empty;
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
return chunk_empty;
}
siglen = scx_get_keylength(sc);
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)
)
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);
} }
else
siglen = scx_get_keylength(sc);
if (siglen == 0)
{ {
/* RSA signature is done in software */ plog("failed to get keylength from smartcard");
siglen = pri->pub.k; scx_release_context(sc);
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); return chunk_empty;
*pos++ = 0x00; }
sign_hash(pri, digest.ptr, digest.len, pos, siglen);
DBG(DBG_CONTROL | DBG_CRYPT,
DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
, (int)sc->slot, sc->id)
)
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (hasher == NULL)
{
return chunk_empty;
}
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)
{
scx_release_context(sc);
} }
return sigdata; 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) static chunk_t build_signature(chunk_t tbsRequest)
{ {
chunk_t sigdata, certs; chunk_t sigdata, certs;
chunk_t digest_info;
u_char digest_buf[MAX_DIGEST_LEN]; if (ocsp_requestor_sc != NULL)
chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN }; {
/* RSA signature is done on smartcard */
if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw)) sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc);
return chunk_empty; }
else
/* according to PKCS#1 v2.1 digest must be packaged into {
* an ASN.1 structure for encryption /* RSA signature is done in software */
*/ sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key,
digest_info = asn1_wrap(ASN1_SEQUENCE, "cm" TRUE);
, 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 (sigdata.ptr == NULL) if (sigdata.ptr == NULL)
{
return chunk_empty; return chunk_empty;
}
/* include our certificate */ /* include our certificate */
certs = asn1_wrap(ASN1_CONTEXT_C_0, "m" 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") DBG_log("ocsp signer cert found")
) )
if (!check_signature(res->tbs, res->signature, res->algorithm if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert))
, res->algorithm, authcert))
{ {
plog("signature of ocsp response is invalid"); plog("signature of ocsp response is invalid");
unlock_authcert_list("valid_ocsp_response"); unlock_authcert_list("valid_ocsp_response");
@@ -1051,8 +1057,8 @@ static bool valid_ocsp_response(response_t *res)
DBG_log("issuer cacert found") DBG_log("issuer cacert found")
) )
if (!check_signature(cert->tbsCertificate, cert->signature if (!x509_check_signature(cert->tbsCertificate, cert->signature,
, cert->algorithm, cert->algorithm, authcert)) cert->algorithm, authcert))
{ {
plog("certificate signature is invalid"); plog("certificate signature is invalid");
unlock_authcert_list("valid_ocsp_response"); unlock_authcert_list("valid_ocsp_response");
+65 -217
View File
@@ -1,5 +1,7 @@
/* Support of OpenPGP certificates /* Support of OpenPGP certificates
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur * Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
@@ -19,6 +21,7 @@
#include <freeswan.h> #include <freeswan.h>
#include <library.h> #include <library.h>
#include <pgp/pgp.h>
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include "constants.h" #include "constants.h"
@@ -26,10 +29,9 @@
#include "mp_defs.h" #include "mp_defs.h"
#include "log.h" #include "log.h"
#include "id.h" #include "id.h"
#include "pgp.h" #include "pgpcert.h"
#include "certs.h" #include "certs.h"
#include "whack.h" #include "whack.h"
#include "pkcs1.h"
#include "keys.h" #include "keys.h"
/* /*
@@ -87,36 +89,6 @@ static const char *const pgp_packet_type_name[] = {
#define PGP_PUBKEY_ALG_ECDSA 19 #define PGP_PUBKEY_ALG_ECDSA 19
#define PGP_PUBKEY_ALG_ELGAMAL 20 #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 * Size of PGP Key ID
*/ */
@@ -129,28 +101,15 @@ const pgpcert_t empty_pgpcert = {
{ NULL, 0 }, /* certificate */ { NULL, 0 }, /* certificate */
0 , /* created */ 0 , /* created */
0 , /* until */ 0 , /* until */
0 , /* pubkeyAlgorithm */ NULL , /* public key */
{ NULL, 0 }, /* modulus */ NULL /* fingerprint */
{ 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 * extracts the length of a PGP packet
*/ */
static size_t static size_t pgp_old_packet_length(chunk_t *blob)
pgp_old_packet_length(chunk_t *blob)
{ {
/* bits 0 and 1 define the packet length type */ /* bits 0 and 1 define the packet length type */
int len_type = 0x03 & *blob->ptr++; int len_type = 0x03 & *blob->ptr++;
@@ -158,14 +117,13 @@ pgp_old_packet_length(chunk_t *blob)
blob->len--; blob->len--;
/* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
return pgp_size(blob, (len_type == 0)? 1: len_type << 1); return pgp_length(blob, (len_type == 0)? 1: len_type << 1);
} }
/* /*
* extracts PGP packet version (V3 or V4) * extracts PGP packet version (V3 or V4)
*/ */
static u_char static u_char pgp_version(chunk_t *blob)
pgp_version(chunk_t *blob)
{ {
u_char version = *blob->ptr++; u_char version = *blob->ptr++;
blob->len--; blob->len--;
@@ -179,10 +137,10 @@ pgp_version(chunk_t *blob)
/* /*
* Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440 * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
*/ */
static bool static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
{ {
u_char version = pgp_version(packet); u_char version = pgp_version(packet);
public_key_t *key;
if (version < 3 || version > 4) if (version < 3 || version > 4)
{ {
@@ -191,7 +149,7 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
} }
/* creation date - 4 bytes */ /* creation date - 4 bytes */
cert->created = (time_t)pgp_size(packet, 4); cert->created = (time_t)pgp_length(packet, 4);
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log("L3 - created:"); DBG_log("L3 - created:");
DBG_log(" %T", &cert->created, TRUE) DBG_log(" %T", &cert->created, TRUE)
@@ -200,12 +158,13 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
if (version == 3) if (version == 3)
{ {
/* validity in days - 2 bytes */ /* validity in days - 2 bytes */
cert->until = (time_t)pgp_size(packet, 2); cert->until = (time_t)pgp_length(packet, 2);
/* validity of 0 days means that the key never expires */ /* validity of 0 days means that the key never expires */
if (cert->until > 0) if (cert->until > 0)
{
cert->until = cert->created + 24*3600*cert->until; cert->until = cert->created + 24*3600*cert->until;
}
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log("L3 - until:"); DBG_log("L3 - until:");
DBG_log(" %T", &cert->until, TRUE); DBG_log(" %T", &cert->until, TRUE);
@@ -217,49 +176,29 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
DBG_log("L3 - public key algorithm:") DBG_log("L3 - public key algorithm:")
) )
switch (pgp_size(packet, 1)) switch (pgp_length(packet, 1))
{ {
case PGP_PUBKEY_ALG_RSA: case PGP_PUBKEY_ALG_RSA:
case PGP_PUBKEY_ALG_RSA_SIGN_ONLY: case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
cert->pubkeyAlg = PUBKEY_ALG_RSA;
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log(" RSA") DBG_log(" RSA")
) )
/* modulus n */ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE; BUILD_BLOB_PGP, *packet,
cert->modulus.ptr = packet->ptr; BUILD_END);
packet->ptr += cert->modulus.len; if (key == NULL)
packet->len -= cert->modulus.len; {
DBG(DBG_PARSING, return FALSE;
DBG_log("L3 - modulus:") }
) cert->public_key = key;
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) if (version == 3)
{ {
hasher_t *hasher; cert->fingerprint = key->get_id(key, ID_KEY_ID);
if (cert->fingerprint == NULL)
/* 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; return FALSE;
} }
hasher->get_hash(hasher, cert->modulus, NULL);
hasher->get_hash(hasher, cert->publicExponent, cert->fingerprint);
hasher->destroy(hasher);
} }
else else
{ {
@@ -267,14 +206,12 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
} }
break; break;
case PGP_PUBKEY_ALG_DSA: case PGP_PUBKEY_ALG_DSA:
cert->pubkeyAlg = PUBKEY_ALG_DSA;
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log(" DSA") DBG_log(" DSA")
) )
plog(" DSA public keys not supported"); plog(" DSA public keys not supported");
return FALSE; return FALSE;
default: default:
cert->pubkeyAlg = 0;
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log(" other") DBG_log(" other")
) )
@@ -284,104 +221,10 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE; 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 * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
*/ */
static bool static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
{ {
time_t created; time_t created;
chunk_t keyid; chunk_t keyid;
@@ -393,20 +236,20 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE; return TRUE;
/* size byte must have the value 5 */ /* size byte must have the value 5 */
if (pgp_size(packet, 1) != 5) if (pgp_length(packet, 1) != 5)
{ {
plog(" size must be 5"); plog(" size must be 5");
return FALSE; return FALSE;
} }
/* signature type - 1 byte */ /* signature type - 1 byte */
sig_type = (u_char)pgp_size(packet, 1); sig_type = (u_char)pgp_length(packet, 1);
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log("L3 - signature type: 0x%2x", sig_type) DBG_log("L3 - signature type: 0x%2x", sig_type)
) )
/* creation date - 4 bytes */ /* creation date - 4 bytes */
created = (time_t)pgp_size(packet, 4); created = (time_t)pgp_length(packet, 4);
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log("L3 - created:"); DBG_log("L3 - created:");
DBG_log(" %T", &cert->created, TRUE) DBG_log(" %T", &cert->created, TRUE)
@@ -420,8 +263,7 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE; return TRUE;
} }
bool bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key)
parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
{ {
DBG(DBG_PARSING, DBG(DBG_PARSING,
DBG_log("L0 - PGP file:") DBG_log("L0 - PGP file:")
@@ -486,11 +328,15 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
{ {
case PGP_PKT_PUBLIC_KEY: case PGP_PKT_PUBLIC_KEY:
if (!parse_pgp_pubkey_packet(&packet, cert)) if (!parse_pgp_pubkey_packet(&packet, cert))
{
return FALSE; return FALSE;
}
break; break;
case PGP_PKT_SIGNATURE: case PGP_PKT_SIGNATURE:
if (!parse_pgp_signature_packet(&packet, cert)) if (!parse_pgp_signature_packet(&packet, cert))
{
return FALSE; return FALSE;
}
break; break;
case PGP_PKT_USER_ID: case PGP_PKT_USER_ID:
DBG(DBG_PARSING, DBG(DBG_PARSING,
@@ -508,12 +354,18 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
switch (packet_type) switch (packet_type)
{ {
case PGP_PKT_SECRET_KEY: case PGP_PKT_SECRET_KEY:
if (!parse_pgp_secretkey_packet(&packet, key)) *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
return FALSE; BUILD_BLOB_PGP, packet,
BUILD_END);
break; break;
default: default:
break; break;
} }
if (*key == NULL)
{
return FALSE;
}
} }
} }
} }
@@ -523,8 +375,7 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
/* /*
* compare two OpenPGP certificates * compare two OpenPGP certificates
*/ */
static bool static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b)
same_pgpcert(pgpcert_t *a, pgpcert_t *b)
{ {
return a->certificate.len == b->certificate.len && return a->certificate.len == b->certificate.len &&
memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len); memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
@@ -533,8 +384,7 @@ same_pgpcert(pgpcert_t *a, pgpcert_t *b)
/* /*
* for each link pointing to the certificate increase the count by one * for each link pointing to the certificate increase the count by one
*/ */
void void share_pgpcert(pgpcert_t *cert)
share_pgpcert(pgpcert_t *cert)
{ {
if (cert != NULL) if (cert != NULL)
{ {
@@ -545,21 +395,17 @@ share_pgpcert(pgpcert_t *cert)
/* /*
* select the OpenPGP keyid as ID * select the OpenPGP keyid as ID
*/ */
void void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
{ {
end_id->kind = ID_KEY_ID; end_id->kind = ID_KEY_ID;
end_id->name.len = PGP_FINGERPRINT_SIZE; end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
end_id->name.ptr = cert->fingerprint; end_id->name = chunk_clone(end_id->name);
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 * add an OpenPGP user/host certificate to the chained list
*/ */
pgpcert_t* pgpcert_t* add_pgpcert(pgpcert_t *cert)
add_pgpcert(pgpcert_t *cert)
{ {
pgpcert_t *c = pgpcerts; pgpcert_t *c = pgpcerts;
@@ -585,14 +431,15 @@ add_pgpcert(pgpcert_t *cert)
/* release of a certificate decreases the count by one /* release of a certificate decreases the count by one
" the certificate is freed when the counter reaches zero " the certificate is freed when the counter reaches zero
*/ */
void void release_pgpcert(pgpcert_t *cert)
release_pgpcert(pgpcert_t *cert)
{ {
if (cert != NULL && --cert->count == 0) if (cert != NULL && --cert->count == 0)
{ {
pgpcert_t **pp = &pgpcerts; pgpcert_t **pp = &pgpcerts;
while (*pp != cert) while (*pp != cert)
{
pp = &(*pp)->next; pp = &(*pp)->next;
}
*pp = cert->next; *pp = cert->next;
free_pgpcert(cert); free_pgpcert(cert);
} }
@@ -601,11 +448,12 @@ release_pgpcert(pgpcert_t *cert)
/* /*
* free a PGP certificate * free a PGP certificate
*/ */
void void free_pgpcert(pgpcert_t *cert)
free_pgpcert(pgpcert_t *cert)
{ {
if (cert != NULL) if (cert != NULL)
{ {
DESTROY_IF(cert->public_key);
DESTROY_IF(cert->fingerprint);
free(cert->certificate.ptr); free(cert->certificate.ptr);
free(cert); free(cert);
} }
@@ -614,8 +462,7 @@ free_pgpcert(pgpcert_t *cert)
/* /*
* list all PGP end certificates in a chained list * list all PGP end certificates in a chained list
*/ */
void void list_pgp_end_certs(bool utc)
list_pgp_end_certs(bool utc)
{ {
pgpcert_t *cert = pgpcerts; pgpcert_t *cert = pgpcerts;
time_t now; time_t now;
@@ -632,19 +479,20 @@ list_pgp_end_certs(bool utc)
while (cert != NULL) while (cert != NULL)
{ {
unsigned keysize; public_key_t *key = cert->public_key;
char buf[BUF_LEN];
cert_t c; cert_t c;
c.type = CERT_PGP; c.type = CERT_PGP;
c.u.pgp = cert; c.u.pgp = cert;
whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count); 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: %Y", cert->fingerprint);
whack_log(RC_COMMENT, " fingerprint: %s", buf); whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
form_keyid(cert->publicExponent, cert->modulus, buf, &keysize); key_type_names, key->get_type(key),
whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf, key->get_keysize(key) * BITS_PER_BYTE,
(has_private_key(c))? ", has private key" : ""); 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, " created: %T", &cert->created, utc);
whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc, whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc,
check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE)); check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+17 -17
View File
@@ -1,5 +1,7 @@
/* Support of OpenPGP certificates /* Support of OpenPGP certificates
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur * Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
@@ -12,12 +14,12 @@
* for more details. * for more details.
*/ */
#ifndef _PGP_H #ifndef _PGPCERT_H
#define _PGP_H #define _PGPCERT_H
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include <credentials/keys/private_key.h>
#include "pkcs1.h" #include <credentials/keys/public_key.h>
/* /*
* Length of PGP V3 fingerprint * Length of PGP V3 fingerprint
@@ -31,20 +33,18 @@ typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
typedef struct pgpcert pgpcert_t; typedef struct pgpcert pgpcert_t;
struct pgpcert { struct pgpcert {
pgpcert_t *next; pgpcert_t *next;
time_t installed; time_t installed;
int count; int count;
chunk_t certificate; chunk_t certificate;
time_t created; time_t created;
time_t until; time_t until;
enum pubkey_alg pubkeyAlg; public_key_t *public_key;
chunk_t modulus; identification_t *fingerprint;
chunk_t publicExponent;
fingerprint_t fingerprint;
}; };
extern const pgpcert_t empty_pgpcert; extern const pgpcert_t empty_pgpcert;
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key); extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key);
extern void share_pgpcert(pgpcert_t *cert); extern void share_pgpcert(pgpcert_t *cert);
extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id); extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
extern pgpcert_t* add_pgpcert(pgpcert_t *cert); extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
@@ -52,4 +52,4 @@ extern void list_pgp_end_certs(bool utc);
extern void release_pgpcert(pgpcert_t *cert); extern void release_pgpcert(pgpcert_t *cert);
extern void free_pgpcert(pgpcert_t *cert); extern void free_pgpcert(pgpcert_t *cert);
#endif /* _PGP_H */ #endif /* _PGPCERT_H */
-602
View File
@@ -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);
}
-86
View File
@@ -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 */
+54 -25
View 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 */ /* check the signature only if a cacert is available */
if (cacert != NULL) if (cacert != NULL)
{ {
public_key_t *key = cacert->public_key;
signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
if (signerInfos == 0) if (signerInfos == 0)
{ {
DBG1("no signerInfo object found"); DBG1("no signerInfo object found");
@@ -355,15 +358,39 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
DBG1("no authenticatedAttributes object found"); DBG1("no authenticatedAttributes object found");
return FALSE; return FALSE;
} }
if (!check_signature(*attributes, encrypted_digest, digest_alg, if (enc_alg != OID_RSA_ENCRYPTION)
enc_alg, cacert))
{ {
DBG1("invalid signature"); DBG1("only RSA digest encryption supported");
return FALSE; return FALSE;
} }
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 else
{ {
DBG2("signature is valid"); DBG1("invalid signature");
return FALSE;
} }
} }
return TRUE; 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, bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber, chunk_t serialNumber,
const RSA_private_key_t *key) private_key_t *key)
{ {
asn1_parser_t *parser; asn1_parser_t *parser;
chunk_t object; chunk_t object;
@@ -446,7 +473,7 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
} }
break; break;
case PKCS7_ENCRYPTED_KEY: 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"); DBG1("symmetric key could not be decrypted with rsa");
goto end; goto end;
@@ -579,17 +606,20 @@ chunk_t pkcs7_contentType_attribute(void)
*/ */
chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
{ {
u_char digest_buf[MAX_DIGEST_LEN]; chunk_t digest;
chunk_t digest = { digest_buf, MAX_DIGEST_LEN }; hash_algorithm_t hash_alg;
hasher_t *hasher;
compute_digest(content, digest_alg, &digest); 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" return asn1_wrap(ASN1_SEQUENCE, "cm",
, ASN1_messageDigest_oid ASN1_messageDigest_oid,
, asn1_wrap(ASN1_SET, "m" asn1_wrap(ASN1_SET, "m",
, asn1_simple_object(ASN1_OCTET_STRING, digest) 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, chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
const x509cert_t *cert, int digest_alg, const x509cert_t *cert, int digest_alg,
const RSA_private_key_t *key) private_key_t *key)
{ {
contentInfo_t pkcs7Data, signedData; contentInfo_t pkcs7Data, signedData;
chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo; 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) if (attributes.ptr != NULL)
{ {
encryptedDigest = pkcs1_build_signature(attributes, digest_alg encryptedDigest = x509_build_signature(attributes, digest_alg, key,
, key, FALSE); FALSE);
authenticatedAttributes = chunk_clone(attributes); authenticatedAttributes = chunk_clone(attributes);
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
} }
else else
{ {
encryptedDigest = (data.ptr == NULL)? chunk_empty 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; 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; encryption_algorithm_t alg;
size_t alg_key_size; size_t alg_key_size;
RSA_public_key_t public_key; chunk_t symmetricKey, protectedKey, iv, in, out;
chunk_t symmetricKey, iv, in, out;
crypter_t *crypter; crypter_t *crypter;
alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size); 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(in.ptr);
free(iv.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 */ /* build pkcs7 enveloped data object */
{ {
chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm" chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_build_known_oid(enc_alg) , asn1_build_known_oid(enc_alg)
, asn1_simple_object(ASN1_OCTET_STRING, iv)); , 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)); , asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m" chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
, RSA_encrypt(&public_key, symmetricKey)); , protectedKey);
chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm" chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
, ASN1_INTEGER_0 , 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); cInfo = pkcs7_build_contentInfo(&envelopedData);
DBG3("envelopedData %B", &cInfo); DBG3("envelopedData %B", &cInfo);
free_RSA_public_content(&public_key);
free(envelopedData.content.ptr); free(envelopedData.content.ptr);
free(symmetricKey.ptr); free(symmetricKey.ptr);
return cInfo; return cInfo;
+5 -5
View File
@@ -1,6 +1,7 @@
/* Support of PKCS#7 data structures /* Support of PKCS#7 data structures
* Copyright (C) 2005 Jan Hutter, Martin Willi * Copyright (C) 2005 Jan Hutter, Martin Willi
* Copyright (C) 2002-2005 Andreas Steffen * Copyright (C) 2002-2009 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil, Switzerland * Hochschule fuer Technik Rapperswil, Switzerland
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -18,9 +19,8 @@
#define _PKCS7_H #define _PKCS7_H
#include <crypto/crypters/crypter.h> #include <crypto/crypters/crypter.h>
#include <credentials/keys/private_key.h>
#include "defs.h" #include "defs.h"
#include "pkcs1.h"
#include "x509.h" #include "x509.h"
/* Access structure for a PKCS#7 ContentInfo object */ /* 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, extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data,
x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert); x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert);
extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, 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_contentType_attribute(void);
extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg); 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_issuerAndSerialNumber(const x509cert_t *cert);
extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, 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, extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert,
int enc_alg); int enc_alg);
+5 -4
View File
@@ -234,10 +234,11 @@ key_add_request(const whack_message_t *msg)
} }
else else
{ {
ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg if (!add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, msg->keyval,
, &msg->keyval, &pubkeys); &pubkeys))
if (ugh != NULL) {
loglog(RC_LOG_SERIOUS, "%s", ugh); loglog(RC_LOG_SERIOUS, "failed to add public key");
}
} }
} }
} }
+126 -224
View File
@@ -35,7 +35,6 @@
#include "mp_defs.h" #include "mp_defs.h"
#include "log.h" #include "log.h"
#include "id.h" #include "id.h"
#include "pkcs1.h"
#include "x509.h" #include "x509.h"
#include "crl.h" #include "crl.h"
#include "ca.h" #include "ca.h"
@@ -198,36 +197,33 @@ static const asn1Object_t pubkeyObjects[] = {
* ASN.1 definition of an X.509v3 x509_cert * ASN.1 definition of an X.509v3 x509_cert
*/ */
static const asn1Object_t certObjects[] = { static const asn1Object_t certObjects[] = {
{ 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
{ 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
{ 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
{ 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
{ 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
{ 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */
{ 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
{ 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
{ 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 14 */ { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
{ 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 16 */ { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */
{ 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 18 */ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */
{ 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 19 */ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 20 */ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 21 */ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF | { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */
ASN1_BODY }, /* 22 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 23 */ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 24 */ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 25 */ { 0, "exit", ASN1_EOC, ASN1_EXIT }
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 26 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 27 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
}; };
#define X509_OBJ_CERTIFICATE 0 #define X509_OBJ_CERTIFICATE 0
#define X509_OBJ_TBS_CERTIFICATE 1 #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_BEFORE 8
#define X509_OBJ_NOT_AFTER 9 #define X509_OBJ_NOT_AFTER 9
#define X509_OBJ_SUBJECT 10 #define X509_OBJ_SUBJECT 10
#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12 #define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11
#define X509_OBJ_SUBJECT_PUBLIC_KEY 13 #define X509_OBJ_EXTN_ID 19
#define X509_OBJ_EXTN_ID 21 #define X509_OBJ_CRITICAL 20
#define X509_OBJ_CRITICAL 22 #define X509_OBJ_EXTN_VALUE 21
#define X509_OBJ_EXTN_VALUE 23 #define X509_OBJ_ALGORITHM 24
#define X509_OBJ_ALGORITHM 26 #define X509_OBJ_SIGNATURE 25
#define X509_OBJ_SIGNATURE 27
const x509cert_t empty_x509cert = { const x509cert_t empty_x509cert = {
NULL , /* *next */ NULL , /* *next */
@@ -262,11 +257,7 @@ const x509cert_t empty_x509cert = {
0 , /* notBefore */ 0 , /* notBefore */
0 , /* notAfter */ 0 , /* notAfter */
{ NULL, 0 } , /* subject */ { NULL, 0 } , /* subject */
/* subjectPublicKeyInfo */ NULL , /* public_key */
OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
{ NULL, 0 } , /* subjectPublicKey */
{ NULL, 0 } , /* modulus */
{ NULL, 0 } , /* publicExponent */
/* issuerUniqueID */ /* issuerUniqueID */
/* subjectUniqueID */ /* subjectUniqueID */
/* extensions */ /* extensions */
@@ -1140,13 +1131,19 @@ chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
/** /**
* Build a to-be-signed X.509 certificate body * 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 */ /* version is always X.509v3 */
chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2); chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
chunk_t extensions = chunk_empty; 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) if (cert->subjectAltName != NULL)
{ {
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m" 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" return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
, version , version
, asn1_simple_object(ASN1_INTEGER, cert->serialNumber) , asn1_integer("c", cert->serialNumber)
, asn1_algorithmIdentifier(cert->sigAlg) , asn1_algorithmIdentifier(cert->sigAlg)
, cert->issuer , cert->issuer
, asn1_wrap(ASN1_SEQUENCE, "mm" , 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) , asn1_from_time(&cert->notAfter, ASN1_UTCTIME)
) )
, cert->subject , cert->subject
, pkcs1_build_publicKeyInfo(rsa) , keyInfo
, extensions , 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 * Build a DER-encoded X.509 certificate
*/ */
void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key, void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
const RSA_private_key_t *signer_key) private_key_t *signer_key)
{ {
chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key); chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg
, signer_key, TRUE); , signer_key, TRUE);
cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm" cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
, tbs_cert , tbs_cert
@@ -1210,6 +1207,7 @@ void free_x509cert(x509cert_t *cert)
{ {
if (cert != NULL) if (cert != NULL)
{ {
DESTROY_IF(cert->public_key);
free_generalNames(cert->subjectAltName, FALSE); free_generalNames(cert->subjectAltName, FALSE);
free_generalNames(cert->crlDistributionPoints, FALSE); free_generalNames(cert->crlDistributionPoints, FALSE);
free(cert->certificate.ptr); free(cert->certificate.ptr);
@@ -1318,111 +1316,75 @@ void store_x509certs(x509cert_t **firstcert, bool strict)
} }
/** /**
* Decrypts an RSA signature using the issuer's certificate * Check if a signature over binary blob is genuine
*/ */
static bool decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert, bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
chunk_t *digest) const x509cert_t *issuer_cert)
{ {
switch (alg) public_key_t *key = issuer_cert->public_key;
signature_scheme_t scheme = SIGN_DEFAULT;
switch (algorithm)
{ {
chunk_t decrypted;
case OID_RSA_ENCRYPTION:
case OID_MD2_WITH_RSA:
case OID_MD5_WITH_RSA: case OID_MD5_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1_WITH_RSA: case OID_SHA1_WITH_RSA:
case OID_SHA1_WITH_RSA_OIW: scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256_WITH_RSA: case OID_SHA256_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384_WITH_RSA: case OID_SHA384_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512_WITH_RSA: case OID_SHA512_WITH_RSA:
{ scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
mpz_t s; break;
RSA_public_key_t rsa; case OID_ECDSA_WITH_SHA1:
scheme = SIGN_ECDSA_WITH_SHA1;
init_RSA_public_key(&rsa, issuer_cert->publicExponent break;
, issuer_cert->modulus);
/* decrypt the signature s = s^e mod n */
n_to_mpz(s, sig.ptr, sig.len);
mpz_powm(s, s, &rsa.e, &rsa.n);
/* convert back to bytes */
decrypted = mpz_to_n(s, rsa.k);
DBG(DBG_PARSING,
DBG_dump_chunk(" decrypted signature: ", decrypted)
)
/* copy the least significant bits of decrypted signature
* into the digest string
*/
memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
digest->len);
/* free memory */
free_RSA_public_content(&rsa);
free(decrypted.ptr);
mpz_clear(s);
return TRUE;
}
default: default:
digest->len = 0;
return FALSE; return FALSE;
} }
return key->verify(key, scheme, tbs, sig);
} }
/** /**
* Check if a signature over binary blob is genuine * Build an ASN.1 encoded PKCS#1 signature over a binary blob
*/ */
bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg, chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
const x509cert_t *issuer_cert) bool bit_string)
{ {
u_char digest_buf[MAX_DIGEST_LEN]; signature_scheme_t scheme = SIGN_DEFAULT;
u_char decrypted_buf[MAX_DIGEST_LEN]; chunk_t signature;
chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
DBG(DBG_PARSING, switch (hash_alg)
if (digest_alg != OID_UNKNOWN)
{
DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
}
else
{
DBG_log("unknown signature digest algorithm");
}
)
if (!compute_digest(tbs, digest_alg, &digest))
{ {
plog(" digest algorithm not supported"); case OID_MD5:
return FALSE; scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512:
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
break;
default:
return chunk_empty;
} }
if (!key->sign(key, scheme, tbs, &signature))
DBG(DBG_PARSING,
DBG_dump_chunk(" digest:", digest)
)
decrypted.len = digest.len; /* we want the same digest length */
DBG(DBG_PARSING,
if (enc_alg != OID_UNKNOWN)
{
DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
}
else
{
DBG_log("unknown signature encryption algorithm");
}
)
if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
{ {
plog(" decryption algorithm not supported"); return chunk_empty;
return FALSE; }
} return (bit_string) ? asn1_bitstring("m", signature)
: asn1_wrap(ASN1_OCTET_STRING, "m", signature);
/* check if digests are equal */
return memeq(decrypted.ptr, digest.ptr, digest.len);
} }
/** /**
@@ -1489,15 +1451,17 @@ void gntoid(struct id *id, const generalName_t *gn)
*/ */
bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID) bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
{ {
hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); identification_t *keyid;
chunk_t encoding;
if (hasher == NULL) keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1);
if (keyid == NULL)
{ {
plog(" no SHA-1 hasher available to compute subjectKeyID"); plog(" unable to compute subjectKeyID");
return FALSE; return FALSE;
} }
hasher->get_hash(hasher, cert->subjectPublicKey, subjectKeyID.ptr); encoding = keyid->get_encoding(keyid);
hasher->destroy(hasher); memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len);
return TRUE; return TRUE;
} }
@@ -1824,50 +1788,6 @@ static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
return top_gn; return top_gn;
} }
/**
* Parses an RSA public key
*/
bool parse_RSA_public_key(chunk_t blob, u_int level0, x509cert_t *cert)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success = FALSE;
parser = asn1_parser_create(pubkeyObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID) {
case PUB_KEY_RSA_PUBLIC_KEY:
cert->subjectPublicKey = object;
break;
case PUB_KEY_MODULUS:
if (object.len < RSA_MIN_OCTETS + 1)
{
plog(" " RSA_MIN_OCTETS_UGH);
goto end;
}
if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00))
{
plog(" " RSA_MAX_OCTETS_UGH);
goto end;
}
cert->modulus = object;
break;
case PUB_KEY_EXPONENT:
cert->publicExponent = object;
break;
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
return success;
}
/** /**
* Parses an X.509v3 certificate * Parses an X.509v3 certificate
*/ */
@@ -1927,30 +1847,11 @@ bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
DBG_log(" '%s'",buf) DBG_log(" '%s'",buf)
) )
break; break;
case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO:
if (asn1_parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION) cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
if (cert->public_key == NULL)
{ {
cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA;
}
else
{
plog(" unsupported public key algorithm");
goto end;
}
break;
case X509_OBJ_SUBJECT_PUBLIC_KEY:
if (object.len > 0 && *object.ptr == 0x00)
{
/* skip initial bit string octet defining 0 unused bits */
object = chunk_skip(object, 1);
if (!parse_RSA_public_key(object, level, cert))
{
goto end;
}
}
else
{
plog(" invalid RSA public key format");
goto end; goto end;
} }
break; break;
@@ -2116,8 +2017,8 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
DBG_log("issuer cacert found") DBG_log("issuer cacert found")
) )
if (!check_signature(cert->tbsCertificate, cert->signature if (!x509_check_signature(cert->tbsCertificate, cert->signature,
, cert->algorithm, cert->algorithm, issuer_cert)) cert->algorithm, issuer_cert))
{ {
plog("certificate signature is invalid"); plog("certificate signature is invalid");
unlock_authcert_list("verify_x509cert"); unlock_authcert_list("verify_x509cert");
@@ -2220,9 +2121,8 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
{ {
if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
{ {
unsigned keysize;
char keyid[KEYID_BUF];
u_char buf[BUF_LEN]; u_char buf[BUF_LEN];
public_key_t *key = cert->public_key;
cert_t c; cert_t c;
c.type = CERT_X509_SIGNATURE; c.type = CERT_X509_SIGNATURE;
@@ -2242,36 +2142,38 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
whack_log(RC_COMMENT, " subject: '%s'", buf); whack_log(RC_COMMENT, " subject: '%s'", buf);
dntoa(buf, BUF_LEN, cert->issuer); dntoa(buf, BUF_LEN, cert->issuer);
whack_log(RC_COMMENT, " issuer: '%s'", buf); whack_log(RC_COMMENT, " issuer: '%s'", buf);
datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':' datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':',
, buf, BUF_LEN); buf, BUF_LEN);
whack_log(RC_COMMENT, " serial: %s", buf); whack_log(RC_COMMENT, " serial: %s", buf);
form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s"
, 8*keysize, keyid
, cert->smartcard ? ", on smartcard" :
(has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " validity: not before %T %s", whack_log(RC_COMMENT, " validity: not before %T %s",
&cert->notBefore, utc, &cert->notBefore, utc,
(cert->notBefore < now)?"ok":"fatal (not valid yet)"); (cert->notBefore < now)?"ok":"fatal (not valid yet)");
whack_log(RC_COMMENT, " not after %T %s", whack_log(RC_COMMENT, " not after %T %s",
&cert->notAfter, utc, &cert->notAfter, utc,
check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
key_type_names, key->get_type(key),
key->get_keysize(key) * BITS_PER_BYTE,
cert->smartcard ? ", on smartcard" :
(has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " keyid: %Y",
key->get_id(key, ID_PUBKEY_INFO_SHA1));
if (cert->subjectKeyID.ptr != NULL) if (cert->subjectKeyID.ptr != NULL)
{ {
datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':' datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':',
, buf, BUF_LEN); buf, BUF_LEN);
whack_log(RC_COMMENT, " subjkey: %s", buf); whack_log(RC_COMMENT, " subjkey: %s", buf);
} }
if (cert->authKeyID.ptr != NULL) if (cert->authKeyID.ptr != NULL)
{ {
datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':',
, buf, BUF_LEN); buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf); whack_log(RC_COMMENT, " authkey: %s", buf);
} }
if (cert->authKeySerialNumber.ptr != NULL) if (cert->authKeySerialNumber.ptr != NULL)
{ {
datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len datatot(cert->authKeySerialNumber.ptr,
, ':', buf, BUF_LEN); cert->authKeySerialNumber.len, ':', buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf); whack_log(RC_COMMENT, " aserial: %s", buf);
} }
} }
+52 -52
View File
@@ -2,7 +2,7 @@
* Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
* Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
* Copyright (C) 2002 Mario Strasser * Copyright (C) 2002 Mario Strasser
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur * Copyright (C) 2000-2009 Andreas Steffen, Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
@@ -18,8 +18,10 @@
#ifndef _X509_H #ifndef _X509_H
#define _X509_H #define _X509_H
#include <credentials/keys/public_key.h>
#include <credentials/keys/private_key.h>
#include "constants.h" #include "constants.h"
#include "pkcs1.h"
#include "id.h" #include "id.h"
/* Definition of generalNames kinds */ /* Definition of generalNames kinds */
@@ -51,46 +53,42 @@ struct generalName {
typedef struct x509cert x509cert_t; typedef struct x509cert x509cert_t;
struct x509cert { struct x509cert {
x509cert_t *next; x509cert_t *next;
time_t installed; time_t installed;
int count; int count;
bool smartcard; bool smartcard;
u_char authority_flags; u_char authority_flags;
chunk_t certificate; chunk_t certificate;
chunk_t tbsCertificate; chunk_t tbsCertificate;
u_int version; u_int version;
chunk_t serialNumber; chunk_t serialNumber;
/* signature */ /* signature */
int sigAlg; int sigAlg;
chunk_t issuer; chunk_t issuer;
/* validity */ /* validity */
time_t notBefore; time_t notBefore;
time_t notAfter; time_t notAfter;
chunk_t subject; chunk_t subject;
/* subjectPublicKeyInfo */ public_key_t *public_key;
enum pubkey_alg subjectPublicKeyAlgorithm; /* issuerUniqueID */
chunk_t subjectPublicKey; /* subjectUniqueID */
chunk_t modulus; /* v3 extensions */
chunk_t publicExponent; /* extension */
/* issuerUniqueID */ /* extension */
/* subjectUniqueID */ /* extnID */
/* v3 extensions */ /* critical */
/* extension */ /* extnValue */
/* extension */ bool isCA;
/* extnID */ bool isOcspSigner; /* ocsp */
/* critical */ chunk_t subjectKeyID;
/* extnValue */ chunk_t authKeyID;
bool isCA; chunk_t authKeySerialNumber;
bool isOcspSigner; /* ocsp */ chunk_t accessLocation; /* ocsp */
chunk_t subjectKeyID; generalName_t *subjectAltName;
chunk_t authKeyID; generalName_t *crlDistributionPoints;
chunk_t authKeySerialNumber; /* signatureAlgorithm */
chunk_t accessLocation; /* ocsp */ int algorithm;
generalName_t *subjectAltName; chunk_t signature;
generalName_t *crlDistributionPoints;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
}; };
/* used for initialization */ /* used for initialization */
@@ -104,8 +102,8 @@ extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b);
extern void hex_str(chunk_t bin, chunk_t *str); extern void hex_str(chunk_t bin, chunk_t *str);
extern int dn_count_wildcards(chunk_t dn); extern int dn_count_wildcards(chunk_t dn);
extern int dntoa(char *dst, size_t dstlen, chunk_t dn); extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn,
, const char* null_dn); const char* null_dn);
extern err_t atodn(char *src, chunk_t *dn); extern err_t atodn(char *src, chunk_t *dn);
extern void gntoid(struct id *id, const generalName_t *gn); extern void gntoid(struct id *id, const generalName_t *gn);
extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID); extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID);
@@ -116,21 +114,23 @@ extern void parse_authorityKeyIdentifier(chunk_t blob, int level0
, chunk_t *authKeyID, chunk_t *authKeySerialNumber); , chunk_t *authKeyID, chunk_t *authKeySerialNumber);
extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit); extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
extern err_t check_validity(const x509cert_t *cert, time_t *until); extern err_t check_validity(const x509cert_t *cert, time_t *until);
extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
, int enc_alg, const x509cert_t *issuer_cert); const x509cert_t *issuer_cert);
extern chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
bool bit_string);
extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until); extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until);
extern x509cert_t* add_x509cert(x509cert_t *cert); extern x509cert_t* add_x509cert(x509cert_t *cert);
extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid,
, x509cert_t* chain); x509cert_t* chain);
extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
, const RSA_private_key_t *signer_key); private_key_t *signer_key);
extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames); extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames);
extern void share_x509cert(x509cert_t *cert); extern void share_x509cert(x509cert_t *cert);
extern void release_x509cert(x509cert_t *cert); extern void release_x509cert(x509cert_t *cert);
extern void free_x509cert(x509cert_t *cert); extern void free_x509cert(x509cert_t *cert);
extern void store_x509certs(x509cert_t **firstcert, bool strict); extern void store_x509certs(x509cert_t **firstcert, bool strict);
extern void list_x509cert_chain(const char *caption, x509cert_t* cert extern void list_x509cert_chain(const char *caption, x509cert_t* cert,
, u_char auth_flags, bool utc); u_char auth_flags, bool utc);
extern void list_x509_end_certs(bool utc); extern void list_x509_end_certs(bool utc);
extern void free_generalNames(generalName_t* gn, bool free_name); extern void free_generalNames(generalName_t* gn, bool free_name);
+3 -6
View File
@@ -1,5 +1,5 @@
ipsec_PROGRAMS = scepclient ipsec_PROGRAMS = scepclient
scepclient_SOURCES = scepclient.c rsakey.c rsakey.h pkcs10.c pkcs10.h scep.c scep.h loglite.c scepclient_SOURCES = scepclient.c pkcs10.c pkcs10.h scep.c scep.h loglite.c
PLUTODIR=$(top_srcdir)/src/pluto PLUTODIR=$(top_srcdir)/src/pluto
OPENACDIR=$(top_srcdir)/src/openac OPENACDIR=$(top_srcdir)/src/openac
@@ -28,7 +28,7 @@ LIBCRYPTOBUILDDIR=$(top_builddir)/src/libcrypto
scepclient_LDADD = \ scepclient_LDADD = \
ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o \ ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o \
mp_defs.o ocsp.o pem.o pgp.o pkcs1.o pkcs7.o smartcard.o x509.o \ mp_defs.o ocsp.o pem.o pgpcert.o pkcs7.o smartcard.o x509.o \
$(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \ $(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \
$(LIBFREESWANBUILDDIR)/libfreeswan.a \ $(LIBFREESWANBUILDDIR)/libfreeswan.a \
-lgmp -lgmp
@@ -77,10 +77,7 @@ ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
$(COMPILE) $(INCLUDES) -c -o $@ $< $(COMPILE) $(INCLUDES) -c -o $@ $<
pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h pgpcert.o : $(PLUTODIR)/pgpcert.c $(PLUTODIR)/pgpcert.h
$(COMPILE) $(INCLUDES) -c -o $@ $<
pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
$(COMPILE) $(INCLUDES) -c -o $@ $< $(COMPILE) $(INCLUDES) -c -o $@ $<
pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
+21 -17
View File
@@ -31,7 +31,6 @@
#include "../pluto/constants.h" #include "../pluto/constants.h"
#include "../pluto/defs.h" #include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/log.h" #include "../pluto/log.h"
#include "../pluto/x509.h" #include "../pluto/x509.h"
@@ -158,21 +157,25 @@ build_req_info_attributes(pkcs10_t* pkcs10)
static chunk_t static chunk_t
pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg) pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
{ {
RSA_public_key_t *rsak = (RSA_public_key_t *) pkcs10->private_key; chunk_t key = pkcs10->public_key->get_encoding(pkcs10->public_key);
chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm" chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
, ASN1_INTEGER_0 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
, pkcs10->subject asn1_bitstring("m", key));
, pkcs1_build_publicKeyInfo(rsak)
, build_req_info_attributes(pkcs10));
chunk_t signature = pkcs1_build_signature(cert_req_info chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm",
, signature_alg, pkcs10->private_key, TRUE); ASN1_INTEGER_0,
pkcs10->subject,
keyInfo,
build_req_info_attributes(pkcs10));
return asn1_wrap(ASN1_SEQUENCE, "mcm" chunk_t signature = x509_build_signature(cert_req_info, signature_alg,
, cert_req_info pkcs10->private_key, TRUE);
, asn1_algorithmIdentifier(signature_alg)
, signature); return asn1_wrap(ASN1_SEQUENCE, "mcm",
cert_req_info,
asn1_algorithmIdentifier(signature_alg),
signature);
} }
/** /**
@@ -189,14 +192,15 @@ pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
* @param[in] subjectAltNames linked list of subjectAltNames or NULL * @param[in] subjectAltNames linked list of subjectAltNames or NULL
* @return pointer to a #pkcs10_t object * @return pointer to a #pkcs10_t object
*/ */
pkcs10_t* pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public,
pkcs10_build(RSA_private_key_t *key, chunk_t subject, chunk_t challengePassword chunk_t subject, chunk_t challengePassword,
, generalName_t *subjectAltNames, int signature_alg) generalName_t *subjectAltNames, int signature_alg)
{ {
pkcs10_t *pkcs10 = malloc_thing(pkcs10_t); pkcs10_t *pkcs10 = malloc_thing(pkcs10_t);
pkcs10->subject = subject; pkcs10->subject = subject;
pkcs10->private_key = key; pkcs10->private_key = private;
pkcs10->public_key = public;
pkcs10->challengePassword = challengePassword; pkcs10->challengePassword = challengePassword;
pkcs10->subjectAltNames = subjectAltNames; pkcs10->subjectAltNames = subjectAltNames;
+14 -11
View File
@@ -23,8 +23,10 @@
#ifndef _PKCS10_H #ifndef _PKCS10_H
#define _PKCS10_H #define _PKCS10_H
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "../pluto/defs.h" #include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/x509.h" #include "../pluto/x509.h"
typedef struct pkcs10_struct pkcs10_t; typedef struct pkcs10_struct pkcs10_t;
@@ -38,20 +40,21 @@ typedef struct pkcs10_struct pkcs10_t;
* The RSA private key is needed to compute the signature of the given request * The RSA private key is needed to compute the signature of the given request
*/ */
struct pkcs10_struct { struct pkcs10_struct {
RSA_private_key_t *private_key; private_key_t *private_key;
chunk_t request; public_key_t *public_key;
chunk_t subject; chunk_t request;
chunk_t challengePassword; chunk_t subject;
generalName_t *subjectAltNames; chunk_t challengePassword;
generalName_t *subjectAltNames;
}; };
extern const pkcs10_t empty_pkcs10; extern const pkcs10_t empty_pkcs10;
extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames,
, generalNames_t kind, char *value); generalNames_t kind, char *value);
extern pkcs10_t* pkcs10_build(RSA_private_key_t *key, chunk_t subject extern pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public,
, chunk_t challengePassword, generalName_t *subjectAltNames chunk_t subject, chunk_t challengePassword,
, int signature_alg); generalName_t *subjectAltNames, int signature_alg);
extern void pkcs10_free(pkcs10_t *pkcs10); extern void pkcs10_free(pkcs10_t *pkcs10);
#endif /* _PKCS10_H */ #endif /* _PKCS10_H */
-313
View File
@@ -1,313 +0,0 @@
/**
* @file rsakey.c
* @brief Functions for RSA key generation
*/
/*
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <gmp.h>
#include <freeswan.h>
#include <library.h>
#include <crypto/rngs/rng.h>
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/mp_defs.h"
#include "../pluto/log.h"
#include "../pluto/pkcs1.h"
#include "rsakey.h"
/* Number of times the probabilistic primality test is applied */
#define PRIMECHECK_ROUNDS 30
/* Public exponent used for signature key generation */
#define PUBLIC_EXPONENT 0x10001
#ifndef DEV_RANDOM
#define DEV_RANDOM "/dev/random"
#endif
/**
* @brief Reads a specific number of bytes from a given device/file
*
* @param[in] nbytes number of bytes to read from random device
* @param[out] buf pointer to buffer where to write the data in.
* size of buffer has to be at least nbytes.
* @return TRUE, if succeeded, FALSE otherwise
*/
/**
* @brief initialize an mpz_t to a random number, specified bit count
*
* Converting the random value in a value of type mpz_t is done
* by creating a hexbuffer.
* Converting via hex is a bit weird, but it's the best route GMP gives us.
* Note that highmost and lowmost bits are forced on -- highmost to give a
* number of exactly the specified length, lowmost so it is an odd number.
*
* @param[out] var uninitialized mpz_t to store th random number in
* @param[in] nbits length of var in bits (known to be a multiple of BITS_PER_BYTE)
* @return TRUE on success, FALSE otherwise
*/
static bool init_random(mpz_t var, int nbits)
{
size_t nbytes = (size_t)(nbits/BITS_PER_BYTE);
char random_buf[RSA_MAX_OCTETS/2];
rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
if (!rng)
{
return FALSE;
}
assert(nbytes <= sizeof(random_buf));
rng->get_bytes(rng, nbytes, random_buf);
rng->destroy(rng);
random_buf[0] |= 01 << (BITS_PER_BYTE-1); /* force high bit on */
random_buf[nbytes-1] |= 01; /* force low bit on */
n_to_mpz(var, random_buf, nbytes);
return TRUE;
}
/**
* @brief initialize an mpz_t to a random prime of specified size
*
* Efficiency tweak: we reject candidates that are 1 higher than a multiple
* of e, since they will make the internal modulus not relatively prime to e.
*
* @param[out] var mpz_t variable to initialize
* @param[in] nbits length of given prime in bits (known to be a multiple of BITS_PER_BYTE)
* @param[in] eval E-Value, 0 means don't bother w. tweak
* @return 1 on success, 0 otherwise
*/
static bool init_prime(mpz_t var, int nbits, int eval)
{
unsigned long tries;
size_t len;
/* get a random value of nbits length */
if (!init_random(var, nbits))
return FALSE;
/* check if odd number */
assert(mpz_fdiv_ui(var, 2) == 1);
DBG(DBG_CONTROLMORE,
DBG_log("looking for a prime starting there (can take a while)...")
)
tries = 1;
while (mpz_fdiv_ui(var, eval) == 1
|| !mpz_probab_prime_p(var, PRIMECHECK_ROUNDS))
{
/* not a prime, increase by 2 */
mpz_add_ui(var, var, 2);
tries++;
}
len = mpz_sizeinbase(var, 2);
/* check bit length of primee */
assert(len == (size_t)nbits || len == (size_t)(nbits+1));
if (len == (size_t)(nbits+1))
{
DBG(DBG_CONTROLMORE,
DBG_log("carry out occurred (!), retrying...")
)
mpz_clear(var);
/* recursive call */
return init_prime(var, nbits, eval);
}
DBG(DBG_CONTROLMORE,
DBG_log("found it after %lu tries.",tries)
)
return TRUE;
}
/**
* @brief Generate a RSA key usable for encryption
*
* Generate an RSA key usable for encryption. All the
* values of the RSA key are filled into mpz_t parameters.
* These mpz_t parameters must not be initialized and have
* to be cleared with mpz_clear after using.
*
* @param[in] nbits size of rsa key in bits
* @return RSA_public_key_t containing the generated RSA key
*/
err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key)
{
mpz_t p, q, n, e, d, exp1, exp2, coeff;
mpz_t m, q1, t; /* temporary variables*/
DBG(DBG_CONTROL,
DBG_log("generating %d bit RSA key:", nbits)
)
if (nbits <= 0)
return "negative rsa key length!";
/* Get values of primes p and q */
DBG(DBG_CONTROLMORE,
DBG_log("initialize prime p")
)
if (!init_prime(p, nbits/2, PUBLIC_EXPONENT))
return "could not generate prime p";
DBG(DBG_CONTROLMORE,
DBG_log("initialize prime q")
)
if (!init_prime(q, nbits/2, PUBLIC_EXPONENT))
return "could not generate prime q";
mpz_init(t);
/* Swapping primes so p is larger then q */
if (mpz_cmp(p, q) < 0)
{
DBG(DBG_CONTROLMORE,
DBG_log("swapping primes so p is the larger...")
);
mpz_set(t, p);
mpz_set(p, q);
mpz_set(q, t);
}
DBG(DBG_CONTROLMORE,
DBG_log("computing modulus...")
)
mpz_init(n);
/* n = p*q */
mpz_mul(n, p, q);
/* Assign e the value of defined PUBLIC_EXPONENT */
mpz_init_set_ui(e, PUBLIC_EXPONENT);
DBG(DBG_CONTROLMORE,
DBG_log("computing lcm(p-1, q-1)...")
)
/* m = p */
mpz_init_set(m, p);
/* m = m-1 */
mpz_sub_ui(m, m, 1);
/* q1 = q */
mpz_init_set(q1, q);
/* q1 = q1-1 */
mpz_sub_ui(q1, q1, 1);
/* t = gcd(p-1, q-1) */
mpz_gcd(t, m, q1);
/* m = (p-1)*(q-1) */
mpz_mul(m, m, q1);
/* m = m / t */
mpz_divexact(m, m, t);
/* t = gcd(m, e) (greatest common divisor) */
mpz_gcd(t, m, e);
/* m and e relatively prime */
assert(mpz_cmp_ui(t, 1) == 0);
/* decryption key */
DBG(DBG_CONTROLMORE,
DBG_log("computing d...")
)
mpz_init(d);
/* e has an inverse mod m */
assert(mpz_invert(d, e, m));
/* make sure d is positive */
if (mpz_cmp_ui(d, 0) < 0)
mpz_add(d, d, m);
/* d has to be positive */
assert(mpz_cmp(d, m) < 0);
/* the speedup hacks */
DBG(DBG_CONTROLMORE,
DBG_log("computing exp1, exp1, coeff...")
)
mpz_init(exp1);
/* t = p-1 */
mpz_sub_ui(t, p, 1);
/* exp1 = d mod p-1 */
mpz_mod(exp1, d, t);
mpz_init(exp2);
/* t = q-1 */
mpz_sub_ui(t, q, 1);
/* exp2 = d mod q-1 */
mpz_mod(exp2, d, t);
mpz_init(coeff);
/* coeff = q^-1 mod p */
mpz_invert(coeff, q, p);
/* make sure coeff is positive */
if (mpz_cmp_ui(coeff, 0) < 0)
mpz_add(coeff, coeff, p);
/* coeff has to be positive */
assert(mpz_cmp(coeff, p) < 0);
/* Clear temporary variables */
mpz_clear(q1);
mpz_clear(m);
mpz_clear(t);
/* form FreeS/WAN keyid */
{
size_t e_len = (mpz_sizeinbase(e,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
size_t n_len = (mpz_sizeinbase(n,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
chunk_t e_ch = mpz_to_n(e, e_len);
chunk_t n_ch = mpz_to_n(n, n_len);
form_keyid(e_ch, n_ch, key->pub.keyid, &key->pub.k);
free(e_ch.ptr);
free(n_ch.ptr);
}
/* fill in the elements of the RSA private key */
key->p = *p;
key->q = *q;
key->pub.n = *n;
key->pub.e = *e;
key->d = *d;
key->dP = *exp1;
key->dQ = *exp2;
key->qInv = *coeff;
DBG(DBG_CONTROL,
DBG_log("RSA key *%s generated with %d bits", key->pub.keyid
, (int)mpz_sizeinbase(n,2))
)
#ifdef DEBUG
DBG(DBG_PRIVATE,
RSA_show_private_key(key)
)
#endif
return NULL;
}
+26 -19
View File
@@ -34,7 +34,6 @@
#include "../pluto/constants.h" #include "../pluto/constants.h"
#include "../pluto/defs.h" #include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/fetch.h" #include "../pluto/fetch.h"
#include "../pluto/log.h" #include "../pluto/log.h"
@@ -266,35 +265,43 @@ end:
* Generates a unique fingerprint of the pkcs10 request * Generates a unique fingerprint of the pkcs10 request
* by computing an MD5 hash over it * by computing an MD5 hash over it
*/ */
void scep_generate_pkcs10_fingerprint(chunk_t pkcs10, chunk_t *fingerprint) chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10)
{ {
char buf[HASH_SIZE_MD5]; char digest_buf[HASH_SIZE_MD5];
chunk_t digest = { buf, sizeof(buf) }; chunk_t digest = chunk_from_buf(digest_buf);
hasher_t *hasher;
/* the fingerprint is the MD5 hash in hexadecimal format */ hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
compute_digest(pkcs10, OID_MD5, &digest); hasher->get_hash(hasher, pkcs10, digest_buf);
fingerprint->len = 2*digest.len; hasher->destroy(hasher);
fingerprint->ptr = malloc(fingerprint->len + 1);
datatot(digest.ptr, digest.len, 16, fingerprint->ptr, fingerprint->len + 1); return chunk_to_hex(digest, NULL, FALSE);
} }
/** /**
* Generate a transaction id as the MD5 hash of an public key * Generate a transaction id as the MD5 hash of an public key
* the transaction id is also used as a unique serial number * the transaction id is also used as a unique serial number
*/ */
void scep_generate_transaction_id(const RSA_public_key_t *rsak, void scep_generate_transaction_id(public_key_t *key, chunk_t *transID,
chunk_t *transID, chunk_t *serialNumber) chunk_t *serialNumber)
{ {
char buf[HASH_SIZE_MD5]; char digest_buf[HASH_SIZE_MD5];
chunk_t digest = chunk_from_buf(digest_buf);
chunk_t digest = { buf, sizeof(buf) }; chunk_t keyEncoding, keyInfo;
chunk_t public_key = pkcs1_build_publicKeyInfo(rsak); hasher_t *hasher;
bool msb_set; bool msb_set;
u_char *pos; u_char *pos;
keyEncoding = key->get_encoding(key);
compute_digest(public_key, OID_MD5, &digest); keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
free(public_key.ptr); asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
asn1_bitstring("m", keyEncoding));
hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
hasher->get_hash(hasher, keyInfo, digest_buf);
hasher->destroy(hasher);
free(keyInfo.ptr);
/* is the most significant bit of the digest set? */ /* is the most significant bit of the digest set? */
msb_set = (*digest.ptr & 0x80) == 0x80; msb_set = (*digest.ptr & 0x80) == 0x80;
@@ -376,7 +383,7 @@ chunk_t scep_senderNonce_attribute(void)
chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg, chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
const x509cert_t *enc_cert, int enc_alg, const x509cert_t *enc_cert, int enc_alg,
const x509cert_t *signer_cert, int digest_alg, const x509cert_t *signer_cert, int digest_alg,
const RSA_private_key_t *private_key) private_key_t *private_key)
{ {
chunk_t envelopedData, attributes, request; chunk_t envelopedData, attributes, request;
+13 -13
View File
@@ -24,7 +24,6 @@
#define _SCEP_H #define _SCEP_H
#include "../pluto/defs.h" #include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/pkcs7.h" #include "../pluto/pkcs7.h"
/* supported SCEP operation types */ /* supported SCEP operation types */
@@ -74,20 +73,21 @@ typedef struct {
extern const scep_attributes_t empty_scep_attributes; extern const scep_attributes_t empty_scep_attributes;
extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs); extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs);
extern void scep_generate_pkcs10_fingerprint(chunk_t pkcs10 extern void scep_generate_transaction_id(public_key_t *key,
, chunk_t *fingerprint); chunk_t *transID,
extern void scep_generate_transaction_id(const RSA_public_key_t *rsak chunk_t *serialNumber);
, chunk_t *transID, chunk_t *serialNumber); extern chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10);
extern chunk_t scep_transId_attribute(chunk_t transaction_id); extern chunk_t scep_transId_attribute(chunk_t transaction_id);
extern chunk_t scep_messageType_attribute(scep_msg_t m); extern chunk_t scep_messageType_attribute(scep_msg_t m);
extern chunk_t scep_senderNonce_attribute(void); extern chunk_t scep_senderNonce_attribute(void);
extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
, const x509cert_t *enc_cert, int enc_alg const x509cert_t *enc_cert, int enc_alg,
, const x509cert_t *signer_cert, int digest_alg const x509cert_t *signer_cert, int digest_alg,
, const RSA_private_key_t *private_key); private_key_t *private_key);
extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op,
, bool http_get_request, chunk_t *response); bool http_get_request, chunk_t *response);
extern err_t scep_parse_response(chunk_t response, chunk_t transID extern err_t scep_parse_response(chunk_t response, chunk_t transID,
, contentInfo_t *data, scep_attributes_t *attrs, x509cert_t *signer_cert); contentInfo_t *data, scep_attributes_t *attrs,
x509cert_t *signer_cert);
#endif /* _SCEP_H */ #endif /* _SCEP_H */
+24 -25
View File
@@ -42,15 +42,15 @@
#include <asn1/oid.h> #include <asn1/oid.h>
#include <utils/optionsfrom.h> #include <utils/optionsfrom.h>
#include <utils/enumerator.h> #include <utils/enumerator.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "../pluto/constants.h" #include "../pluto/constants.h"
#include "../pluto/defs.h" #include "../pluto/defs.h"
#include "../pluto/log.h" #include "../pluto/log.h"
#include "../pluto/pkcs1.h"
#include "../pluto/pkcs7.h" #include "../pluto/pkcs7.h"
#include "../pluto/certs.h" #include "../pluto/certs.h"
#include "rsakey.h"
#include "pkcs10.h" #include "pkcs10.h"
#include "scep.h" #include "scep.h"
@@ -120,7 +120,8 @@ options_t *options;
* Global variables * Global variables
*/ */
RSA_private_key_t *private_key = NULL; private_key_t *private_key = NULL;
public_key_t *public_key = NULL;
chunk_t pkcs1; chunk_t pkcs1;
chunk_t pkcs7; chunk_t pkcs7;
@@ -150,11 +151,8 @@ exit_scepclient(err_t message, ...)
{ {
int status = 0; int status = 0;
if (private_key != NULL) DESTROY_IF(private_key);
{ DESTROY_IF(public_key);
free_RSA_private_content(private_key);
free(private_key);
}
free(pkcs1.ptr); free(pkcs1.ptr);
free(pkcs7.ptr); free(pkcs7.ptr);
free(subject.ptr); free(subject.ptr);
@@ -784,24 +782,27 @@ int main(int argc, char **argv)
/* /*
* input of PKCS#1 file * input of PKCS#1 file
*/ */
private_key = malloc_thing(RSA_private_key_t);
if (filetype_in & PKCS1) /* load an RSA key pair from file */ if (filetype_in & PKCS1) /* load an RSA key pair from file */
{ {
prompt_pass_t pass = { "", FALSE, STDIN_FILENO }; prompt_pass_t pass = { "", FALSE, STDIN_FILENO };
char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1); char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
ugh = load_rsa_private_key(path, &pass, private_key); private_key = load_private_key(path, &pass, KEY_RSA);
} }
else /* generate an RSA key pair */ else /* generate an RSA key pair */
{ {
ugh = generate_rsa_private_key(rsa_keylength, private_key); private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_KEY_SIZE, rsa_keylength,
BUILD_END);
} }
if (ugh != NULL) if (private_key == NULL)
exit_scepclient(ugh); {
exit_scepclient("no RSA private key available");
}
public_key = private_key->get_public_key(private_key);
/* check for minimum key length */ /* check for minimum key length */
if ((private_key->pub.k) < RSA_MIN_OCTETS) if (private_key->get_keysize(private_key) < RSA_MIN_OCTETS)
{ {
exit_scepclient("length of RSA key has to be at least %d bits" exit_scepclient("length of RSA key has to be at least %d bits"
,RSA_MIN_OCTETS * BITS_PER_BYTE); ,RSA_MIN_OCTETS * BITS_PER_BYTE);
@@ -855,10 +856,11 @@ int main(int argc, char **argv)
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("building pkcs10 object:") DBG_log("building pkcs10 object:")
) )
pkcs10 = pkcs10_build(private_key, subject, challengePassword pkcs10 = pkcs10_build(private_key, public_key, subject,
, subjectAltNames, pkcs10_signature_alg); challengePassword, subjectAltNames,
scep_generate_pkcs10_fingerprint(pkcs10->request, &fingerprint); pkcs10_signature_alg);
plog(" fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr); fingerprint = scep_generate_pkcs10_fingerprint(pkcs10->request);
plog(" fingerprint: %s", fingerprint.ptr);
} }
/* /*
@@ -889,7 +891,7 @@ int main(int argc, char **argv)
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("building pkcs1 object:") DBG_log("building pkcs1 object:")
) )
pkcs1 = pkcs1_build_private_key(private_key); pkcs1 = private_key->get_encoding(private_key);
if (!chunk_write(pkcs1, path, "pkcs1", 0066, force)) if (!chunk_write(pkcs1, path, "pkcs1", 0066, force))
exit_scepclient("could not write pkcs1 file '%s'", path); exit_scepclient("could not write pkcs1 file '%s'", path);
@@ -902,8 +904,7 @@ int main(int argc, char **argv)
exit_scepclient(NULL); /* no further output required */ exit_scepclient(NULL); /* no further output required */
} }
scep_generate_transaction_id((const RSA_public_key_t *)private_key scep_generate_transaction_id(public_key, &transID, &serialNumber);
, &transID, &serialNumber);
plog(" transaction ID: %.*s", (int)transID.len, transID.ptr); plog(" transaction ID: %.*s", (int)transID.len, transID.ptr);
/* generate a self-signed X.509 certificate */ /* generate a self-signed X.509 certificate */
@@ -918,9 +919,7 @@ int main(int argc, char **argv)
: x509_signer->notBefore + validity; : x509_signer->notBefore + validity;
x509_signer->subject = subject; x509_signer->subject = subject;
x509_signer->subjectAltName = subjectAltNames; x509_signer->subjectAltName = subjectAltNames;
build_x509cert(x509_signer, public_key, private_key);
build_x509cert(x509_signer, (const RSA_public_key_t *)private_key
, private_key);
/* /*
* output of self-signed X.509 certificate file * output of self-signed X.509 certificate file
+15 -3
View File
@@ -6,12 +6,11 @@ charon {
threads = 16 threads = 16
# plugins to load in charon # plugins to load in charon
# load = aes des gmp hmac md5 random sha1 sha2 pubkey xcbc x509 stroke # load = aes des sha1 md5 sha2 hmac gmp random pubkey xcbc x509 stroke
plugins { plugins {
sql { sql {
# loglevel to log into sql database # loglevel to log into sql database
loglevel = -1 loglevel = -1
@@ -23,3 +22,16 @@ charon {
# ... # ...
} }
pluto {
# plugins to load in pluto
# load = aes des sha1 md5 sha2 hmac gmp random pubkey
}
libstrongswan {
# set to no, the DH exponent size is optimized
# dh_exponent_ansi_x9_42 = no
}