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/ocsp_request.h \
credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \
fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \
database/database.h database/database_factory.h database/database_factory.c \
fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \
pgp/pgp.c pgp/pgp.h \
utils.h utils.c \
utils/host.c utils/host.h \
utils/identification.c utils/identification.h \
+37 -2
View File
@@ -255,7 +255,7 @@ chunk_t asn1_build_known_oid(int n)
/*
* Defined in header.
*/
u_int asn1_length(chunk_t *blob)
size_t asn1_length(chunk_t *blob)
{
u_char n;
size_t len;
@@ -675,7 +675,7 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
}
/**
* Build an ASN.1 BITSTRING object
* Build an ASN.1 BIT_STRING object
*/
chunk_t asn1_bitstring(const char *mode, chunk_t content)
{
@@ -691,6 +691,41 @@ chunk_t asn1_bitstring(const char *mode, chunk_t content)
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.
* 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
* @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
@@ -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);
/**
* 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
*
+2
View File
@@ -20,6 +20,8 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_AGENT_SOCKET",
"BUILD_BLOB_ASN1_DER",
"BUILD_BLOB_ASN1_PEM",
"BUILD_BLOB_PGP",
"BUILD_BLOB_RFC_3110",
"BUILD_KEY_SIZE",
"BUILD_SIGNING_KEY",
"BUILD_SIGNING_CERT",
+7 -3
View File
@@ -38,14 +38,18 @@ typedef builder_t* (*builder_constructor_t)(int subtype);
* Parts to build credentials from.
*/
enum builder_part_t {
/** path to a file containing an ASN1 blob, char* */
/** path to a file containing an ASN.1 blob, char* */
BUILD_FROM_FILE,
/** unix socket of a ssh/pgp agent, char* */
BUILD_AGENT_SOCKET,
/** DER encoded ASN1 blob, chunk_t */
/** DER encoded ASN.1 blob, chunk_t */
BUILD_BLOB_ASN1_DER,
/** PEM encoded ASN1 blob, null terminated char* */
/** PEM encoded ASN.1 blob, null terminated char* */
BUILD_BLOB_ASN1_PEM,
/** OpenPGP key blob, chunk_t */
BUILD_BLOB_PGP,
/** RFC 3110 DNS public key blob, chunk_t */
BUILD_BLOB_RFC_3110,
/** key size in bits, as used for key generation, u_int */
BUILD_KEY_SIZE,
/** private key to use for signing, private_key_t* */
@@ -156,6 +156,8 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
case BUILD_END:
break;
case BUILD_BLOB_ASN1_DER:
case BUILD_BLOB_PGP:
case BUILD_BLOB_RFC_3110:
case BUILD_SERIAL:
builder->add(builder, part, va_arg(args, chunk_t));
continue;
@@ -79,6 +79,14 @@ struct private_key_t {
*/
public_key_t* (*get_public_key)(private_key_t *this);
/**
* Check if two private keys are equal.
*
* @param other other private key
* @return TRUE, if equality
*/
bool (*equals) (private_key_t *this, private_key_t *other);
/**
* Check if a private key belongs to a public key.
*
@@ -15,13 +15,15 @@
#include "public_key.h"
ENUM(key_type_names, KEY_RSA, KEY_ECDSA,
ENUM(key_type_names, KEY_RSA, KEY_DSA,
"RSA",
"ECDSA"
"ECDSA",
"DSA"
);
ENUM(signature_scheme_names, SIGN_DEFAULT, SIGN_ECDSA_521,
"DEFAULT",
"RSA_EMSA_PKCS1_NULL",
"RSA_EMSA_PKCS1_MD5",
"RSA_EMSA_PKCS1_SHA1",
"RSA_EMSA_PKCS1_SHA256",
+33 -19
View File
@@ -34,12 +34,14 @@ typedef enum signature_scheme_t signature_scheme_t;
*/
enum key_type_t {
/** key type wildcard */
KEY_ANY,
KEY_ANY = 0,
/** RSA crypto system as in PKCS#1 */
KEY_RSA,
KEY_RSA = 1,
/** ECDSA as in ANSI X9.62 */
KEY_ECDSA,
/** DSS, ElGamal, ... */
KEY_ECDSA = 2,
/** DSA */
KEY_DSA = 3,
/** ElGamal, ... */
};
/**
@@ -50,29 +52,33 @@ extern enum_name_t *key_type_names;
/**
* Signature scheme for signature creation
*
* EMSA-PKCS1 signatures are from the PKCS#1 standard. They include
* the ASN1-OID of the used hash algorithm.
* EMSA-PKCS1 signatures are defined in PKCS#1 standard.
* A prepended ASN.1 encoded digestInfo field contains the
* OID of the used hash algorithm. The ASN.1 type of the PKCS#7
* variants is OCTET_STRING instead of the default BIT_STRING.
*/
enum signature_scheme_t {
/** default scheme of that underlying crypto system */
/** Default scheme of the underlying crypto system */
SIGN_DEFAULT,
/** EMSA-PKCS1 with MD5 */
/** EMSA-PKCS1_v1.5 signature over digest without digestInfo */
SIGN_RSA_EMSA_PKCS1_NULL,
/** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and MD5 */
SIGN_RSA_EMSA_PKCS1_MD5,
/** EMSA-PKCS1 signature as in PKCS#1 standard using SHA1 as hash. */
/** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-1 */
SIGN_RSA_EMSA_PKCS1_SHA1,
/** EMSA-PKCS1 signature as in PKCS#1 standard using SHA256 as hash. */
/** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-256 */
SIGN_RSA_EMSA_PKCS1_SHA256,
/** EMSA-PKCS1 signature as in PKCS#1 standard using SHA384 as hash. */
/** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-384 */
SIGN_RSA_EMSA_PKCS1_SHA384,
/** EMSA-PKCS1 signature as in PKCS#1 standard using SHA512 as hash. */
/** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-512 */
SIGN_RSA_EMSA_PKCS1_SHA512,
/** ECDSA using SHA-1 as hash. */
/** ECDSA with SHA-1 */
SIGN_ECDSA_WITH_SHA1,
/** ECDSA with SHA-256 on the P-256 curve as in RFC 4754 */
/** ECDSA on the P-256 curve with SHA-256 as in RFC 4754 */
SIGN_ECDSA_256,
/** ECDSA with SHA-384 on the P-384 curve as in RFC 4754 */
/** ECDSA on the P-384 curve with SHA-384 as in RFC 4754 */
SIGN_ECDSA_384,
/** ECDSA with SHA-512 on the P-521 curve as in RFC 4754 */
/** ECDSA on the P-521 curve with SHA-512 as in RFC 4754 */
SIGN_ECDSA_521,
};
@@ -107,12 +113,20 @@ struct public_key_t {
/**
* Encrypt a chunk of data.
*
* @param crypto chunk containing plaintext data
* @param plain where to allocate encrypted data
* @param plain chunk containing plaintext data
* @param crypto where to allocate encrypted data
* @return TRUE if data successfully encrypted
*/
bool (*encrypt)(public_key_t *this, chunk_t crypto, chunk_t *plain);
bool (*encrypt)(public_key_t *this, chunk_t plain, chunk_t *crypto);
/**
* Check if two public keys are equal.
*
* @param other other public key
* @return TRUE, if equality
*/
bool (*equals)(public_key_t *this, public_key_t *other);
/**
* Get the strength of the key in bytes.
*
@@ -1,11 +1,6 @@
/**
* @file rsakey.h
* @brief Functions for RSA key generation
*/
/*
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
* Copyright (C) 2005 Jan Hutter, Martin Willi
/*
* Copyright (C) 2002-2009 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,12 +13,40 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "pgp.h"
#ifndef RSAKEY_H_
#define RSAKEY_H_
ENUM(pgp_sym_alg_names, PGP_SYM_ALG_PLAIN, PGP_SYM_ALG_TWOFISH,
"PLAINTEXT",
"IDEA",
"3DES",
"CAST5",
"BLOWFISH",
"SAFER",
"DES",
"AES_128",
"AES_192",
"AES_256",
"TWOFISH"
);
#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/asn1.h>
#include <asn1/asn1_parser.h>
#include <pgp/pgp.h>
/**
* Public exponent to use for key generation.
@@ -110,11 +111,12 @@ struct private_gmp_rsa_private_key_t {
};
/**
* shared functions, implemented in gmp_rsa_public_key.c
* Shared functions defined in gmp_rsa_public_key.c
*/
bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid,
identification_t **keyid_info);
gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e);
extern bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e,
identification_t **keyid,
identification_t **keyid_info);
extern gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e);
/**
* Auxiliary function overwriting private key material with zero bytes
@@ -215,32 +217,36 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this,
hash_algorithm_t hash_algorithm,
chunk_t data, chunk_t *signature)
{
hasher_t *hasher;
chunk_t em, digestInfo, hash;
int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
if (hash_oid == OID_UNKNOWN)
{
return FALSE;
}
chunk_t digestInfo = chunk_empty;
chunk_t em;
/* get hasher */
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
if (hasher == NULL)
if (hash_algorithm != HASH_UNKNOWN)
{
return FALSE;
hasher_t *hasher;
chunk_t hash;
int hash_oid = hasher_algorithm_to_oid(hash_algorithm);
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:
* EM = 0x00 || 0x01 || PS || 0x00 || T.
@@ -255,9 +261,9 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this,
/* set magic bytes */
*(em.ptr) = 0x00;
*(em.ptr+1) = 0x01;
*(em.ptr + em.len - digestInfo.len - 1) = 0x00;
*(em.ptr + em.len - data.len - 1) = 0x00;
/* set DER-encoded hash */
memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len);
memcpy(em.ptr + em.len - data.len, data.ptr, data.len);
/* build signature */
*signature = rsasp1(this, em);
@@ -269,7 +275,7 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this,
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.get_type.
*/
static key_type_t get_type(private_gmp_rsa_private_key_t *this)
{
@@ -277,15 +283,16 @@ static key_type_t get_type(private_gmp_rsa_private_key_t *this)
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.sign.
*/
static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme,
chunk_t data, chunk_t *signature)
{
switch (scheme)
{
case SIGN_RSA_EMSA_PKCS1_NULL:
return build_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
case SIGN_DEFAULT:
/* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1:
return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256:
@@ -304,7 +311,7 @@ static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme,
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.decrypt.
*/
static bool decrypt(private_gmp_rsa_private_key_t *this,
chunk_t crypto, chunk_t *plain)
@@ -314,7 +321,7 @@ static bool decrypt(private_gmp_rsa_private_key_t *this,
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.get_keysize.
*/
static size_t get_keysize(private_gmp_rsa_private_key_t *this)
{
@@ -322,7 +329,7 @@ static size_t get_keysize(private_gmp_rsa_private_key_t *this)
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.get_id.
*/
static identification_t* get_id(private_gmp_rsa_private_key_t *this,
id_type_t type)
@@ -347,7 +354,35 @@ static gmp_rsa_public_key_t* get_public_key(private_gmp_rsa_private_key_t *this)
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.equals.
*/
static bool equals(private_gmp_rsa_private_key_t *this, private_key_t *other)
{
identification_t *keyid;
if (&this->public.interface == other)
{
return TRUE;
}
if (other->get_type(other) != KEY_RSA)
{
return FALSE;
}
keyid = other->get_id(other, ID_PUBKEY_SHA1);
if (keyid && keyid->equals(keyid, this->keyid))
{
return TRUE;
}
keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1);
if (keyid && keyid->equals(keyid, this->keyid_info))
{
return TRUE;
}
return FALSE;
}
/**
* Implementation of gmp_rsa_private_key.belongs_to.
*/
static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public)
{
@@ -371,19 +406,27 @@ static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public
}
/**
* convert a MP integer into a DER coded ASN.1 object
* Convert a MP integer into a chunk_t
*/
chunk_t gmp_mpz_to_asn1(const mpz_t value)
chunk_t gmp_mpz_to_chunk(const mpz_t value)
{
chunk_t n;
n.len = 1 + mpz_sizeinbase(value, 2) / 8; /* size in bytes */
n.len = 1 + mpz_sizeinbase(value, 2) / BITS_PER_BYTE;
n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value);
if (n.ptr == NULL)
{ /* if we have zero in "value", gmp returns NULL */
n.len = 0;
}
return asn1_wrap(ASN1_INTEGER, "m", n);
return n;
}
/**
* Convert a MP integer into a DER coded ASN.1 object
*/
chunk_t gmp_mpz_to_asn1(const mpz_t value)
{
return asn1_wrap(ASN1_INTEGER, "m", gmp_mpz_to_chunk(value));
}
/**
@@ -404,7 +447,7 @@ static chunk_t get_encoding(private_gmp_rsa_private_key_t *this)
}
/**
* Implementation of gmp_rsa_private_key.destroy.
* Implementation of gmp_rsa_private_key.get_ref.
*/
static private_gmp_rsa_private_key_t* get_ref(private_gmp_rsa_private_key_t *this)
{
@@ -445,14 +488,14 @@ static status_t check(private_gmp_rsa_private_key_t *this)
/* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
* We actually require more (for security).
*/
if (this->k < 512/8)
if (this->k < 512 / BITS_PER_BYTE)
{
DBG1("key shorter than 512 bits");
return FAILED;
}
/* we picked a max modulus size to simplify buffer allocation */
if (this->k > 8192/8)
if (this->k > 8192 / BITS_PER_BYTE)
{
DBG1("key larger than 8192 bits");
return FAILED;
@@ -540,16 +583,17 @@ static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void)
{
private_gmp_rsa_private_key_t *this = malloc_thing(private_gmp_rsa_private_key_t);
this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
this->public.interface.get_type = (key_type_t (*) (private_key_t*))get_type;
this->public.interface.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign;
this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt;
this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize;
this->public.interface.get_id = (identification_t* (*) (private_key_t*, id_type_t))get_id;
this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key;
this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals;
this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to;
this->public.interface.get_encoding = (chunk_t (*) (private_key_t*))get_encoding;
this->public.interface.get_ref = (private_key_t* (*) (private_key_t*))get_ref;
this->public.interface.destroy = (void (*) (private_key_t*))destroy;
this->keyid = NULL;
this->keyid_info = NULL;
@@ -567,7 +611,7 @@ static gmp_rsa_private_key_t *generate(size_t key_size)
mpz_t m, q1, t;
private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty();
key_size = key_size / 8;
key_size = key_size / BITS_PER_BYTE;
/* Get values of primes p and q */
if (compute_prime(this, key_size/2, &p) != SUCCESS)
@@ -678,7 +722,7 @@ static const asn1Object_t privkeyObjects[] = {
/**
* load private key from a ASN1 encoded blob
*/
static gmp_rsa_private_key_t *load(chunk_t blob)
static gmp_rsa_private_key_t *load_asn1_der(chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
@@ -706,6 +750,7 @@ static gmp_rsa_private_key_t *load(chunk_t blob)
case PRIV_KEY_VERSION:
if (object.len > 0 && *object.ptr != 0)
{
DBG1("PKCS#1 private key format is not version 1");
goto end;
}
break;
@@ -755,7 +800,6 @@ end:
destroy(this);
return NULL;
}
if (check(this) != SUCCESS)
{
destroy(this);
@@ -764,6 +808,125 @@ end:
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;
/**
* 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);
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;
}
@@ -28,11 +28,7 @@
#include <asn1/asn1_parser.h>
#include <asn1/pem.h>
#include <crypto/hashers/hasher.h>
/**
* defined in gmp_rsa_private_key.c
*/
extern chunk_t gmp_mpz_to_asn1(const mpz_t value);
#include <pgp/pgp.h>
typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
@@ -76,6 +72,12 @@ struct private_gmp_rsa_public_key_t {
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.
*/
@@ -189,13 +191,24 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
goto end;
}
/* parse ASN.1-based digestInfo */
{
if (algorithm == HASH_UNKNOWN)
{ /* IKEv1 signatures without digestInfo */
if (em.len != data.len)
{
DBG1("hash size in signature is %u bytes instead of %u bytes",
em.len, data.len);
goto end;
}
success = memeq(em.ptr, data.ptr, data.len);
}
else
{ /* IKEv2 and X.509 certificate signatures */
asn1_parser_t *parser;
chunk_t object;
int objectID;
hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
DBG2("signature verification:");
parser = asn1_parser_create(digestInfoObjects, em);
while (parser->iterate(parser, &objectID, &object))
@@ -218,8 +231,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
parser->get_level(parser)+1, NULL);
hash_algorithm = hasher_algorithm_from_oid(hash_oid);
if (hash_algorithm == HASH_UNKNOWN ||
(algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
if (hash_algorithm == HASH_UNKNOWN || hash_algorithm != algorithm)
{
DBG1("expected hash algorithm %N, but found %N (OID: %#B)",
hash_algorithm_names, algorithm,
@@ -287,7 +299,8 @@ static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme
{
switch (scheme)
{
case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */
case SIGN_DEFAULT:
case SIGN_RSA_EMSA_PKCS1_NULL:
return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
case SIGN_RSA_EMSA_PKCS1_MD5:
return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
@@ -315,6 +328,34 @@ static bool encrypt_(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t
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.
*/
@@ -323,6 +364,34 @@ static size_t get_keysize(private_gmp_rsa_public_key_t *this)
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.
*/
@@ -335,6 +404,8 @@ static identification_t *get_id(private_gmp_rsa_public_key_t *this,
return this->keyid_info;
case ID_PUBKEY_SHA1:
return this->keyid;
case ID_KEY_ID:
return gmp_rsa_build_pgp_v3_keyid(this->n, this->e);
default:
return NULL;
}
@@ -381,14 +452,15 @@ static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty()
{
private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t);
this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_;
this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
this->public.interface.get_type = (key_type_t (*) (public_key_t*))get_type;
this->public.interface.verify = (bool (*) (public_key_t*, signature_scheme_t, chunk_t, chunk_t))verify;
this->public.interface.encrypt = (bool (*) (public_key_t*, chunk_t, chunk_t*))encrypt_;
this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals;
this->public.interface.get_keysize = (size_t (*) (public_key_t*))get_keysize;
this->public.interface.get_id = (identification_t* (*) (public_key_t*, id_type_t))get_id;
this->public.interface.get_encoding = (chunk_t(*) (public_key_t*))get_encoding;
this->public.interface.get_ref = (public_key_t* (*) (public_key_t *this))get_ref;
this->public.interface.destroy = (void (*) (public_key_t *this))destroy;
this->keyid = NULL;
this->keyid_info = NULL;
@@ -443,7 +515,7 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e)
mpz_init_set(this->n, n);
mpz_init_set(this->e, e);
this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info))
{
@@ -467,9 +539,9 @@ static const asn1Object_t pubkeyObjects[] = {
#define PUB_KEY_EXPONENT 2
/**
* Load a public key from an ASN1 encoded blob
* Load a public key from an ASN.1 encoded blob
*/
static gmp_rsa_public_key_t *load(chunk_t blob)
static gmp_rsa_public_key_t *load_asn1_der(chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
@@ -505,7 +577,7 @@ static gmp_rsa_public_key_t *load(chunk_t blob)
return NULL;
}
this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info))
@@ -516,6 +588,125 @@ static gmp_rsa_public_key_t *load(chunk_t blob)
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;
/**
* Builder implementation for key loading
@@ -554,7 +745,23 @@ static void add(private_builder_t *this, builder_part_t part, ...)
{
va_start(args, part);
chunk = va_arg(args, chunk_t);
this->key = load(chunk_clone(chunk));
this->key = load_asn1_der(chunk_clone(chunk));
va_end(args);
return;
}
case BUILD_BLOB_PGP:
{
va_start(args, part);
chunk = va_arg(args, chunk_t);
this->key = load_pgp(chunk_clone(chunk));
va_end(args);
return;
}
case BUILD_BLOB_RFC_3110:
{
va_start(args, part);
chunk = va_arg(args, chunk_t);
this->key = load_rfc_3110(chunk_clone(chunk));
va_end(args);
return;
}
@@ -136,7 +136,7 @@ error:
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.get_type.
*/
static key_type_t get_type(private_openssl_rsa_private_key_t *this)
{
@@ -144,7 +144,7 @@ static key_type_t get_type(private_openssl_rsa_private_key_t *this)
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.sign.
*/
static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t scheme,
chunk_t data, chunk_t *signature)
@@ -152,7 +152,6 @@ static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t sch
switch (scheme)
{
case SIGN_DEFAULT:
/* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1:
return build_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256:
@@ -171,7 +170,7 @@ static bool sign(private_openssl_rsa_private_key_t *this, signature_scheme_t sch
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.decrypt.
*/
static bool decrypt(private_openssl_rsa_private_key_t *this,
chunk_t crypto, chunk_t *plain)
@@ -181,7 +180,7 @@ static bool decrypt(private_openssl_rsa_private_key_t *this,
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.get_keysize.
*/
static size_t get_keysize(private_openssl_rsa_private_key_t *this)
{
@@ -189,7 +188,7 @@ static size_t get_keysize(private_openssl_rsa_private_key_t *this)
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.get_id.
*/
static identification_t* get_id(private_openssl_rsa_private_key_t *this,
id_type_t type)
@@ -206,7 +205,7 @@ static identification_t* get_id(private_openssl_rsa_private_key_t *this,
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.get_public_key.
*/
static openssl_rsa_public_key_t* get_public_key(private_openssl_rsa_private_key_t *this)
{
@@ -214,7 +213,35 @@ static openssl_rsa_public_key_t* get_public_key(private_openssl_rsa_private_key_
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.equals.
*/
static bool equals(private_openssl_rsa_private_key_t *this, private_key_t *other)
{
identification_t *keyid;
if (&this->public.interface == other)
{
return TRUE;
}
if (other->get_type(other) != KEY_RSA)
{
return FALSE;
}
keyid = other->get_id(other, ID_PUBKEY_SHA1);
if (keyid && keyid->equals(keyid, this->keyid))
{
return TRUE;
}
keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1);
if (keyid && keyid->equals(keyid, this->keyid_info))
{
return TRUE;
}
return FALSE;
}
/**
* Implementation of openssl_rsa_private_key.belongs_to.
*/
static bool belongs_to(private_openssl_rsa_private_key_t *this, public_key_t *public)
{
@@ -253,7 +280,7 @@ static chunk_t get_encoding(private_openssl_rsa_private_key_t *this)
}
/**
* Implementation of openssl_rsa_private_key.destroy.
* Implementation of openssl_rsa_private_key.get_ref.
*/
static private_openssl_rsa_private_key_t* get_ref(private_openssl_rsa_private_key_t *this)
{
@@ -286,16 +313,17 @@ static private_openssl_rsa_private_key_t *openssl_rsa_private_key_create_empty(v
{
private_openssl_rsa_private_key_t *this = malloc_thing(private_openssl_rsa_private_key_t);
this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
this->public.interface.get_type = (key_type_t (*) (private_key_t*))get_type;
this->public.interface.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign;
this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt;
this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize;
this->public.interface.get_id = (identification_t* (*) (private_key_t*, id_type_t))get_id;
this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key;
this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals;
this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to;
this->public.interface.get_encoding = (chunk_t(*) (private_key_t*))get_encoding;
this->public.interface.get_ref = (private_key_t* (*) (private_key_t*))get_ref;
this->public.interface.destroy = (void (*) (private_key_t*))destroy;
this->engine = FALSE;
this->keyid = NULL;
@@ -124,7 +124,6 @@ static bool verify(private_openssl_rsa_public_key_t *this, signature_scheme_t sc
switch (scheme)
{
case SIGN_DEFAULT:
/* default is EMSA-PKCS1 using SHA1 */
case SIGN_RSA_EMSA_PKCS1_SHA1:
return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_SHA256:
@@ -151,6 +150,34 @@ static bool encrypt_(private_openssl_rsa_public_key_t *this, chunk_t crypto, chu
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.
*/
@@ -262,6 +289,7 @@ static private_openssl_rsa_public_key_t *openssl_rsa_public_key_create_empty()
this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_;
this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals;
this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
+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);
if (this->public_key == NULL)
{
DBG1("could not create public key");
goto end;
}
break;
@@ -1123,19 +1122,19 @@ static private_x509_cert_t* create_empty(void)
{
private_x509_cert_t *this = malloc_thing(private_x509_cert_t);
this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
this->public.interface.interface.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy;
this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type;
this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject;
this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_issuer;
this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject;
this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_issuer;
this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by;
this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key;
this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity;
this->public.interface.interface.is_newer = (bool (*) (certificate_t*,certificate_t*))is_newer;
this->public.interface.interface.get_encoding = (chunk_t (*) (certificate_t*))get_encoding;
this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals;
this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref;
this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy;
this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags;
this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial;
this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier;
@@ -1314,7 +1313,7 @@ static bool generate(private_builder_t *this)
this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2),
asn1_simple_object(ASN1_INTEGER, this->cert->serialNumber),
asn1_integer("c", this->cert->serialNumber),
asn1_algorithmIdentifier(this->cert->algorithm),
issuer->get_encoding(issuer),
asn1_wrap(ASN1_SEQUENCE, "mm",
+1 -2
View File
@@ -38,8 +38,7 @@ nat_traversal.c nat_traversal.h \
ocsp.c ocsp.h \
packet.c packet.h \
pem.c pem.h \
pgp.c pgp.h \
pkcs1.c pkcs1.h \
pgpcert.c pgpcert.h \
pkcs7.c pkcs7.h \
plutomain.c \
rcv_whack.c rcv_whack.h \
+2 -2
View File
@@ -783,8 +783,8 @@ bool verify_x509acert(x509acert_t *ac, bool strict)
DBG_log("issuer aacert found")
)
if (!check_signature(ac->certificateInfo, ac->signature
, ac->algorithm, ac->algorithm, aacert))
if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm,
aacert))
{
plog("attribute certificate signature is invalid");
return FALSE;
+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
, cert->algorithm, cert->algorithm, authcert))
if (!x509_check_signature(cert->tbsCertificate, cert->signature,
cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("trust_authcert_candidate");
+20 -16
View File
@@ -1,5 +1,7 @@
/* Certificate support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -18,17 +20,15 @@
#include <freeswan.h>
#include "library.h"
#include "asn1/asn1.h"
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "id.h"
#include "x509.h"
#include "pgp.h"
#include "pem.h"
#include "certs.h"
#include "pkcs1.h"
/**
* used for initializatin of certs
@@ -118,14 +118,14 @@ bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type,
}
/**
* Loads a PKCS#1 or PGP private RSA key file
* Loads a PKCS#1 or PGP privatekey file
*/
err_t load_rsa_private_key(char* filename, prompt_pass_t *pass,
RSA_private_key_t *key)
private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
key_type_t type)
{
err_t ugh = NULL;
bool pgp = FALSE;
private_key_t *key = NULL;
chunk_t blob = chunk_empty;
bool pgp = FALSE;
char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
@@ -133,20 +133,24 @@ err_t load_rsa_private_key(char* filename, prompt_pass_t *pass,
{
if (pgp)
{
if (!parse_pgp(blob, NULL, key))
ugh = "syntax error in PGP private key file";
parse_pgp(blob, NULL, &key);
}
else
{
if (!pkcs1_parse_private_key(blob, key))
ugh = "syntax error in PKCS#1 private key file";
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
BUILD_BLOB_ASN1_DER, blob, BUILD_END);
}
if (key == NULL)
{
plog("syntax error in %s private key file", pgp ? "PGP":"PKCS#");
}
free(blob.ptr);
}
else
ugh = "error loading RSA private key file";
return ugh;
{
plog("error loading RSA private key file");
}
return key;
}
/**
+10 -7
View File
@@ -1,5 +1,7 @@
/* Certificate support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -15,9 +17,10 @@
#ifndef _CERTS_H
#define _CERTS_H
#include "pkcs1.h"
#include <credentials/keys/private_key.h>
#include "x509.h"
#include "pgp.h"
#include "pgpcert.h"
/* path definitions for private keys, end certs,
* cacerts, attribute certs and crls
@@ -59,11 +62,11 @@ extern const cert_t empty_cert;
*/
extern bool no_cr_send;
extern err_t load_rsa_private_key(char* filename, prompt_pass_t *pass
, RSA_private_key_t *key);
extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
key_type_t type);
extern chunk_t get_mycert(cert_t cert);
extern bool load_coded_file(char *filename, prompt_pass_t *pass
, const char *type, chunk_t *blob, bool *pgp);
extern bool load_coded_file(char *filename, prompt_pass_t *pass,
const char *type, chunk_t *blob, bool *pgp);
extern bool load_cert(char *filename, const char *label, cert_t *cert);
extern bool load_host_cert(char *filename, cert_t *cert);
extern bool load_ca_cert(char *filename, cert_t *cert);
+29 -25
View File
@@ -29,13 +29,15 @@
#include <freeswan.h>
#include "kameipsec.h"
#include <credentials/keys/private_key.h>
#include "constants.h"
#include "defs.h"
#include "id.h"
#include "x509.h"
#include "ca.h"
#include "crl.h"
#include "pgp.h"
#include "pgpcert.h"
#include "certs.h"
#include "ac.h"
#include "smartcard.h"
@@ -2155,17 +2157,16 @@ check_key_recs(enum myid_state try_state
* If so, treat as a kind of failure.
*/
enum myid_state old_myid_state = myid_state;
const struct RSA_private_key *our_RSA_pri;
private_key_t *private;
err_t ugh = NULL;
myid_state = try_state;
if (old_myid_state != myid_state
&& old_myid_state == MYID_SPECIFIED)
if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED)
{
ugh = "%myid was specified while we were guessing";
}
else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
else if ((private = get_private_key(c)) == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2185,7 +2186,7 @@ check_key_recs(enum myid_state try_state
{
ugh = "all our KEY RRs have the wrong public key";
if (kr->key->alg == PUBKEY_ALG_RSA
&& same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
&& private->belongs_to(private, &kr->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -2198,10 +2199,9 @@ check_key_recs(enum myid_state try_state
}
#endif /* USE_KEYRR */
static err_t
check_txt_recs(enum myid_state try_state
, const struct connection *c
, struct adns_continuation *ac)
static err_t check_txt_recs(enum myid_state try_state,
const struct connection *c,
struct adns_continuation *ac)
{
/* Check if TXT lookup yielded good results.
* Looking up based on our ID. Used if
@@ -2211,7 +2211,7 @@ check_txt_recs(enum myid_state try_state
* If so, treat as a kind of failure.
*/
enum myid_state old_myid_state = myid_state;
const struct RSA_private_key *our_RSA_pri;
private_key_t *private;
err_t ugh = NULL;
myid_state = try_state;
@@ -2221,7 +2221,7 @@ check_txt_recs(enum myid_state try_state
{
ugh = "%myid was specified while we were guessing";
}
else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
else if ((private = get_private_key(c)) == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2239,9 +2239,11 @@ check_txt_recs(enum myid_state try_state
ugh = "no TXT RR found for us";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
{
public_key_t *pub_key = gwp->key->public_key;
ugh = "all our TXT RRs have the wrong public key";
if (gwp->key->alg == PUBKEY_ALG_RSA
&& same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
if (pub_key->get_type(pub_key) == KEY_RSA &&
private->belongs_to(private, pub_key))
{
ugh = NULL; /* good! */
break;
@@ -2249,7 +2251,9 @@ check_txt_recs(enum myid_state try_state
}
}
if (ugh != NULL)
{
myid_state = old_myid_state;
}
return ugh;
}
@@ -2513,13 +2517,13 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* normal situation */
passert(sr != NULL);
if (our_RSA_pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2560,7 +2564,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
ugh = NULL; /* good! */
break;
}
if (same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -2579,11 +2583,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* unless we decide to look for KEY RR */
if (our_RSA_pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2604,8 +2608,8 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
passert(same_id(&gwp->gw_id, &sr->this.id));
ugh = "TXT RR for us has wrong key";
if (gwp->gw_key_present
&& same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
if (gwp->gw_key_present &&
private->belongs_to(private, gwp->key->public_key))
{
DBG(DBG_CONTROL,
DBG_log("initiate on demand found TXT with right public key at: %s"
@@ -2639,11 +2643,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* always */
if (our_RSA_pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2663,7 +2667,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
{
ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)";
if (kr->key->alg == PUBKEY_ALG_RSA
&& same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
&& private->belongs_to(private, kr->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
@@ -3399,7 +3403,7 @@ refine_host_connection(const struct state *st, const struct id *peer_id
* We must at least be able to find our private key
.*/
if (d->spd.this.sc == NULL /* no smartcard */
&& get_RSA_private_key(d) == NULL) /* no private key */
&& get_private_key(d) == NULL) /* no private key */
continue;
break;
+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 */
valid_sig = check_signature(crl->tbsCertList, crl->signature
, crl->algorithm, crl->algorithm, issuer_cert);
valid_sig = x509_check_signature(crl->tbsCertList, crl->signature,
crl->algorithm, issuer_cert);
unlock_authcert_list("insert_crl");
if (!valid_sig)
@@ -656,8 +656,8 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
, crl->authKeyID, AUTH_CA);
valid = check_signature(crl->tbsCertList, crl->signature
, crl->algorithm, crl->algorithm, issuer_cert);
valid = x509_check_signature(crl->tbsCertList, crl->signature,
crl->algorithm, issuer_cert);
unlock_authcert_list("verify_by_crl");
+74 -31
View File
@@ -29,6 +29,9 @@
#include <freeswan.h>
#include <utils/identification.h>
#include <credentials/keys/public_key.h>
#include "constants.h"
#include "adns.h" /* needs <resolv.h> */
#include "defs.h"
@@ -83,7 +86,9 @@ init_adns(void)
{
strcpy(adns_path_space, helper_bin_dir);
if (n > 0 && adns_path_space[n -1] != '/')
{
adns_path_space[n++] = '/';
}
}
}
else
@@ -95,25 +100,33 @@ init_adns(void)
n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));
if (n < 0)
{
exit_log_errno((e
, "readlink(\"/proc/self/exe\") failed in init_adns()"));
}
}
if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))
{
exit_log("path to %s is too long", adns_name);
}
while (n > 0 && adns_path_space[n - 1] != '/')
{
n--;
}
strcpy(adns_path_space + n, adns_name);
adns_path = adns_path_space;
}
if (access(adns_path, X_OK) < 0)
{
exit_log_errno((e, "%s missing or not executable", adns_path));
}
if (pipe(qfds) != 0 || pipe(afds) != 0)
{
exit_log_errno((e, "pipe(2) failed in init_adns()"));
}
adns_pid = fork();
switch (adns_pid)
@@ -128,7 +141,9 @@ init_adns(void)
* Take care to handle case where pipes already use these fds.
*/
if (afds[1] == 0)
{
afds[1] = dup(afds[1]); /* avoid being overwritten */
}
if (qfds[0] != 0)
{
dup2(qfds[0], 0);
@@ -140,16 +155,18 @@ init_adns(void)
close(qfds[1]);
}
if (afds[0] > 1)
{
close(afds[0]);
}
if (afds[1] > 1)
{
close(afds[1]);
}
DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));
execlp(adns_path, adns_name, NULL);
exit_log_errno((e, "execlp of %s failed", adns_path));
}
default:
/* parent */
close(qfds[0]);
@@ -183,8 +200,10 @@ stop_adns(void)
else if (WIFEXITED(status))
{
if (WEXITSTATUS(status) != 0)
{
plog("ADNS process exited with status %d"
, (int) WEXITSTATUS(status));
}
}
else if (WIFSIGNALED(status))
{
@@ -227,8 +246,9 @@ decode_iii(u_char **pp, struct id *gw_id)
u_char under = *e;
if (p == e)
{
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
}
*e = '\0';
if (*p == '@')
{
@@ -236,8 +256,10 @@ decode_iii(u_char **pp, struct id *gw_id)
err_t ugh = atoid(p, gw_id, FALSE);
if (ugh != NULL)
{
return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
, ugh);
}
}
else
{
@@ -248,12 +270,14 @@ decode_iii(u_char **pp, struct id *gw_id)
, &ip);
if (ugh != NULL)
{
return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
, ugh);
}
if (isanyaddr(&ip))
{
return "gateway address must not be 0.0.0.0 or 0::0";
}
iptoid(&ip, gw_id);
}
@@ -278,14 +302,18 @@ process_txt_rr_body(u_char *str
/* is this for us? */
if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)
{
return NULL; /* neither interesting nor bad */
}
p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */
p += strspn(p, " \t"); /* ignore leading whitespace */
/* decode '(' nnn ')' */
if (*p != '(')
{
return "X-IPsec-Server missing '('";
}
{
char *e;
@@ -293,25 +321,30 @@ process_txt_rr_body(u_char *str
p++;
pref = strtoul(p, &e, 0);
if ((u_char *)e == p)
{
return "malformed X-IPsec-Server priority";
}
p = e + strspn(e, " \t");
if (*p != ')')
{
return "X-IPsec-Server priority missing ')'";
}
p++;
p += strspn(p, " \t");
if (pref > 0xFFFF)
{
return "X-IPsec-Server priority larger than 0xFFFF";
}
}
/* time for '=' */
if (*p != '=')
{
return "X-IPsec-Server priority missing '='";
}
p++;
p += strspn(p, " \t");
@@ -384,29 +417,34 @@ process_txt_rr_body(u_char *str
/* Decode base 64 encoding of key.
* Similar code is in process_lwdnsq_key.
*/
u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
chunk_t kbc;
struct RSA_public_key r;
u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
size_t sz;
err_t ugh;
chunk_t rfc3110_chunk;
public_key_t *key;
err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len
, diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
if (ugh != NULL)
ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz,
diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
if (ugh)
{
return builddiag("malformed key data: %s", ugh);
if (kbc.len > sizeof(kb))
return builddiag("key data larger than %lu bytes"
, (unsigned long) sizeof(kb));
kbc.ptr = kb;
ugh = unpack_RSA_public_key(&r, &kbc);
if (ugh != NULL)
return builddiag("invalid key data: %s", ugh);
}
if (sz > sizeof(buf))
{
return builddiag("key data larger than %lu bytes",
(unsigned long) sizeof(buf));
}
rfc3110_chunk = chunk_create(buf, sz);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_BLOB_RFC_3110, rfc3110_chunk,
BUILD_END);
if (key == NULL)
{
return builddiag("invalid key data");
}
/* now find a key entry to put it in */
gi.key = public_key_from_rsa(&r);
free_RSA_public_content(&r);
gi.key = public_key_from_rsa(key);
unreference_key(&cr->last_info);
cr->last_info = reference_key(gi.key);
@@ -426,13 +464,18 @@ process_txt_rr_body(u_char *str
{
char cidb[BUF_LEN];
char gwidb[BUF_LEN];
identification_t *keyid;
public_key_t *pub_key;
idtoa(client_id, cidb, sizeof(cidb));
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
pub_key = gi.key->public_key;
keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
if (gi.gw_key_present)
{
DBG_log("gateway for %s is %s with key %s"
, cidb, gwidb, gi.key->u.rsa.keyid);
DBG_log("gateway for %s is %s with key %Y"
, cidb, gwidb, keyid);
}
else
{
+109 -255
View File
@@ -34,6 +34,8 @@
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include <crypto/rngs/rng.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "constants.h"
#include "defs.h"
@@ -1402,35 +1404,44 @@ static bool generate_skeyids_iv(struct state *st)
return prf_block_size;
}
/* Create an RSA signature of a hash.
/* Create a public key signature of a hash.
* Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* Use PKCS#1 version 1.5 encryption of hash (called
* RSAES-PKCS1-V1_5) in PKCS#2.
*/
static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
const u_char *hash_val, size_t hash_len)
static size_t sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
u_char *hash_val, size_t hash_len)
{
size_t sz = 0;
smartcard_t *sc = c->spd.this.sc;
if (sc == NULL) /* no smartcard */
{
const struct RSA_private_key *k = get_RSA_private_key(c);
chunk_t hash, sig;
private_key_t *private = get_private_key(c);
if (k == NULL)
if (private == NULL)
{
return 0; /* failure: no key to use */
sz = k->pub.k;
}
sz = private->get_keysize(private);
passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
sign_hash(k, hash_val, hash_len, sig_val, sz);
hash = chunk_create(hash_val, hash_len);
sig = chunk_create(sig_val, sz);
if (!private->sign(private, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
{
return 0;
}
memcpy(sig_val, sig.ptr, sz);
free(sig.ptr);
}
else if (sc->valid) /* if valid pin then sign hash on the smartcard */
{
lock_certs_and_keys("RSA_sign_hash");
lock_certs_and_keys("sign_hash");
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash");
unlock_certs_and_keys("sign_hash");
return 0;
}
@@ -1439,7 +1450,7 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS]
{
plog("failed to get keylength from smartcard");
scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash");
unlock_certs_and_keys("sign_hash");
return 0;
}
@@ -1450,142 +1461,11 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS]
sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
if (!pkcs11_keep_state)
scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash");
unlock_certs_and_keys("sign_hash");
}
return sz;
}
/* Check a Main Mode RSA Signature against computed hash using RSA public key k.
*
* As a side effect, on success, the public key is copied into the
* state object to record the authenticator.
*
* Can fail because wrong public key is used or because hash disagrees.
* We distinguish because diagnostics should also.
*
* The result is NULL if the Signature checked out.
* Otherwise, the first character of the result indicates
* how far along failure occurred. A greater character signifies
* greater progress.
*
* Classes:
* 0 reserved for caller
* 1 SIG length doesn't match key length -- wrong key
* 2-8 malformed ECB after decryption -- probably wrong key
* 9 decrypted hash != computed hash -- probably correct key
*
* Although the math should be the same for generating and checking signatures,
* it is not: the knowledge of the private key allows more efficient (i.e.
* different) computation for encryption.
*/
static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
size_t hash_len, const pb_stream *sig_pbs,
pubkey_t *kr, struct state *st)
{
const u_char *sig_val = sig_pbs->cur;
size_t sig_len = pbs_left(sig_pbs);
u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */
u_char *hash_in_s = &s[sig_len - hash_len];
const struct RSA_public_key *k = &kr->u.rsa;
/* decrypt the signature -- reversing RSA_sign_hash */
if (sig_len != k->k)
{
/* XXX notification: INVALID_KEY_INFORMATION */
return "1" "SIG length does not match public key length";
}
/* actual exponentiation; see PKCS#1 v2.0 5.1 */
{
chunk_t temp_s;
mpz_t c;
n_to_mpz(c, sig_val, sig_len);
mpz_powm(c, c, &k->e, &k->n);
temp_s = mpz_to_n(c, sig_len); /* back to octets */
memcpy(s, temp_s.ptr, sig_len);
free(temp_s.ptr);
mpz_clear(c);
}
/* sanity check on signature: see if it matches
* PKCS#1 v1.5 8.1 encryption-block formatting
*/
{
err_t ugh = NULL;
if (s[0] != 0x00)
ugh = "2" "no leading 00";
else if (hash_in_s[-1] != 0x00)
ugh = "3" "00 separator not present";
else if (s[1] == 0x01)
{
const u_char *p;
for (p = &s[2]; p != hash_in_s - 1; p++)
{
if (*p != 0xFF)
{
ugh = "4" "invalid Padding String";
break;
}
}
}
else if (s[1] == 0x02)
{
const u_char *p;
for (p = &s[2]; p != hash_in_s - 1; p++)
{
if (*p == 0x00)
{
ugh = "5" "invalid Padding String";
break;
}
}
}
else
ugh = "6" "Block Type not 01 or 02";
if (ugh != NULL)
{
/* note: it might be a good idea to make sure that
* an observer cannot tell what kind of failure happened.
* I don't know what this means in practice.
*/
/* We probably selected the wrong public key for peer:
* SIG Payload decrypted into malformed ECB
*/
/* XXX notification: INVALID_KEY_INFORMATION */
return ugh;
}
}
/* We have the decoded hash: see if it matches. */
if (memcmp(hash_val, hash_in_s, hash_len) != 0)
{
/* good: header, hash, signature, and other payloads well-formed
* good: we could find an RSA Sig key for the peer.
* bad: hash doesn't match
* Guess: sides disagree about key to be used.
*/
DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len);
DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len);
/* XXX notification: INVALID_HASH_INFORMATION */
return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed";
}
/* Success: copy successful key into state.
* There might be an old one if we previously aborted this
* state transition.
*/
unreference_key(&st->st_peer_pubkey);
st->st_peer_pubkey = reference_key(kr);
return NULL; /* happy happy */
}
/* Check signature against all RSA public keys we can find.
* If we need keys from DNS KEY records, and they haven't been fetched,
* return STF_SUSPEND to ask for asynch DNS lookup.
@@ -1597,54 +1477,39 @@ static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
* If only we had coroutines.
*/
struct tac_state {
/* RSA_check_signature's args that take_a_crack needs */
struct state *st;
const u_char *hash_val;
size_t hash_len;
const pb_stream *sig_pbs;
/* state carried between calls */
err_t best_ugh; /* most successful failure */
chunk_t hash;
chunk_t sig;
int tried_cnt; /* number of keys tried */
char tried[50]; /* keyids of tried public keys */
char *tn; /* roof of tried[] */
};
static bool take_a_crack(struct tac_state *s, pubkey_t *kr,
const char *story USED_BY_DEBUG)
static bool take_a_crack(struct tac_state *s, pubkey_t *kr)
{
err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs
, kr, s->st);
const struct RSA_public_key *k = &kr->u.rsa;
public_key_t *pub_key = kr->public_key;
identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
s->tried_cnt++;
if (ugh == NULL)
if (pub_key->verify(pub_key, SIGN_RSA_EMSA_PKCS1_NULL, s->hash, s->sig))
{
DBG(DBG_CRYPT | DBG_CONTROL
, DBG_log("an RSA Sig check passed with *%s [%s]"
, k->keyid, story));
DBG(DBG_CRYPT | DBG_CONTROL,
DBG_log("signature check passed with keyid %Y", keyid)
)
unreference_key(&s->st->st_peer_pubkey);
s->st->st_peer_pubkey = reference_key(kr);
return TRUE;
}
else
{
DBG(DBG_CRYPT
, DBG_log("an RSA Sig check failure %s with *%s [%s]"
, ugh + 1, k->keyid, story));
if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0])
s->best_ugh = ugh;
if (ugh[0] > '0'
&& s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried))
{
strcpy(s->tn, " *");
strcpy(s->tn + 2, k->keyid);
s->tn += strlen(s->tn);
}
DBG(DBG_CRYPT,
DBG_log("signature check failed with keyid %Y", keyid)
)
return FALSE;
}
}
static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const u_char hash_val[MAX_DIGEST_LEN],
u_char hash_val[MAX_DIGEST_LEN],
size_t hash_len, const pb_stream *sig_pbs,
#ifdef USE_KEYRR
const pubkey_list_t *keys_from_dns,
@@ -1653,16 +1518,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
{
const struct connection *c = st->st_connection;
struct tac_state s;
err_t dns_ugh = NULL;
s.st = st;
s.hash_val = hash_val;
s.hash_len = hash_len;
s.sig_pbs = sig_pbs;
s.best_ugh = NULL;
s.hash = chunk_create(hash_val, hash_len);
s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs));
s.tried_cnt = 0;
s.tn = s.tried;
/* try all gateway records hung off c */
if (c->policy & POLICY_OPPO)
@@ -1672,10 +1532,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
for (gw = c->gw_info; gw != NULL; gw = gw->next)
{
/* only consider entries that have a key and are for our peer */
if (gw->gw_key_present
&& same_id(&gw->gw_id, &c->spd.that.id)
&& take_a_crack(&s, gw->key, "key saved from DNS TXT"))
if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id)&&
take_a_crack(&s, gw->key))
{
return STF_OK;
}
}
}
@@ -1688,8 +1549,9 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
for (p = pubkeys; p != NULL; p = *pp)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id))
if (type == KEY_RSA && same_id(peer, &key->id))
{
time_t now = time(NULL);
@@ -1702,18 +1564,19 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
continue; /* continue with next public key */
}
if (take_a_crack(&s, key, "preloaded key"))
return STF_OK;
if (take_a_crack(&s, key))
{
return STF_OK;
}
}
pp = &p->next;
}
}
/* if no key was found (evidenced by best_ugh == NULL)
* and that side of connection is key_from_DNS_on_demand
* then go search DNS for keys for peer.
/* if no key was found and that side of connection is
* key_from_DNS_on_demand then go search DNS for keys for peer.
*/
if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand)
if (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand)
{
if (gateways_from_dns != NULL)
{
@@ -1721,9 +1584,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const struct gw_info *gwp;
for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next)
if (gwp->gw_key_present
&& take_a_crack(&s, gwp->key, "key from DNS TXT"))
{
if (gwp->gw_key_present && take_a_crack(&s, gwp->key))
{
return STF_OK;
}
}
}
#ifdef USE_KEYRR
else if (keys_from_dns != NULL)
@@ -1732,9 +1598,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const pubkey_list_t *kr;
for (kr = keys_from_dns; kr != NULL; kr = kr->next)
if (kr->key->alg == PUBKEY_ALG_RSA
&& take_a_crack(&s, kr->key, "key from DNS KEY"))
{
if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key))
{
return STF_OK;
}
}
}
#endif /* USE_KEYRR */
else
@@ -1748,53 +1617,32 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
{
char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
(void) idtoa(peer, id_buf, sizeof(id_buf));
idtoa(peer, id_buf, sizeof(id_buf));
if (s.best_ugh == NULL)
if (s.tried_cnt == 0)
{
if (dns_ugh == NULL)
loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
, id_buf);
else
loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
"; DNS search for KEY failed (%s)"
, id_buf, dns_ugh);
/* ??? is this the best code there is? */
return STF_FAIL + INVALID_KEY_INFORMATION;
loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf);
}
if (s.best_ugh[0] == '9')
else if (s.tried_cnt == 1)
{
loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
/* XXX Could send notification back */
return STF_FAIL + INVALID_HASH_INFORMATION;
loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
" wrong key?; tried %d", id_buf, s.tried_cnt);
DBG(DBG_CONTROL,
DBG_log("public key for '%s' failed: "
"decrypted SIG payload into a malformed ECB", id_buf)
)
}
else
{
if (s.tried_cnt == 1)
{
loglog(RC_LOG_SERIOUS
, "Signature check (on %s) failed (wrong key?); tried%s"
, id_buf, s.tried);
DBG(DBG_CONTROL,
DBG_log("public key for %s failed:"
" decrypted SIG payload into a malformed ECB (%s)"
, id_buf, s.best_ugh + 1));
}
else
{
loglog(RC_LOG_SERIOUS
, "Signature check (on %s) failed:"
" tried%s keys but none worked."
, id_buf, s.tried);
DBG(DBG_CONTROL,
DBG_log("all %d public keys for %s failed:"
" best decrypted SIG payload into a malformed ECB (%s)"
, s.tried_cnt, id_buf, s.best_ugh + 1));
}
return STF_FAIL + INVALID_KEY_INFORMATION;
loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
"tried %d keys but none worked.", id_buf, s.tried_cnt);
DBG(DBG_CONTROL,
DBG_log("all %d public keys for '%s' failed: "
"best decrypted SIG payload into a malformed ECB",
s.tried_cnt, id_buf)
)
}
return STF_FAIL + INVALID_KEY_INFORMATION;
}
}
@@ -2245,6 +2093,7 @@ static void decode_cert(struct msg_digest *md)
{
plog("X.509 certificate rejected");
}
DESTROY_IF(cert.public_key);
free_generalNames(cert.subjectAltName, FALSE);
free_generalNames(cert.crlDistributionPoints, FALSE);
}
@@ -2749,9 +2598,9 @@ static bool has_preloaded_public_key(struct state *st)
for (p = pubkeys; p != NULL; p = p->next)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
if (key->alg == PUBKEY_ALG_RSA &&
same_id(&c->spd.that.id, &key->id) &&
if (type == KEY_RSA && same_id(&c->spd.that.id, &key->id) &&
key->until_time == UNDEFINED_TIME)
{
/* found a preloaded public key */
@@ -3595,12 +3444,12 @@ stf_status main_inR2_outI3(struct msg_digest *md)
{
/* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val, hash_len);
size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
hash_len);
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
@@ -3997,12 +3846,12 @@ main_inI3_outR3_tail(struct msg_digest *md
{
/* SIG_R out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val, hash_len);
size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
hash_len);
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
@@ -4479,10 +4328,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_client:
next_step = vos_his_client;
{
const struct RSA_private_key *pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
struct gw_info *gwp;
if (pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4503,7 +4352,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = NULL; /* good! */
break;
}
else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
else if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -4515,9 +4364,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_txt:
next_step = vos_his_client;
{
const struct RSA_private_key *pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
if (pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4534,7 +4383,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
#endif
if (gwp->gw_key_present
&& same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
&& private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -4551,9 +4400,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_key:
next_step = vos_his_client;
{
const struct RSA_private_key *pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
if (pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4565,7 +4414,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next)
{
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa))
if (private->belongs_to(private, kp->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
@@ -4585,11 +4434,15 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_his_client:
next_step = vos_done;
{
public_key_t *pub_key;
identification_t *p1st_keyid;
struct gw_info *gwp;
/* check that the public key that authenticated
* the ISAKMP SA (p1st) will do for this gateway.
*/
pub_key = p1st->st_peer_pubkey->public_key;
p1st_keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1);
ugh = "peer's client does not delegate to peer";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
@@ -4601,9 +4454,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
* it implies fetching a KEY from the same
* place we must have gotten it.
*/
if (!gwp->gw_key_present
|| same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa
, &gwp->key->u.rsa))
if (!gwp->gw_key_present || p1st_keyid->equals(p1st_keyid,
gwp->key->public_key->get_id(gwp->key->public_key,
ID_PUBKEY_INFO_SHA1))
)
{
ugh = NULL; /* good! */
break;
+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)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
int pathlen;
if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id)
&& trusted_ca(key->issuer, sr->that.ca, &pathlen))
if (type == KEY_RSA && same_id(&sr->that.id, &key->id) &&
trusted_ca(key->issuer, sr->that.ca, &pathlen))
{
dntoa_or_null(peerca_str, BUF_LEN, key->issuer, "");
escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str));
+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)
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
* Copyright (C) 2009 Andreas Steffen, Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -15,9 +16,9 @@
#ifndef _KEYS_H
#define _KEYS_H
#include <gmp.h> /* GNU Multi-Precision library */
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "pkcs1.h"
#include "certs.h"
#ifndef SHARED_SECRETS_FILE
@@ -31,8 +32,7 @@ extern void free_preshared_secrets(void);
enum PrivateKeyKind {
PPK_PSK,
/* PPK_DSS, */ /* not implemented */
PPK_RSA,
PPK_PUBKEY,
PPK_XAUTH,
PPK_PIN
};
@@ -43,9 +43,8 @@ extern void xauth_defaults(void);
struct connection;
extern const chunk_t *get_preshared_secret(const struct connection *c);
extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
extern private_key_t *get_private_key(const struct connection *c);
extern private_key_t *get_x509_private_key(const x509cert_t *cert);
/* public key machinery */
@@ -62,10 +61,7 @@ struct pubkey {
, until_time;
chunk_t issuer;
chunk_t serial;
enum pubkey_alg alg;
union {
RSA_public_key_t rsa;
} u;
public_key_t *public_key;
};
typedef struct pubkey_list pubkey_list_t;
@@ -77,21 +73,20 @@ struct pubkey_list {
extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */
extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k);
extern pubkey_t *public_key_from_rsa(public_key_t *key);
extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
extern void free_public_keys(pubkey_list_t **keys);
extern void free_remembered_public_keys(void);
extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
, chunk_t issuer, chunk_t serial);
extern void delete_public_keys(const struct id *id, key_type_t type,
chunk_t issuer, chunk_t serial);
extern pubkey_t *reference_key(pubkey_t *pk);
extern void unreference_key(pubkey_t **pkp);
extern err_t add_public_key(const struct id *id
, enum dns_auth_level dns_auth_level
, enum pubkey_alg alg
, const chunk_t *key
, pubkey_list_t **head);
extern bool add_public_key(const struct id *id,
enum dns_auth_level dns_auth_level,
enum pubkey_alg alg,
chunk_t rfc3110_key,
pubkey_list_t **head);
extern bool has_private_key(cert_t cert);
extern void add_x509_public_key(x509cert_t *cert, time_t until
+76 -70
View File
@@ -39,7 +39,6 @@
#include "certs.h"
#include "smartcard.h"
#include "whack.h"
#include "pkcs1.h"
#include "keys.h"
#include "fetch.h"
#include "ocsp.h"
@@ -159,7 +158,7 @@ static x509cert_t *ocsp_requestor_cert = NULL;
static smartcard_t *ocsp_requestor_sc = NULL;
static const struct RSA_private_key *ocsp_requestor_pri = NULL;
static private_key_t *ocsp_requestor_key = NULL;
/**
* ASN.1 definition of ocspResponse
@@ -293,8 +292,9 @@ static const asn1Object_t singleResponseObjects[] = {
*/
static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
{
hasher_t *hasher;
static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */
location->uri = cert->accessLocation;
if (location->uri.ptr == NULL)
@@ -311,8 +311,15 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio
}
}
/* compute authNameID from as SHA-1 hash of issuer DN */
location->authNameID = chunk_create(digest, HASH_SIZE_SHA1);
compute_digest(cert->issuer, OID_SHA1, &location->authNameID);
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (hasher == NULL)
{
return FALSE;
}
hasher->get_hash(hasher, cert->issuer, digest);
hasher->destroy(hasher);
location->next = NULL;
location->issuer = cert->issuer;
@@ -660,7 +667,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
/* initialize temporary static storage */
ocsp_requestor_cert = NULL;
ocsp_requestor_sc = NULL;
ocsp_requestor_pri = NULL;
ocsp_requestor_key = NULL;
for (;;)
{
@@ -699,15 +706,15 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
else
{
/* look for a matching private key in the chained list */
const struct RSA_private_key *pri = get_x509_private_key(cert);
private_key_t *private = get_x509_private_key(cert);
if (pri != NULL)
if (private != NULL)
{
DBG(DBG_CONTROL,
DBG_log("matching private key found")
)
ocsp_requestor_cert = cert;
ocsp_requestor_pri = pri;
ocsp_requestor_key = private;
return TRUE;
}
}
@@ -715,50 +722,58 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
return FALSE;
}
static chunk_t generate_signature(chunk_t digest, smartcard_t *sc,
const RSA_private_key_t *pri)
static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc)
{
chunk_t sigdata;
hasher_t *hasher;
u_char *pos;
u_char digest_buf[HASH_SIZE_SHA1];
chunk_t digest = chunk_from_buf(digest_buf);
chunk_t digest_info, sigdata;
size_t siglen = 0;
if (sc != NULL)
if (!scx_establish_context(sc) || !scx_login(sc))
{
/* RSA signature is done on smartcard */
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
return chunk_empty;
}
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);
scx_release_context(sc);
return chunk_empty;
}
else
siglen = scx_get_keylength(sc);
if (siglen == 0)
{
/* RSA signature is done in software */
siglen = pri->pub.k;
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
*pos++ = 0x00;
sign_hash(pri, digest.ptr, digest.len, pos, siglen);
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)
)
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;
}
@@ -770,30 +785,22 @@ static chunk_t generate_signature(chunk_t digest, smartcard_t *sc,
static chunk_t build_signature(chunk_t tbsRequest)
{
chunk_t sigdata, certs;
chunk_t digest_info;
u_char digest_buf[MAX_DIGEST_LEN];
chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN };
if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw))
return chunk_empty;
/* according to PKCS#1 v2.1 digest must be packaged into
* an ASN.1 structure for encryption
*/
digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
, asn1_algorithmIdentifier(OID_SHA1)
, asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
/* generate the RSA signature */
sigdata = generate_signature(digest_info
, ocsp_requestor_sc
, ocsp_requestor_pri);
free(digest_info.ptr);
/* has the RSA signature generation been successful? */
if (ocsp_requestor_sc != NULL)
{
/* RSA signature is done on smartcard */
sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc);
}
else
{
/* RSA signature is done in software */
sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key,
TRUE);
}
if (sigdata.ptr == NULL)
{
return chunk_empty;
}
/* include our certificate */
certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
@@ -992,8 +999,7 @@ static bool valid_ocsp_response(response_t *res)
DBG_log("ocsp signer cert found")
)
if (!check_signature(res->tbs, res->signature, res->algorithm
, res->algorithm, authcert))
if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert))
{
plog("signature of ocsp response is invalid");
unlock_authcert_list("valid_ocsp_response");
@@ -1051,8 +1057,8 @@ static bool valid_ocsp_response(response_t *res)
DBG_log("issuer cacert found")
)
if (!check_signature(cert->tbsCertificate, cert->signature
, cert->algorithm, cert->algorithm, authcert))
if (!x509_check_signature(cert->tbsCertificate, cert->signature,
cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("valid_ocsp_response");
+65 -217
View File
@@ -1,5 +1,7 @@
/* Support of OpenPGP certificates
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -19,6 +21,7 @@
#include <freeswan.h>
#include <library.h>
#include <pgp/pgp.h>
#include <crypto/hashers/hasher.h>
#include "constants.h"
@@ -26,10 +29,9 @@
#include "mp_defs.h"
#include "log.h"
#include "id.h"
#include "pgp.h"
#include "pgpcert.h"
#include "certs.h"
#include "whack.h"
#include "pkcs1.h"
#include "keys.h"
/*
@@ -87,36 +89,6 @@ static const char *const pgp_packet_type_name[] = {
#define PGP_PUBKEY_ALG_ECDSA 19
#define PGP_PUBKEY_ALG_ELGAMAL 20
/*
* OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440
*/
#define PGP_SYM_ALG_PLAIN 0
#define PGP_SYM_ALG_IDEA 1
#define PGP_SYM_ALG_3DES 2
#define PGP_SYM_ALG_CAST5 3
#define PGP_SYM_ALG_BLOWFISH 4
#define PGP_SYM_ALG_SAFER 5
#define PGP_SYM_ALG_DES 6
#define PGP_SYM_ALG_AES 7
#define PGP_SYM_ALG_AES_192 8
#define PGP_SYM_ALG_AES_256 9
#define PGP_SYM_ALG_TWOFISH 10
#define PGP_SYM_ALG_ROOF 11
static const char *const pgp_sym_alg_name[] = {
"Plaintext",
"IDEA",
"3DES",
"CAST5",
"Blowfish",
"SAFER",
"DES",
"AES",
"AES-192",
"AES-256",
"Twofish"
};
/*
* Size of PGP Key ID
*/
@@ -129,28 +101,15 @@ const pgpcert_t empty_pgpcert = {
{ NULL, 0 }, /* certificate */
0 , /* created */
0 , /* until */
0 , /* pubkeyAlgorithm */
{ NULL, 0 }, /* modulus */
{ NULL, 0 }, /* publicExponent */
"" /* fingerprint */
NULL , /* public key */
NULL /* fingerprint */
};
static size_t
pgp_size(chunk_t *blob, int len)
{
size_t size = 0;
blob->len -= len;
while (len-- > 0)
size = 256*size + *blob->ptr++;
return size;
}
/*
* extracts the length of a PGP packet
*/
static size_t
pgp_old_packet_length(chunk_t *blob)
static size_t pgp_old_packet_length(chunk_t *blob)
{
/* bits 0 and 1 define the packet length type */
int len_type = 0x03 & *blob->ptr++;
@@ -158,14 +117,13 @@ pgp_old_packet_length(chunk_t *blob)
blob->len--;
/* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
return pgp_size(blob, (len_type == 0)? 1: len_type << 1);
return pgp_length(blob, (len_type == 0)? 1: len_type << 1);
}
/*
* extracts PGP packet version (V3 or V4)
*/
static u_char
pgp_version(chunk_t *blob)
static u_char pgp_version(chunk_t *blob)
{
u_char version = *blob->ptr++;
blob->len--;
@@ -179,10 +137,10 @@ pgp_version(chunk_t *blob)
/*
* Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
*/
static bool
parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
{
u_char version = pgp_version(packet);
public_key_t *key;
if (version < 3 || version > 4)
{
@@ -191,7 +149,7 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
}
/* creation date - 4 bytes */
cert->created = (time_t)pgp_size(packet, 4);
cert->created = (time_t)pgp_length(packet, 4);
DBG(DBG_PARSING,
DBG_log("L3 - created:");
DBG_log(" %T", &cert->created, TRUE)
@@ -200,12 +158,13 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
if (version == 3)
{
/* validity in days - 2 bytes */
cert->until = (time_t)pgp_size(packet, 2);
cert->until = (time_t)pgp_length(packet, 2);
/* validity of 0 days means that the key never expires */
if (cert->until > 0)
{
cert->until = cert->created + 24*3600*cert->until;
}
DBG(DBG_PARSING,
DBG_log("L3 - until:");
DBG_log(" %T", &cert->until, TRUE);
@@ -217,49 +176,29 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
DBG_log("L3 - public key algorithm:")
)
switch (pgp_size(packet, 1))
switch (pgp_length(packet, 1))
{
case PGP_PUBKEY_ALG_RSA:
case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
cert->pubkeyAlg = PUBKEY_ALG_RSA;
DBG(DBG_PARSING,
DBG_log(" RSA")
)
/* modulus n */
cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
cert->modulus.ptr = packet->ptr;
packet->ptr += cert->modulus.len;
packet->len -= cert->modulus.len;
DBG(DBG_PARSING,
DBG_log("L3 - modulus:")
)
DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus);
/* public exponent e */
cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
cert->publicExponent.ptr = packet->ptr;
packet->ptr += cert->publicExponent.len;
packet->len -= cert->publicExponent.len;
DBG(DBG_PARSING,
DBG_log("L3 - public exponent:")
)
DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent);
key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
BUILD_BLOB_PGP, *packet,
BUILD_END);
if (key == NULL)
{
return FALSE;
}
cert->public_key = key;
if (version == 3)
{
hasher_t *hasher;
/* a V3 fingerprint is the MD5 hash of modulus and public exponent */
hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
if (hasher == NULL)
cert->fingerprint = key->get_id(key, ID_KEY_ID);
if (cert->fingerprint == NULL)
{
plog(" computation of V3 key ID failed, no MD5 hasher is available");
return FALSE;
}
hasher->get_hash(hasher, cert->modulus, NULL);
hasher->get_hash(hasher, cert->publicExponent, cert->fingerprint);
hasher->destroy(hasher);
}
else
{
@@ -267,14 +206,12 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
}
break;
case PGP_PUBKEY_ALG_DSA:
cert->pubkeyAlg = PUBKEY_ALG_DSA;
DBG(DBG_PARSING,
DBG_log(" DSA")
)
plog(" DSA public keys not supported");
return FALSE;
default:
cert->pubkeyAlg = 0;
DBG(DBG_PARSING,
DBG_log(" other")
)
@@ -284,104 +221,10 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE;
}
/*
* Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440
*/
static bool
parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key)
{
int i, s2k;
pgpcert_t cert = empty_pgpcert;
if (!parse_pgp_pubkey_packet(packet, &cert))
return FALSE;
init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent
, cert.modulus);
/* string-to-key usage */
s2k = pgp_size(packet, 1);
DBG(DBG_PARSING,
DBG_log("L3 - string-to-key: %d", s2k)
)
if (s2k == 255)
{
plog(" string-to-key specifiers not supported");
return FALSE;
}
if (s2k >= PGP_SYM_ALG_ROOF)
{
plog(" undefined symmetric key algorithm");
return FALSE;
}
/* a known symmetric key algorithm is specified*/
DBG(DBG_PARSING,
DBG_log(" %s", pgp_sym_alg_name[s2k])
)
/* private key is unencrypted */
if (s2k == PGP_SYM_ALG_PLAIN)
{
for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++)
{
mpz_t u; /* auxiliary variable */
/* compute offset to private key component i*/
MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset);
switch (i)
{
case 2:
case 3:
case 4:
{
size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
n_to_mpz(n, packet->ptr, len);
DBG(DBG_PARSING,
DBG_log("L3 - %s:", RSA_private_field[i].name)
)
DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len);
packet->ptr += len;
packet->len -= len;
}
break;
case 5: /* dP = d mod (p-1) */
mpz_init(u);
mpz_sub_ui(u, &key->p, 1);
mpz_mod(n, &key->d, u);
mpz_clear(u);
break;
case 6: /* dQ = d mod (q-1) */
mpz_init(u);
mpz_sub_ui(u, &key->q, 1);
mpz_mod(n, &key->d, u);
mpz_clear(u);
break;
case 7: /* qInv = (q^-1) mod p */
mpz_invert(n, &key->q, &key->p);
if (mpz_cmp_ui(n, 0) < 0)
mpz_add(n, n, &key->p);
passert(mpz_cmp(n, &key->p) < 0);
break;
}
}
return TRUE;
}
plog(" %s encryption not supported", pgp_sym_alg_name[s2k]);
return FALSE;
}
/*
* Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
*/
static bool
parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
{
time_t created;
chunk_t keyid;
@@ -393,20 +236,20 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE;
/* size byte must have the value 5 */
if (pgp_size(packet, 1) != 5)
if (pgp_length(packet, 1) != 5)
{
plog(" size must be 5");
return FALSE;
}
/* signature type - 1 byte */
sig_type = (u_char)pgp_size(packet, 1);
sig_type = (u_char)pgp_length(packet, 1);
DBG(DBG_PARSING,
DBG_log("L3 - signature type: 0x%2x", sig_type)
)
/* creation date - 4 bytes */
created = (time_t)pgp_size(packet, 4);
created = (time_t)pgp_length(packet, 4);
DBG(DBG_PARSING,
DBG_log("L3 - created:");
DBG_log(" %T", &cert->created, TRUE)
@@ -420,8 +263,7 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE;
}
bool
parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key)
{
DBG(DBG_PARSING,
DBG_log("L0 - PGP file:")
@@ -486,11 +328,15 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
{
case PGP_PKT_PUBLIC_KEY:
if (!parse_pgp_pubkey_packet(&packet, cert))
{
return FALSE;
}
break;
case PGP_PKT_SIGNATURE:
if (!parse_pgp_signature_packet(&packet, cert))
{
return FALSE;
}
break;
case PGP_PKT_USER_ID:
DBG(DBG_PARSING,
@@ -508,12 +354,18 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
switch (packet_type)
{
case PGP_PKT_SECRET_KEY:
if (!parse_pgp_secretkey_packet(&packet, key))
return FALSE;
*key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_BLOB_PGP, packet,
BUILD_END);
break;
default:
break;
}
if (*key == NULL)
{
return FALSE;
}
}
}
}
@@ -523,8 +375,7 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
/*
* compare two OpenPGP certificates
*/
static bool
same_pgpcert(pgpcert_t *a, pgpcert_t *b)
static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b)
{
return a->certificate.len == b->certificate.len &&
memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
@@ -533,8 +384,7 @@ same_pgpcert(pgpcert_t *a, pgpcert_t *b)
/*
* for each link pointing to the certificate increase the count by one
*/
void
share_pgpcert(pgpcert_t *cert)
void share_pgpcert(pgpcert_t *cert)
{
if (cert != NULL)
{
@@ -545,21 +395,17 @@ share_pgpcert(pgpcert_t *cert)
/*
* select the OpenPGP keyid as ID
*/
void
select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
{
end_id->kind = ID_KEY_ID;
end_id->name.len = PGP_FINGERPRINT_SIZE;
end_id->name.ptr = cert->fingerprint;
end_id->name.ptr = temporary_cyclic_buffer();
memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE);
end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
end_id->name = chunk_clone(end_id->name);
}
/*
* add an OpenPGP user/host certificate to the chained list
*/
pgpcert_t*
add_pgpcert(pgpcert_t *cert)
pgpcert_t* add_pgpcert(pgpcert_t *cert)
{
pgpcert_t *c = pgpcerts;
@@ -585,14 +431,15 @@ add_pgpcert(pgpcert_t *cert)
/* release of a certificate decreases the count by one
" the certificate is freed when the counter reaches zero
*/
void
release_pgpcert(pgpcert_t *cert)
void release_pgpcert(pgpcert_t *cert)
{
if (cert != NULL && --cert->count == 0)
{
pgpcert_t **pp = &pgpcerts;
while (*pp != cert)
{
pp = &(*pp)->next;
}
*pp = cert->next;
free_pgpcert(cert);
}
@@ -601,11 +448,12 @@ release_pgpcert(pgpcert_t *cert)
/*
* free a PGP certificate
*/
void
free_pgpcert(pgpcert_t *cert)
void free_pgpcert(pgpcert_t *cert)
{
if (cert != NULL)
{
DESTROY_IF(cert->public_key);
DESTROY_IF(cert->fingerprint);
free(cert->certificate.ptr);
free(cert);
}
@@ -614,8 +462,7 @@ free_pgpcert(pgpcert_t *cert)
/*
* list all PGP end certificates in a chained list
*/
void
list_pgp_end_certs(bool utc)
void list_pgp_end_certs(bool utc)
{
pgpcert_t *cert = pgpcerts;
time_t now;
@@ -632,19 +479,20 @@ list_pgp_end_certs(bool utc)
while (cert != NULL)
{
unsigned keysize;
char buf[BUF_LEN];
public_key_t *key = cert->public_key;
cert_t c;
c.type = CERT_PGP;
c.u.pgp = cert;
whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN);
whack_log(RC_COMMENT, " fingerprint: %s", buf);
form_keyid(cert->publicExponent, cert->modulus, buf, &keysize);
whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf,
(has_private_key(c))? ", has private key" : "");
whack_log(RC_COMMENT, " fingerprint: %Y", cert->fingerprint);
whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
key_type_names, key->get_type(key),
key->get_keysize(key) * BITS_PER_BYTE,
has_private_key(c)? ", has private key" : "");
whack_log(RC_COMMENT, " keyid: %Y",
key->get_id(key, ID_PUBKEY_INFO_SHA1));
whack_log(RC_COMMENT, " created: %T", &cert->created, utc);
whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc,
check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+17 -17
View File
@@ -1,5 +1,7 @@
/* Support of OpenPGP certificates
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -12,12 +14,12 @@
* for more details.
*/
#ifndef _PGP_H
#define _PGP_H
#ifndef _PGPCERT_H
#define _PGPCERT_H
#include <crypto/hashers/hasher.h>
#include "pkcs1.h"
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
/*
* Length of PGP V3 fingerprint
@@ -31,20 +33,18 @@ typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
typedef struct pgpcert pgpcert_t;
struct pgpcert {
pgpcert_t *next;
time_t installed;
int count;
chunk_t certificate;
time_t created;
time_t until;
enum pubkey_alg pubkeyAlg;
chunk_t modulus;
chunk_t publicExponent;
fingerprint_t fingerprint;
pgpcert_t *next;
time_t installed;
int count;
chunk_t certificate;
time_t created;
time_t until;
public_key_t *public_key;
identification_t *fingerprint;
};
extern const pgpcert_t empty_pgpcert;
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key);
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key);
extern void share_pgpcert(pgpcert_t *cert);
extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
@@ -52,4 +52,4 @@ extern void list_pgp_end_certs(bool utc);
extern void release_pgpcert(pgpcert_t *cert);
extern void free_pgpcert(pgpcert_t *cert);
#endif /* _PGP_H */
#endif /* _PGPCERT_H */
-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 */
if (cacert != NULL)
{
public_key_t *key = cacert->public_key;
signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
if (signerInfos == 0)
{
DBG1("no signerInfo object found");
@@ -355,15 +358,39 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
DBG1("no authenticatedAttributes object found");
return FALSE;
}
if (!check_signature(*attributes, encrypted_digest, digest_alg,
enc_alg, cacert))
if (enc_alg != OID_RSA_ENCRYPTION)
{
DBG1("invalid signature");
DBG1("only RSA digest encryption supported");
return FALSE;
}
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
{
DBG2("signature is valid");
DBG1("invalid signature");
return FALSE;
}
}
return TRUE;
@@ -374,7 +401,7 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
*/
bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber,
const RSA_private_key_t *key)
private_key_t *key)
{
asn1_parser_t *parser;
chunk_t object;
@@ -446,7 +473,7 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
}
break;
case PKCS7_ENCRYPTED_KEY:
if (!RSA_decrypt(key, object, &symmetric_key))
if (!key->decrypt(key, object, &symmetric_key))
{
DBG1("symmetric key could not be decrypted with rsa");
goto end;
@@ -579,17 +606,20 @@ chunk_t pkcs7_contentType_attribute(void)
*/
chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
{
u_char digest_buf[MAX_DIGEST_LEN];
chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
chunk_t digest;
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"
, ASN1_messageDigest_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_simple_object(ASN1_OCTET_STRING, digest)
)
);
return asn1_wrap(ASN1_SEQUENCE, "cm",
ASN1_messageDigest_oid,
asn1_wrap(ASN1_SET, "m",
asn1_wrap(ASN1_OCTET_STRING, "m", digest)
)
);
}
/**
@@ -649,7 +679,7 @@ chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert)
*/
chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
const x509cert_t *cert, int digest_alg,
const RSA_private_key_t *key)
private_key_t *key)
{
contentInfo_t pkcs7Data, signedData;
chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
@@ -658,15 +688,15 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
if (attributes.ptr != NULL)
{
encryptedDigest = pkcs1_build_signature(attributes, digest_alg
, key, FALSE);
encryptedDigest = x509_build_signature(attributes, digest_alg, key,
FALSE);
authenticatedAttributes = chunk_clone(attributes);
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
}
else
{
encryptedDigest = (data.ptr == NULL)? chunk_empty
: pkcs1_build_signature(data, digest_alg, key, FALSE);
: x509_build_signature(data, digest_alg, key, FALSE);
authenticatedAttributes = chunk_empty;
}
@@ -705,8 +735,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
{
encryption_algorithm_t alg;
size_t alg_key_size;
RSA_public_key_t public_key;
chunk_t symmetricKey, iv, in, out;
chunk_t symmetricKey, protectedKey, iv, in, out;
crypter_t *crypter;
alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size);
@@ -759,10 +788,11 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
free(in.ptr);
free(iv.ptr);
init_RSA_public_key(&public_key, cert->publicExponent, cert->modulus);
cert->public_key->encrypt(cert->public_key, symmetricKey, &protectedKey);
/* build pkcs7 enveloped data object */
{
chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_build_known_oid(enc_alg)
, asn1_simple_object(ASN1_OCTET_STRING, iv));
@@ -773,7 +803,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
, asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
, RSA_encrypt(&public_key, symmetricKey));
, protectedKey);
chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
, ASN1_INTEGER_0
@@ -793,7 +823,6 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
cInfo = pkcs7_build_contentInfo(&envelopedData);
DBG3("envelopedData %B", &cInfo);
free_RSA_public_content(&public_key);
free(envelopedData.content.ptr);
free(symmetricKey.ptr);
return cInfo;
+5 -5
View File
@@ -1,6 +1,7 @@
/* Support of PKCS#7 data structures
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Copyright (C) 2002-2005 Andreas Steffen
* Copyright (C) 2002-2009 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil, Switzerland
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,9 +19,8 @@
#define _PKCS7_H
#include <crypto/crypters/crypter.h>
#include <credentials/keys/private_key.h>
#include "defs.h"
#include "pkcs1.h"
#include "x509.h"
/* Access structure for a PKCS#7 ContentInfo object */
@@ -39,12 +39,12 @@ extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0,
extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data,
x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert);
extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber, const RSA_private_key_t *key);
chunk_t serialNumber, private_key_t *key);
extern chunk_t pkcs7_contentType_attribute(void);
extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg);
extern chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert);
extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
const x509cert_t *cert, int digest_alg, const RSA_private_key_t *key);
const x509cert_t *cert, int digest_alg, private_key_t *key);
extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert,
int enc_alg);
+5 -4
View File
@@ -234,10 +234,11 @@ key_add_request(const whack_message_t *msg)
}
else
{
ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg
, &msg->keyval, &pubkeys);
if (ugh != NULL)
loglog(RC_LOG_SERIOUS, "%s", ugh);
if (!add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, msg->keyval,
&pubkeys))
{
loglog(RC_LOG_SERIOUS, "failed to add public key");
}
}
}
}
+126 -224
View File
@@ -35,7 +35,6 @@
#include "mp_defs.h"
#include "log.h"
#include "id.h"
#include "pkcs1.h"
#include "x509.h"
#include "crl.h"
#include "ca.h"
@@ -198,36 +197,33 @@ static const asn1Object_t pubkeyObjects[] = {
* ASN.1 definition of an X.509v3 x509_cert
*/
static const asn1Object_t certObjects[] = {
{ 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
{ 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
{ 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
{ 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
{ 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
{ 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
{ 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */
{ 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */
{ 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 14 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
{ 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 16 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
{ 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 18 */
{ 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 19 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 20 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 21 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
ASN1_BODY }, /* 22 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 23 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 24 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 25 */
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 26 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 27 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
{ 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
{ 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
{ 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
{ 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
{ 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
{ 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */
{ 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
{ 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
{ 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */
{ 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define X509_OBJ_CERTIFICATE 0
#define X509_OBJ_TBS_CERTIFICATE 1
@@ -238,13 +234,12 @@ static const asn1Object_t certObjects[] = {
#define X509_OBJ_NOT_BEFORE 8
#define X509_OBJ_NOT_AFTER 9
#define X509_OBJ_SUBJECT 10
#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12
#define X509_OBJ_SUBJECT_PUBLIC_KEY 13
#define X509_OBJ_EXTN_ID 21
#define X509_OBJ_CRITICAL 22
#define X509_OBJ_EXTN_VALUE 23
#define X509_OBJ_ALGORITHM 26
#define X509_OBJ_SIGNATURE 27
#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11
#define X509_OBJ_EXTN_ID 19
#define X509_OBJ_CRITICAL 20
#define X509_OBJ_EXTN_VALUE 21
#define X509_OBJ_ALGORITHM 24
#define X509_OBJ_SIGNATURE 25
const x509cert_t empty_x509cert = {
NULL , /* *next */
@@ -262,11 +257,7 @@ const x509cert_t empty_x509cert = {
0 , /* notBefore */
0 , /* notAfter */
{ NULL, 0 } , /* subject */
/* subjectPublicKeyInfo */
OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
{ NULL, 0 } , /* subjectPublicKey */
{ NULL, 0 } , /* modulus */
{ NULL, 0 } , /* publicExponent */
NULL , /* public_key */
/* issuerUniqueID */
/* subjectUniqueID */
/* extensions */
@@ -1140,13 +1131,19 @@ chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
/**
* Build a to-be-signed X.509 certificate body
*/
static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa)
{
/* version is always X.509v3 */
chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
chunk_t extensions = chunk_empty;
chunk_t key = rsa->get_encoding(rsa);
chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
asn1_bitstring("m", key));
if (cert->subjectAltName != NULL)
{
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
@@ -1156,7 +1153,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
, version
, asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
, asn1_integer("c", cert->serialNumber)
, asn1_algorithmIdentifier(cert->sigAlg)
, cert->issuer
, asn1_wrap(ASN1_SEQUENCE, "mm"
@@ -1164,7 +1161,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
, asn1_from_time(&cert->notAfter, ASN1_UTCTIME)
)
, cert->subject
, pkcs1_build_publicKeyInfo(rsa)
, keyInfo
, extensions
);
}
@@ -1172,13 +1169,13 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
/**
* Build a DER-encoded X.509 certificate
*/
void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key,
const RSA_private_key_t *signer_key)
void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
private_key_t *signer_key)
{
chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg
, signer_key, TRUE);
chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg
, signer_key, TRUE);
cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
, tbs_cert
@@ -1210,6 +1207,7 @@ void free_x509cert(x509cert_t *cert)
{
if (cert != NULL)
{
DESTROY_IF(cert->public_key);
free_generalNames(cert->subjectAltName, FALSE);
free_generalNames(cert->crlDistributionPoints, FALSE);
free(cert->certificate.ptr);
@@ -1318,111 +1316,75 @@ void store_x509certs(x509cert_t **firstcert, bool strict)
}
/**
* Decrypts an RSA signature using the issuer's certificate
* Check if a signature over binary blob is genuine
*/
static bool decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert,
chunk_t *digest)
bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
const x509cert_t *issuer_cert)
{
switch (alg)
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:
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1_WITH_RSA:
case OID_SHA1_WITH_RSA_OIW:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512_WITH_RSA:
{
mpz_t s;
RSA_public_key_t rsa;
init_RSA_public_key(&rsa, issuer_cert->publicExponent
, issuer_cert->modulus);
/* decrypt the signature s = s^e mod n */
n_to_mpz(s, sig.ptr, sig.len);
mpz_powm(s, s, &rsa.e, &rsa.n);
/* convert back to bytes */
decrypted = mpz_to_n(s, rsa.k);
DBG(DBG_PARSING,
DBG_dump_chunk(" decrypted signature: ", decrypted)
)
/* copy the least significant bits of decrypted signature
* into the digest string
*/
memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
digest->len);
/* free memory */
free_RSA_public_content(&rsa);
free(decrypted.ptr);
mpz_clear(s);
return TRUE;
}
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
break;
case OID_ECDSA_WITH_SHA1:
scheme = SIGN_ECDSA_WITH_SHA1;
break;
default:
digest->len = 0;
return FALSE;
}
return key->verify(key, scheme, tbs, sig);
}
/**
* Check if a signature over binary blob is genuine
* Build an ASN.1 encoded PKCS#1 signature over a binary blob
*/
bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg,
const x509cert_t *issuer_cert)
chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
bool bit_string)
{
u_char digest_buf[MAX_DIGEST_LEN];
u_char decrypted_buf[MAX_DIGEST_LEN];
chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
signature_scheme_t scheme = SIGN_DEFAULT;
chunk_t signature;
DBG(DBG_PARSING,
if (digest_alg != OID_UNKNOWN)
{
DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
}
else
{
DBG_log("unknown signature digest algorithm");
}
)
if (!compute_digest(tbs, digest_alg, &digest))
switch (hash_alg)
{
plog(" digest algorithm not supported");
return FALSE;
case OID_MD5:
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512:
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
break;
default:
return chunk_empty;
}
DBG(DBG_PARSING,
DBG_dump_chunk(" digest:", digest)
)
decrypted.len = digest.len; /* we want the same digest length */
DBG(DBG_PARSING,
if (enc_alg != OID_UNKNOWN)
{
DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
}
else
{
DBG_log("unknown signature encryption algorithm");
}
)
if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
if (!key->sign(key, scheme, tbs, &signature))
{
plog(" decryption algorithm not supported");
return FALSE;
}
/* check if digests are equal */
return memeq(decrypted.ptr, digest.ptr, digest.len);
return chunk_empty;
}
return (bit_string) ? asn1_bitstring("m", signature)
: asn1_wrap(ASN1_OCTET_STRING, "m", signature);
}
/**
@@ -1489,15 +1451,17 @@ void gntoid(struct id *id, const generalName_t *gn)
*/
bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
{
hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
identification_t *keyid;
chunk_t encoding;
if (hasher == NULL)
keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1);
if (keyid == NULL)
{
plog(" no SHA-1 hasher available to compute subjectKeyID");
plog(" unable to compute subjectKeyID");
return FALSE;
}
hasher->get_hash(hasher, cert->subjectPublicKey, subjectKeyID.ptr);
hasher->destroy(hasher);
encoding = keyid->get_encoding(keyid);
memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len);
return TRUE;
}
@@ -1824,50 +1788,6 @@ static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
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
*/
@@ -1927,30 +1847,11 @@ bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
DBG_log(" '%s'",buf)
)
break;
case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
if (asn1_parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO:
cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
if (cert->public_key == NULL)
{
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;
}
break;
@@ -2116,8 +2017,8 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
DBG_log("issuer cacert found")
)
if (!check_signature(cert->tbsCertificate, cert->signature
, cert->algorithm, cert->algorithm, issuer_cert))
if (!x509_check_signature(cert->tbsCertificate, cert->signature,
cert->algorithm, issuer_cert))
{
plog("certificate signature is invalid");
unlock_authcert_list("verify_x509cert");
@@ -2220,9 +2121,8 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
{
if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
{
unsigned keysize;
char keyid[KEYID_BUF];
u_char buf[BUF_LEN];
public_key_t *key = cert->public_key;
cert_t c;
c.type = CERT_X509_SIGNATURE;
@@ -2242,36 +2142,38 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
whack_log(RC_COMMENT, " subject: '%s'", buf);
dntoa(buf, BUF_LEN, cert->issuer);
whack_log(RC_COMMENT, " issuer: '%s'", buf);
datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':'
, buf, BUF_LEN);
datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':',
buf, BUF_LEN);
whack_log(RC_COMMENT, " serial: %s", buf);
form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s"
, 8*keysize, keyid
, cert->smartcard ? ", on smartcard" :
(has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " validity: not before %T %s",
&cert->notBefore, utc,
(cert->notBefore < now)?"ok":"fatal (not valid yet)");
whack_log(RC_COMMENT, " not after %T %s",
&cert->notAfter, utc,
check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
key_type_names, key->get_type(key),
key->get_keysize(key) * BITS_PER_BYTE,
cert->smartcard ? ", on smartcard" :
(has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " keyid: %Y",
key->get_id(key, ID_PUBKEY_INFO_SHA1));
if (cert->subjectKeyID.ptr != NULL)
{
datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':'
, buf, BUF_LEN);
datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':',
buf, BUF_LEN);
whack_log(RC_COMMENT, " subjkey: %s", buf);
}
if (cert->authKeyID.ptr != NULL)
{
datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
, buf, BUF_LEN);
datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':',
buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf);
}
if (cert->authKeySerialNumber.ptr != NULL)
{
datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len
, ':', buf, BUF_LEN);
datatot(cert->authKeySerialNumber.ptr,
cert->authKeySerialNumber.len, ':', buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf);
}
}
+52 -52
View File
@@ -2,7 +2,7 @@
* Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
* Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
* Copyright (C) 2002 Mario Strasser
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2000-2009 Andreas Steffen, Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -18,8 +18,10 @@
#ifndef _X509_H
#define _X509_H
#include <credentials/keys/public_key.h>
#include <credentials/keys/private_key.h>
#include "constants.h"
#include "pkcs1.h"
#include "id.h"
/* Definition of generalNames kinds */
@@ -51,46 +53,42 @@ struct generalName {
typedef struct x509cert x509cert_t;
struct x509cert {
x509cert_t *next;
time_t installed;
int count;
bool smartcard;
u_char authority_flags;
chunk_t certificate;
chunk_t tbsCertificate;
u_int version;
chunk_t serialNumber;
/* signature */
int sigAlg;
chunk_t issuer;
/* validity */
time_t notBefore;
time_t notAfter;
chunk_t subject;
/* subjectPublicKeyInfo */
enum pubkey_alg subjectPublicKeyAlgorithm;
chunk_t subjectPublicKey;
chunk_t modulus;
chunk_t publicExponent;
/* issuerUniqueID */
/* subjectUniqueID */
/* v3 extensions */
/* extension */
/* extension */
/* extnID */
/* critical */
/* extnValue */
bool isCA;
bool isOcspSigner; /* ocsp */
chunk_t subjectKeyID;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
chunk_t accessLocation; /* ocsp */
generalName_t *subjectAltName;
generalName_t *crlDistributionPoints;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
x509cert_t *next;
time_t installed;
int count;
bool smartcard;
u_char authority_flags;
chunk_t certificate;
chunk_t tbsCertificate;
u_int version;
chunk_t serialNumber;
/* signature */
int sigAlg;
chunk_t issuer;
/* validity */
time_t notBefore;
time_t notAfter;
chunk_t subject;
public_key_t *public_key;
/* issuerUniqueID */
/* subjectUniqueID */
/* v3 extensions */
/* extension */
/* extension */
/* extnID */
/* critical */
/* extnValue */
bool isCA;
bool isOcspSigner; /* ocsp */
chunk_t subjectKeyID;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
chunk_t accessLocation; /* ocsp */
generalName_t *subjectAltName;
generalName_t *crlDistributionPoints;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
};
/* used for initialization */
@@ -104,8 +102,8 @@ extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b);
extern void hex_str(chunk_t bin, chunk_t *str);
extern int dn_count_wildcards(chunk_t dn);
extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn
, const char* null_dn);
extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn,
const char* null_dn);
extern err_t atodn(char *src, chunk_t *dn);
extern void gntoid(struct id *id, const generalName_t *gn);
extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID);
@@ -116,21 +114,23 @@ extern void parse_authorityKeyIdentifier(chunk_t blob, int level0
, chunk_t *authKeyID, chunk_t *authKeySerialNumber);
extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
extern err_t check_validity(const x509cert_t *cert, time_t *until);
extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg
, int enc_alg, const x509cert_t *issuer_cert);
extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
const x509cert_t *issuer_cert);
extern chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
bool bit_string);
extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until);
extern x509cert_t* add_x509cert(x509cert_t *cert);
extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid
, x509cert_t* chain);
extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
, const RSA_private_key_t *signer_key);
extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid,
x509cert_t* chain);
extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
private_key_t *signer_key);
extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames);
extern void share_x509cert(x509cert_t *cert);
extern void release_x509cert(x509cert_t *cert);
extern void free_x509cert(x509cert_t *cert);
extern void store_x509certs(x509cert_t **firstcert, bool strict);
extern void list_x509cert_chain(const char *caption, x509cert_t* cert
, u_char auth_flags, bool utc);
extern void list_x509cert_chain(const char *caption, x509cert_t* cert,
u_char auth_flags, bool utc);
extern void list_x509_end_certs(bool utc);
extern void free_generalNames(generalName_t* gn, bool free_name);
+3 -6
View File
@@ -1,5 +1,5 @@
ipsec_PROGRAMS = scepclient
scepclient_SOURCES = scepclient.c rsakey.c rsakey.h pkcs10.c pkcs10.h scep.c scep.h loglite.c
scepclient_SOURCES = scepclient.c pkcs10.c pkcs10.h scep.c scep.h loglite.c
PLUTODIR=$(top_srcdir)/src/pluto
OPENACDIR=$(top_srcdir)/src/openac
@@ -28,7 +28,7 @@ LIBCRYPTOBUILDDIR=$(top_builddir)/src/libcrypto
scepclient_LDADD = \
ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o \
mp_defs.o ocsp.o pem.o pgp.o pkcs1.o pkcs7.o smartcard.o x509.o \
mp_defs.o ocsp.o pem.o pgpcert.o pkcs7.o smartcard.o x509.o \
$(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \
$(LIBFREESWANBUILDDIR)/libfreeswan.a \
-lgmp
@@ -77,10 +77,7 @@ ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
$(COMPILE) $(INCLUDES) -c -o $@ $<
pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
$(COMPILE) $(INCLUDES) -c -o $@ $<
pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
pgpcert.o : $(PLUTODIR)/pgpcert.c $(PLUTODIR)/pgpcert.h
$(COMPILE) $(INCLUDES) -c -o $@ $<
pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
+21 -17
View File
@@ -31,7 +31,6 @@
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/log.h"
#include "../pluto/x509.h"
@@ -158,21 +157,25 @@ build_req_info_attributes(pkcs10_t* pkcs10)
static chunk_t
pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
{
RSA_public_key_t *rsak = (RSA_public_key_t *) pkcs10->private_key;
chunk_t key = pkcs10->public_key->get_encoding(pkcs10->public_key);
chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm"
, ASN1_INTEGER_0
, pkcs10->subject
, pkcs1_build_publicKeyInfo(rsak)
, build_req_info_attributes(pkcs10));
chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
asn1_bitstring("m", key));
chunk_t signature = pkcs1_build_signature(cert_req_info
, signature_alg, pkcs10->private_key, TRUE);
chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm",
ASN1_INTEGER_0,
pkcs10->subject,
keyInfo,
build_req_info_attributes(pkcs10));
return asn1_wrap(ASN1_SEQUENCE, "mcm"
, cert_req_info
, asn1_algorithmIdentifier(signature_alg)
, signature);
chunk_t signature = x509_build_signature(cert_req_info, signature_alg,
pkcs10->private_key, TRUE);
return asn1_wrap(ASN1_SEQUENCE, "mcm",
cert_req_info,
asn1_algorithmIdentifier(signature_alg),
signature);
}
/**
@@ -189,14 +192,15 @@ pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
* @param[in] subjectAltNames linked list of subjectAltNames or NULL
* @return pointer to a #pkcs10_t object
*/
pkcs10_t*
pkcs10_build(RSA_private_key_t *key, chunk_t subject, chunk_t challengePassword
, generalName_t *subjectAltNames, int signature_alg)
pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public,
chunk_t subject, chunk_t challengePassword,
generalName_t *subjectAltNames, int signature_alg)
{
pkcs10_t *pkcs10 = malloc_thing(pkcs10_t);
pkcs10->subject = subject;
pkcs10->private_key = key;
pkcs10->private_key = private;
pkcs10->public_key = public;
pkcs10->challengePassword = challengePassword;
pkcs10->subjectAltNames = subjectAltNames;
+14 -11
View File
@@ -23,8 +23,10 @@
#ifndef _PKCS10_H
#define _PKCS10_H
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/x509.h"
typedef struct pkcs10_struct pkcs10_t;
@@ -38,20 +40,21 @@ typedef struct pkcs10_struct pkcs10_t;
* The RSA private key is needed to compute the signature of the given request
*/
struct pkcs10_struct {
RSA_private_key_t *private_key;
chunk_t request;
chunk_t subject;
chunk_t challengePassword;
generalName_t *subjectAltNames;
private_key_t *private_key;
public_key_t *public_key;
chunk_t request;
chunk_t subject;
chunk_t challengePassword;
generalName_t *subjectAltNames;
};
extern const pkcs10_t empty_pkcs10;
extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames
, generalNames_t kind, char *value);
extern pkcs10_t* pkcs10_build(RSA_private_key_t *key, chunk_t subject
, chunk_t challengePassword, generalName_t *subjectAltNames
, int signature_alg);
extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames,
generalNames_t kind, char *value);
extern pkcs10_t* pkcs10_build(private_key_t *private, public_key_t *public,
chunk_t subject, chunk_t challengePassword,
generalName_t *subjectAltNames, int signature_alg);
extern void pkcs10_free(pkcs10_t *pkcs10);
#endif /* _PKCS10_H */
-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/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/fetch.h"
#include "../pluto/log.h"
@@ -266,35 +265,43 @@ end:
* Generates a unique fingerprint of the pkcs10 request
* by computing an MD5 hash over it
*/
void scep_generate_pkcs10_fingerprint(chunk_t pkcs10, chunk_t *fingerprint)
chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10)
{
char buf[HASH_SIZE_MD5];
chunk_t digest = { buf, sizeof(buf) };
char digest_buf[HASH_SIZE_MD5];
chunk_t digest = chunk_from_buf(digest_buf);
hasher_t *hasher;
/* the fingerprint is the MD5 hash in hexadecimal format */
compute_digest(pkcs10, OID_MD5, &digest);
fingerprint->len = 2*digest.len;
fingerprint->ptr = malloc(fingerprint->len + 1);
datatot(digest.ptr, digest.len, 16, fingerprint->ptr, fingerprint->len + 1);
hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
hasher->get_hash(hasher, pkcs10, digest_buf);
hasher->destroy(hasher);
return chunk_to_hex(digest, NULL, FALSE);
}
/**
* Generate a transaction id as the MD5 hash of an public key
* the transaction id is also used as a unique serial number
*/
void scep_generate_transaction_id(const RSA_public_key_t *rsak,
chunk_t *transID, chunk_t *serialNumber)
void scep_generate_transaction_id(public_key_t *key, chunk_t *transID,
chunk_t *serialNumber)
{
char buf[HASH_SIZE_MD5];
chunk_t digest = { buf, sizeof(buf) };
chunk_t public_key = pkcs1_build_publicKeyInfo(rsak);
char digest_buf[HASH_SIZE_MD5];
chunk_t digest = chunk_from_buf(digest_buf);
chunk_t keyEncoding, keyInfo;
hasher_t *hasher;
bool msb_set;
u_char *pos;
keyEncoding = key->get_encoding(key);
compute_digest(public_key, OID_MD5, &digest);
free(public_key.ptr);
keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
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? */
msb_set = (*digest.ptr & 0x80) == 0x80;
@@ -376,7 +383,7 @@ chunk_t scep_senderNonce_attribute(void)
chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
const x509cert_t *enc_cert, int enc_alg,
const x509cert_t *signer_cert, int digest_alg,
const RSA_private_key_t *private_key)
private_key_t *private_key)
{
chunk_t envelopedData, attributes, request;
+13 -13
View File
@@ -24,7 +24,6 @@
#define _SCEP_H
#include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/pkcs7.h"
/* supported SCEP operation types */
@@ -74,20 +73,21 @@ typedef struct {
extern const scep_attributes_t empty_scep_attributes;
extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs);
extern void scep_generate_pkcs10_fingerprint(chunk_t pkcs10
, chunk_t *fingerprint);
extern void scep_generate_transaction_id(const RSA_public_key_t *rsak
, chunk_t *transID, chunk_t *serialNumber);
extern void scep_generate_transaction_id(public_key_t *key,
chunk_t *transID,
chunk_t *serialNumber);
extern chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10);
extern chunk_t scep_transId_attribute(chunk_t transaction_id);
extern chunk_t scep_messageType_attribute(scep_msg_t m);
extern chunk_t scep_senderNonce_attribute(void);
extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
, const x509cert_t *enc_cert, int enc_alg
, const x509cert_t *signer_cert, int digest_alg
, const RSA_private_key_t *private_key);
extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
, bool http_get_request, chunk_t *response);
extern err_t scep_parse_response(chunk_t response, chunk_t transID
, contentInfo_t *data, scep_attributes_t *attrs, x509cert_t *signer_cert);
extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
const x509cert_t *enc_cert, int enc_alg,
const x509cert_t *signer_cert, int digest_alg,
private_key_t *private_key);
extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op,
bool http_get_request, chunk_t *response);
extern err_t scep_parse_response(chunk_t response, chunk_t transID,
contentInfo_t *data, scep_attributes_t *attrs,
x509cert_t *signer_cert);
#endif /* _SCEP_H */
+24 -25
View File
@@ -42,15 +42,15 @@
#include <asn1/oid.h>
#include <utils/optionsfrom.h>
#include <utils/enumerator.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/log.h"
#include "../pluto/pkcs1.h"
#include "../pluto/pkcs7.h"
#include "../pluto/certs.h"
#include "rsakey.h"
#include "pkcs10.h"
#include "scep.h"
@@ -120,7 +120,8 @@ options_t *options;
* Global variables
*/
RSA_private_key_t *private_key = NULL;
private_key_t *private_key = NULL;
public_key_t *public_key = NULL;
chunk_t pkcs1;
chunk_t pkcs7;
@@ -150,11 +151,8 @@ exit_scepclient(err_t message, ...)
{
int status = 0;
if (private_key != NULL)
{
free_RSA_private_content(private_key);
free(private_key);
}
DESTROY_IF(private_key);
DESTROY_IF(public_key);
free(pkcs1.ptr);
free(pkcs7.ptr);
free(subject.ptr);
@@ -784,24 +782,27 @@ int main(int argc, char **argv)
/*
* input of PKCS#1 file
*/
private_key = malloc_thing(RSA_private_key_t);
if (filetype_in & PKCS1) /* load an RSA key pair from file */
{
prompt_pass_t pass = { "", FALSE, STDIN_FILENO };
char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
ugh = load_rsa_private_key(path, &pass, private_key);
private_key = load_private_key(path, &pass, KEY_RSA);
}
else /* generate an RSA key pair */
{
ugh = generate_rsa_private_key(rsa_keylength, private_key);
private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_KEY_SIZE, rsa_keylength,
BUILD_END);
}
if (ugh != NULL)
exit_scepclient(ugh);
if (private_key == NULL)
{
exit_scepclient("no RSA private key available");
}
public_key = private_key->get_public_key(private_key);
/* check for minimum key length */
if ((private_key->pub.k) < RSA_MIN_OCTETS)
if (private_key->get_keysize(private_key) < RSA_MIN_OCTETS)
{
exit_scepclient("length of RSA key has to be at least %d bits"
,RSA_MIN_OCTETS * BITS_PER_BYTE);
@@ -855,10 +856,11 @@ int main(int argc, char **argv)
DBG(DBG_CONTROL,
DBG_log("building pkcs10 object:")
)
pkcs10 = pkcs10_build(private_key, subject, challengePassword
, subjectAltNames, pkcs10_signature_alg);
scep_generate_pkcs10_fingerprint(pkcs10->request, &fingerprint);
plog(" fingerprint: %.*s", (int)fingerprint.len, fingerprint.ptr);
pkcs10 = pkcs10_build(private_key, public_key, subject,
challengePassword, subjectAltNames,
pkcs10_signature_alg);
fingerprint = scep_generate_pkcs10_fingerprint(pkcs10->request);
plog(" fingerprint: %s", fingerprint.ptr);
}
/*
@@ -889,7 +891,7 @@ int main(int argc, char **argv)
DBG(DBG_CONTROL,
DBG_log("building pkcs1 object:")
)
pkcs1 = pkcs1_build_private_key(private_key);
pkcs1 = private_key->get_encoding(private_key);
if (!chunk_write(pkcs1, path, "pkcs1", 0066, force))
exit_scepclient("could not write pkcs1 file '%s'", path);
@@ -902,8 +904,7 @@ int main(int argc, char **argv)
exit_scepclient(NULL); /* no further output required */
}
scep_generate_transaction_id((const RSA_public_key_t *)private_key
, &transID, &serialNumber);
scep_generate_transaction_id(public_key, &transID, &serialNumber);
plog(" transaction ID: %.*s", (int)transID.len, transID.ptr);
/* generate a self-signed X.509 certificate */
@@ -918,9 +919,7 @@ int main(int argc, char **argv)
: x509_signer->notBefore + validity;
x509_signer->subject = subject;
x509_signer->subjectAltName = subjectAltNames;
build_x509cert(x509_signer, (const RSA_public_key_t *)private_key
, private_key);
build_x509cert(x509_signer, public_key, private_key);
/*
* output of self-signed X.509 certificate file
+15 -3
View File
@@ -6,12 +6,11 @@ charon {
threads = 16
# plugins to load in charon
# load = aes des gmp hmac md5 random sha1 sha2 pubkey xcbc x509 stroke
# load = aes des sha1 md5 sha2 hmac gmp random pubkey xcbc x509 stroke
plugins {
sql {
# loglevel to log into sql database
loglevel = -1
@@ -23,3 +22,16 @@ charon {
# ...
}
pluto {
# plugins to load in pluto
# load = aes des sha1 md5 sha2 hmac gmp random pubkey
}
libstrongswan {
# set to no, the DH exponent size is optimized
# dh_exponent_ansi_x9_42 = no
}