pluto and scepclient use private and public key plugins of libstrongswan
This commit is contained in:
committed by
Martin Willi
parent
b00fbdb55a
commit
8b799d55ce
@@ -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 \
|
||||
|
||||
@@ -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').
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+15
-20
@@ -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
@@ -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");
|
||||
|
||||
@@ -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));
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user