diff options
Diffstat (limited to 'src')
8 files changed, 333 insertions, 511 deletions
diff --git a/src/libstrongswan/credentials/keys/key_encoding.h b/src/libstrongswan/credentials/keys/key_encoding.h index a8fbfa65a..ea97a1f2d 100644 --- a/src/libstrongswan/credentials/keys/key_encoding.h +++ b/src/libstrongswan/credentials/keys/key_encoding.h @@ -102,6 +102,14 @@ enum key_encoding_part_t { KEY_PART_RSA_EXP2, /** coefficient of RSA key, coeff */ KEY_PART_RSA_COEFF, + /** a DER encoded RSA public key */ + KEY_PART_RSA_PUB_ASN1_DER, + /** a DER encoded RSA private key */ + KEY_PART_RSA_PRIV_ASN1_DER, + /** a DER encoded ECDSA public key */ + KEY_PART_ECDSA_PUB_ASN1_DER, + /** a DER encoded ECDSA private key */ + KEY_PART_ECDSA_PRIV_ASN1_DER, KEY_PART_END, }; diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c index d6b442ae9..945e36968 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -21,6 +22,7 @@ #include <openssl/evp.h> #include <openssl/ecdsa.h> +#include <openssl/x509.h> typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t; @@ -37,16 +39,6 @@ struct private_openssl_ec_private_key_t { * EC key object */ EC_KEY *ec; - - /** - * Keyid formed as a SHA-1 hash of a privateKey object - */ - identification_t* keyid; - - /** - * Keyid formed as a SHA-1 hash of a privateKeyInfo object - */ - identification_t* keyid_info; /** * reference count @@ -107,15 +99,6 @@ static bool lookup_scheme(int scheme, int *hash, int *curve) } /** - * shared functions, implemented in openssl_ec_public_key.c - */ -bool openssl_ec_public_key_build_id(EC_KEY *ec, identification_t **keyid, - identification_t **keyid_info); - -openssl_ec_public_key_t *openssl_ec_public_key_create_from_private_key(EC_KEY *ec); - - -/** * Convert an ECDSA_SIG to a chunk by concatenating r and s. * This function allocates memory for the chunk. */ @@ -130,9 +113,10 @@ static bool sig2chunk(const EC_GROUP *group, ECDSA_SIG *sig, chunk_t *chunk) static bool build_signature(private_openssl_ec_private_key_t *this, chunk_t hash, chunk_t *signature) { - ECDSA_SIG *sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec); + ECDSA_SIG *sig; bool success; - + + sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec); if (!sig) { return FALSE; @@ -157,7 +141,7 @@ static bool sign(private_openssl_ec_private_key_t *this, signature_scheme_t sche chunk_t data, chunk_t *signature) { bool success; - + if (scheme == SIGN_ECDSA_WITH_NULL) { success = build_signature(this, data, signature); @@ -168,14 +152,14 @@ static bool sign(private_openssl_ec_private_key_t *this, signature_scheme_t sche const EC_GROUP *my_group; chunk_t hash = chunk_empty; int hash_type, curve; - + if (!lookup_scheme(scheme, &hash_type, &curve)) { DBG1("signature scheme %N not supported in EC", signature_scheme_names, scheme); return FALSE; } - + req_group = EC_GROUP_new_by_curve_name(curve); if (!req_group) { @@ -183,7 +167,7 @@ static bool sign(private_openssl_ec_private_key_t *this, signature_scheme_t sche signature_scheme_names, scheme); return FALSE; } - + my_group = EC_KEY_get0_group(this->ec); if (EC_GROUP_cmp(my_group, req_group, NULL) != 0) { @@ -192,7 +176,7 @@ static bool sign(private_openssl_ec_private_key_t *this, signature_scheme_t sche return FALSE; } EC_GROUP_free(req_group); - + if (!openssl_hash_chunk(hash_type, data, &hash)) { return FALSE; @@ -222,73 +206,73 @@ static size_t get_keysize(private_openssl_ec_private_key_t *this) } /** - * Implementation of private_key_t.get_id. - */ -static identification_t* get_id(private_openssl_ec_private_key_t *this, - id_type_t type) -{ - switch (type) - { - case ID_PUBKEY_INFO_SHA1: - return this->keyid_info; - case ID_PUBKEY_SHA1: - return this->keyid; - default: - return NULL; - } -} - -/** * Implementation of private_key_t.get_public_key. */ -static openssl_ec_public_key_t* get_public_key(private_openssl_ec_private_key_t *this) +static public_key_t* get_public_key(private_openssl_ec_private_key_t *this) { - return openssl_ec_public_key_create_from_private_key(this->ec); + public_key_t *public; + chunk_t key; + u_char *p; + + key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); + p = key.ptr; + i2d_EC_PUBKEY(this->ec, &p); + + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, + BUILD_BLOB_ASN1_DER, key, BUILD_END); + free(key.ptr); + return public; } /** - * Implementation of private_key_t.belongs_to. + * Implementation of private_key_t.get_fingerprint. */ -static bool belongs_to(private_openssl_ec_private_key_t *this, public_key_t *public) +static bool get_fingerprint(private_openssl_ec_private_key_t *this, + key_encoding_type_t type, chunk_t *fingerprint) { - identification_t *keyid; - - if (public->get_type(public) != KEY_ECDSA) - { - return FALSE; - } - keyid = public->get_id(public, ID_PUBKEY_SHA1); - if (keyid && keyid->equals(keyid, this->keyid)) - { - return TRUE; - } - keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); - if (keyid && keyid->equals(keyid, this->keyid_info)) + chunk_t key; + u_char *p; + bool success; + + if (lib->encoding->get_cache(lib->encoding, type, this, fingerprint)) { return TRUE; } - return FALSE; + key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); + p = key.ptr; + i2d_EC_PUBKEY(this->ec, &p); + success = lib->encoding->encode(lib->encoding, type, this, fingerprint, + KEY_PART_ECDSA_PUB_ASN1_DER, key, KEY_PART_END); + free(key.ptr); + return success; } /** * Implementation of private_key_t.get_encoding. */ -static chunk_t get_encoding(private_openssl_ec_private_key_t *this) +static bool get_encoding(private_openssl_ec_private_key_t *this, + key_encoding_type_t type, chunk_t *encoding) { - chunk_t enc = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL)); - u_char *p = enc.ptr; + chunk_t key; + u_char *p; + bool success; + + key = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL)); + p = key.ptr; i2d_ECPrivateKey(this->ec, &p); - return enc; + success = lib->encoding->encode(lib->encoding, type, NULL, encoding, + KEY_PART_ECDSA_PRIV_ASN1_DER, key, KEY_PART_END); + free(key.ptr); + return success; } /** * Implementation of private_key_t.get_ref. */ -static private_openssl_ec_private_key_t* get_ref(private_openssl_ec_private_key_t *this) +static private_key_t* get_ref(private_openssl_ec_private_key_t *this) { ref_get(&this->ref); - return this; - + return &this->public.interface; } /** @@ -302,8 +286,7 @@ static void destroy(private_openssl_ec_private_key_t *this) { EC_KEY_free(this->ec); } - DESTROY_IF(this->keyid); - DESTROY_IF(this->keyid_info); + lib->encoding->clear_cache(lib->encoding, this); free(this); } } @@ -311,7 +294,7 @@ static void destroy(private_openssl_ec_private_key_t *this) /** * Internal generic constructor */ -static private_openssl_ec_private_key_t *openssl_ec_private_key_create_empty(void) +static private_openssl_ec_private_key_t *create_empty(void) { private_openssl_ec_private_key_t *this = malloc_thing(private_openssl_ec_private_key_t); @@ -319,16 +302,15 @@ static private_openssl_ec_private_key_t *openssl_ec_private_key_create_empty(voi 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.equals = private_key_equals; + this->public.interface.belongs_to = private_key_belongs_to; + this->public.interface.get_fingerprint = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_encoding = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *encoding))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->ec = NULL; - this->keyid = NULL; - this->keyid_info = NULL; this->ref = 1; return this; @@ -340,34 +322,25 @@ static private_openssl_ec_private_key_t *openssl_ec_private_key_create_empty(voi static openssl_ec_private_key_t *load(chunk_t blob) { u_char *p = blob.ptr; - private_openssl_ec_private_key_t *this = openssl_ec_private_key_create_empty(); + private_openssl_ec_private_key_t *this = create_empty(); this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&p, blob.len); - chunk_clear(&blob); - if (!this->ec) { destroy(this); return NULL; } - - if (!openssl_ec_public_key_build_id(this->ec, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } - if (!EC_KEY_check_key(this->ec)) { destroy(this); return NULL; } - return &this->public; } typedef struct private_builder_t private_builder_t; + /** * Builder implementation for key loading/generation */ @@ -397,15 +370,13 @@ static void add(private_builder_t *this, builder_part_t part, ...) if (!this->key) { va_list args; - chunk_t chunk; switch (part) { case BUILD_BLOB_ASN1_DER: { va_start(args, part); - chunk = va_arg(args, chunk_t); - this->key = load(chunk_clone(chunk)); + this->key = load(va_arg(args, chunk_t)); va_end(args); return; } diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c index 635a106dd..4d0af04b4 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -39,16 +40,6 @@ struct private_openssl_ec_public_key_t { EC_KEY *ec; /** - * Keyid formed as a SHA-1 hash of a publicKeyInfo object - */ - identification_t *keyid_info; - - /** - * Keyid formed as a SHA-1 hash of a publicKey object - */ - identification_t *keyid; - - /** * reference counter */ refcount_t ref; @@ -187,7 +178,8 @@ static bool verify(private_openssl_ec_public_key_t *this, signature_scheme_t sch /** * Implementation of public_key_t.get_keysize. */ -static bool encrypt_(private_openssl_ec_public_key_t *this, chunk_t crypto, chunk_t *plain) +static bool encrypt_(private_openssl_ec_public_key_t *this, + chunk_t crypto, chunk_t *plain) { DBG1("EC public key encryption not implemented"); return FALSE; @@ -202,64 +194,54 @@ static size_t get_keysize(private_openssl_ec_public_key_t *this) } /** - * Implementation of public_key_t.get_id. + * Implementation of private_key_t.get_fingerprint. */ -static identification_t *get_id(private_openssl_ec_public_key_t *this, - id_type_t type) +static bool get_fingerprint(private_openssl_ec_public_key_t *this, + key_encoding_type_t type, chunk_t *fingerprint) { - switch (type) + chunk_t key; + u_char *p; + bool success; + + if (lib->encoding->get_cache(lib->encoding, type, this, fingerprint)) { - case ID_PUBKEY_INFO_SHA1: - return this->keyid_info; - case ID_PUBKEY_SHA1: - return this->keyid; - default: - return NULL; + return TRUE; } + key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); + p = key.ptr; + i2d_EC_PUBKEY(this->ec, &p); + success = lib->encoding->encode(lib->encoding, type, this, fingerprint, + KEY_PART_ECDSA_PUB_ASN1_DER, key, KEY_PART_END); + free(key.ptr); + return success; } /** - * Encodes the public key - */ -static chunk_t get_encoding_raw(EC_KEY *ec) -{ - /* since the points can be stored in three different forms this may not - * be correct for all cases */ - const EC_GROUP *group = EC_KEY_get0_group(ec); - const EC_POINT *pub = EC_KEY_get0_public_key(ec); - chunk_t enc = chunk_alloc(EC_POINT_point2oct(group, pub, - POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL)); - EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED, - enc.ptr, enc.len, NULL); - return enc; -} - -/** - * Encodes the public key info (public key with ec parameters) - */ -static chunk_t get_encoding_full(EC_KEY *ec) -{ - chunk_t enc = chunk_alloc(i2d_EC_PUBKEY(ec, NULL)); - u_char *p = enc.ptr; - i2d_EC_PUBKEY(ec, &p); - return enc; -} - -/* - * Implementation of public_key_t.get_encoding. + * Implementation of private_key_t.get_encoding. */ -static chunk_t get_encoding(private_openssl_ec_public_key_t *this) +static bool get_encoding(private_openssl_ec_public_key_t *this, + key_encoding_type_t type, chunk_t *encoding) { - return get_encoding_full(this->ec); + chunk_t key; + u_char *p; + bool success; + + key = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); + p = key.ptr; + i2d_EC_PUBKEY(this->ec, &p); + success = lib->encoding->encode(lib->encoding, type, NULL, encoding, + KEY_PART_ECDSA_PUB_ASN1_DER, key, KEY_PART_END); + free(key.ptr); + return success; } /** * Implementation of public_key_t.get_ref. */ -static private_openssl_ec_public_key_t* get_ref(private_openssl_ec_public_key_t *this) +static public_key_t* get_ref(private_openssl_ec_public_key_t *this) { ref_get(&this->ref); - return this; + return &this->public.interface; } /** @@ -273,8 +255,7 @@ static void destroy(private_openssl_ec_public_key_t *this) { EC_KEY_free(this->ec); } - DESTROY_IF(this->keyid); - DESTROY_IF(this->keyid_info); + lib->encoding->clear_cache(lib->encoding, this); free(this); } } @@ -282,7 +263,7 @@ static void destroy(private_openssl_ec_public_key_t *this) /** * Generic private constructor */ -static private_openssl_ec_public_key_t *openssl_ec_public_key_create_empty() +static private_openssl_ec_public_key_t *create_empty() { private_openssl_ec_public_key_t *this = malloc_thing(private_openssl_ec_public_key_t); @@ -290,90 +271,38 @@ static private_openssl_ec_public_key_t *openssl_ec_public_key_create_empty() 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.equals = public_key_equals; + this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))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->ec = NULL; - this->keyid = NULL; - this->keyid_info = NULL; this->ref = 1; return this; } /** - * Build key identifier from the public key using SHA1 hashed publicKey(Info). - * Also used in openssl_ec_private_key.c. - */ -bool openssl_ec_public_key_build_id(EC_KEY *ec, identification_t **keyid, - identification_t **keyid_info) -{ - chunk_t publicKeyInfo, publicKey, hash; - hasher_t *hasher; - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - DBG1("SHA1 hash algorithm not supported, unable to use EC"); - return FALSE; - } - - publicKey = get_encoding_raw(ec); - - hasher->allocate_hash(hasher, publicKey, &hash); - *keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash); - chunk_free(&hash); - - publicKeyInfo = get_encoding_full(ec); - - hasher->allocate_hash(hasher, publicKeyInfo, &hash); - *keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash); - chunk_free(&hash); - - hasher->destroy(hasher); - chunk_free(&publicKeyInfo); - chunk_free(&publicKey); - - return TRUE; -} - -/** * Load a public key from an ASN1 encoded blob */ static openssl_ec_public_key_t *load(chunk_t blob) { + private_openssl_ec_public_key_t *this = create_empty(); u_char *p = blob.ptr; - private_openssl_ec_public_key_t *this = openssl_ec_public_key_create_empty(); this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&p, blob.len); - chunk_clear(&blob); - if (!this->ec) { destroy(this); return NULL; } - - if (!openssl_ec_public_key_build_id(this->ec, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } return &this->public; } -/** - * Create a public key from BIGNUM values, used in openssl_ec_private_key.c - */ -openssl_ec_public_key_t *openssl_ec_public_key_create_from_private_key(EC_KEY *ec) -{ - return (openssl_ec_public_key_t*)load(get_encoding_full(ec)); -} - typedef struct private_builder_t private_builder_t; + /** * Builder implementation for key loading */ @@ -403,15 +332,13 @@ static void add(private_builder_t *this, builder_part_t part, ...) if (!this->key) { va_list args; - chunk_t chunk; - + switch (part) { case BUILD_BLOB_ASN1_DER: { va_start(args, part); - chunk = va_arg(args, chunk_t); - this->key = load(chunk_clone(chunk)); + this->key = load(va_arg(args, chunk_t)); va_end(args); return; } diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index ce6716f5a..53c3e6816 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -24,6 +24,7 @@ #include <library.h> #include <utils/mutex.h> +#include "openssl_util.h" #include "openssl_crypter.h" #include "openssl_hasher.h" #include "openssl_diffie_hellman.h" @@ -182,6 +183,8 @@ static void destroy(private_openssl_plugin_t *this) lib->creds->remove_builder(lib->creds, (builder_constructor_t)openssl_ec_public_key_builder); + lib->encoding->remove_encoder(lib->encoding, openssl_encode); + ENGINE_cleanup(); EVP_cleanup(); CONF_modules_free(); @@ -291,5 +294,8 @@ plugin_t *plugin_create() lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, (builder_constructor_t)openssl_ec_public_key_builder); + /* fingerprinting/encoding */ + lib->encoding->add_encoder(lib->encoding, openssl_encode); + return &this->public.plugin; } diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index 95c0ffdc8..c61cae71f 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -47,34 +48,14 @@ struct private_openssl_rsa_private_key_t { * TRUE if the key is from an OpenSSL ENGINE and might not be readable */ bool engine; - - /** - * Keyid formed as a SHA-1 hash of a privateKey object - */ - identification_t* keyid; - - /** - * Keyid formed as a SHA-1 hash of a privateKeyInfo object - */ - identification_t* keyid_info; /** * reference count */ - refcount_t ref; + refcount_t ref; }; /** - * shared functions, implemented in openssl_rsa_public_key.c - */ -bool openssl_rsa_public_key_build_id(RSA *rsa, identification_t **keyid, - identification_t **keyid_info); - - -openssl_rsa_public_key_t *openssl_rsa_public_key_create_from_n_e(BIGNUM *n, BIGNUM *e); - - -/** * Build an EMPSA PKCS1 signature described in PKCS#1 */ static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this, @@ -98,13 +79,13 @@ static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this, EVP_PKEY *key; const EVP_MD *hasher; u_int len; - + hasher = EVP_get_digestbynid(type); if (!hasher) { return FALSE; } - + ctx = EVP_MD_CTX_create(); key = EVP_PKEY_new(); if (!ctx || !key) @@ -201,95 +182,67 @@ static size_t get_keysize(private_openssl_rsa_private_key_t *this) } /** - * Implementation of openssl_rsa_private_key.get_id. - */ -static identification_t* get_id(private_openssl_rsa_private_key_t *this, - id_type_t type) -{ - switch (type) - { - case ID_PUBKEY_INFO_SHA1: - return this->keyid_info; - case ID_PUBKEY_SHA1: - return this->keyid; - default: - return NULL; - } -} - -/** * 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) -{ - return openssl_rsa_public_key_create_from_n_e(this->rsa->n, this->rsa->e); -} - -/** - * Implementation of openssl_rsa_private_key.equals. - */ -static bool equals(private_openssl_rsa_private_key_t *this, private_key_t *other) +static public_key_t* get_public_key(private_openssl_rsa_private_key_t *this) { - 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; + chunk_t enc; + public_key_t *key; + u_char *p; + + enc = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); + p = enc.ptr; + i2d_RSAPublicKey(this->rsa, &p); + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, enc, BUILD_END); + free(enc.ptr); + return key; } /** - * Implementation of openssl_rsa_private_key.belongs_to. + * Implementation of public_key_t.get_fingerprint. */ -static bool belongs_to(private_openssl_rsa_private_key_t *this, public_key_t *public) +static bool get_fingerprint(private_openssl_rsa_private_key_t *this, + key_encoding_type_t type, chunk_t *fingerprint) { - identification_t *keyid; - - if (public->get_type(public) != KEY_RSA) - { - return FALSE; - } - keyid = public->get_id(public, ID_PUBKEY_SHA1); - if (keyid && keyid->equals(keyid, this->keyid)) - { - return TRUE; - } - keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); - if (keyid && keyid->equals(keyid, this->keyid_info)) + chunk_t enc; + bool success; + u_char *p; + + if (lib->encoding->get_cache(lib->encoding, type, this, fingerprint)) { return TRUE; } - return FALSE; + enc = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); + p = enc.ptr; + i2d_RSAPublicKey(this->rsa, &p); + success = lib->encoding->encode(lib->encoding, type, this, fingerprint, + KEY_PART_RSA_PUB_ASN1_DER, enc, KEY_PART_END); + free(enc.ptr); + return success; } -/** - * Implementation of private_key_t.get_encoding. +/* + * Implementation of public_key_t.get_encoding. */ -static chunk_t get_encoding(private_openssl_rsa_private_key_t *this) +static bool get_encoding(private_openssl_rsa_private_key_t *this, + key_encoding_type_t type, chunk_t *encoding) { - chunk_t enc = chunk_empty; + chunk_t enc; + bool success; + u_char *p; + if (!this->engine) { - enc = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL)); - u_char *p = enc.ptr; - i2d_RSAPrivateKey(this->rsa, &p); + return FALSE; } - return enc; + enc = chunk_alloc(i2d_RSAPrivateKey(this->rsa, NULL)); + p = enc.ptr; + i2d_RSAPrivateKey(this->rsa, &p); + success = lib->encoding->encode(lib->encoding, type, NULL, encoding, + KEY_PART_RSA_PUB_ASN1_DER, enc, KEY_PART_END); + free(enc.ptr); + return success; } /** @@ -299,7 +252,6 @@ static private_openssl_rsa_private_key_t* get_ref(private_openssl_rsa_private_ke { ref_get(&this->ref); return this; - } /** @@ -313,8 +265,7 @@ static void destroy(private_openssl_rsa_private_key_t *this) { RSA_free(this->rsa); } - DESTROY_IF(this->keyid); - DESTROY_IF(this->keyid_info); + lib->encoding->clear_cache(lib->encoding, this); free(this); } } @@ -322,7 +273,7 @@ static void destroy(private_openssl_rsa_private_key_t *this) /** * Internal generic constructor */ -static private_openssl_rsa_private_key_t *openssl_rsa_private_key_create_empty(void) +static private_openssl_rsa_private_key_t *create_empty(void) { private_openssl_rsa_private_key_t *this = malloc_thing(private_openssl_rsa_private_key_t); @@ -330,17 +281,15 @@ static private_openssl_rsa_private_key_t *openssl_rsa_private_key_create_empty(v 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.equals = private_key_equals; + this->public.interface.belongs_to = private_key_belongs_to; + this->public.interface.get_fingerprint = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_encoding = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *encoding))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; - this->keyid_info = NULL; this->ref = 1; return this; @@ -351,16 +300,10 @@ static private_openssl_rsa_private_key_t *openssl_rsa_private_key_create_empty(v */ static openssl_rsa_private_key_t *generate(size_t key_size) { - private_openssl_rsa_private_key_t *this = openssl_rsa_private_key_create_empty(); + private_openssl_rsa_private_key_t *this = create_empty(); this->rsa = RSA_generate_key(key_size, PUBLIC_EXPONENT, NULL, NULL); - if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } - return &this->public; } @@ -370,30 +313,19 @@ static openssl_rsa_private_key_t *generate(size_t key_size) static openssl_rsa_private_key_t *load(chunk_t blob) { u_char *p = blob.ptr; - private_openssl_rsa_private_key_t *this = openssl_rsa_private_key_create_empty(); + private_openssl_rsa_private_key_t *this = create_empty(); this->rsa = d2i_RSAPrivateKey(NULL, (const u_char**)&p, blob.len); - - chunk_clear(&blob); - if (!this->rsa) { destroy(this); return NULL; } - - if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } - if (!RSA_check_key(this->rsa)) { destroy(this); return NULL; } - return &this->public; } @@ -436,15 +368,10 @@ static openssl_rsa_private_key_t *load_from_smartcard(char *keyid, char *pin) } ENGINE_free(engine); - this = openssl_rsa_private_key_create_empty(); + this = create_empty(); this->rsa = EVP_PKEY_get1_RSA(key); this->engine = TRUE; - if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } return &this->public; error: @@ -453,6 +380,7 @@ error: } typedef struct private_builder_t private_builder_t; + /** * Builder implementation for key loading/generation */ @@ -490,15 +418,13 @@ static void add(private_builder_t *this, builder_part_t part, ...) if (!this->key) { va_list args; - chunk_t chunk; - + switch (part) { case BUILD_BLOB_ASN1_DER: { va_start(args, part); - chunk = va_arg(args, chunk_t); - this->key = load(chunk_clone(chunk)); + this->key = load(va_arg(args, chunk_t)); va_end(args); return; } diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index bc1ba35b6..cb3e80a69 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -19,7 +20,6 @@ #include <openssl/evp.h> #include <openssl/rsa.h> -#include <openssl/x509.h> typedef struct private_openssl_rsa_public_key_t private_openssl_rsa_public_key_t; @@ -38,16 +38,6 @@ struct private_openssl_rsa_public_key_t { RSA *rsa; /** - * Keyid formed as a SHA-1 hash of a publicKeyInfo object - */ - identification_t *keyid_info; - - /** - * Keyid formed as a SHA-1 hash of a publicKey object - */ - identification_t *keyid; - - /** * reference counter */ refcount_t ref; @@ -163,41 +153,14 @@ static bool verify(private_openssl_rsa_public_key_t *this, signature_scheme_t sc /** * Implementation of public_key_t.get_keysize. */ -static bool encrypt_(private_openssl_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain) +static bool encrypt_(private_openssl_rsa_public_key_t *this, + chunk_t crypto, chunk_t *plain) { DBG1("RSA public key encryption not implemented"); 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. */ static size_t get_keysize(private_openssl_rsa_public_key_t *this) @@ -206,79 +169,55 @@ static size_t get_keysize(private_openssl_rsa_public_key_t *this) } /** - * Implementation of public_key_t.get_id. + * Implementation of public_key_t.get_fingerprint. */ -static identification_t *get_id(private_openssl_rsa_public_key_t *this, - id_type_t type) +static bool get_fingerprint(private_openssl_rsa_public_key_t *this, + key_encoding_type_t type, chunk_t *fingerprint) { - switch (type) - { - case ID_PUBKEY_INFO_SHA1: - return this->keyid_info; - case ID_PUBKEY_SHA1: - return this->keyid; - default: - return NULL; - } -} - -/** - * Encodes the public key - */ -static chunk_t get_encoding_raw(RSA *rsa) -{ - chunk_t enc = chunk_alloc(i2d_RSAPublicKey(rsa, NULL)); - u_char *p = enc.ptr; - i2d_RSAPublicKey(rsa, &p); - return enc; -} - -/** - * Encodes the public key with the algorithm used - */ -static chunk_t get_encoding_with_algo(RSA *rsa) -{ - u_char *p; chunk_t enc; - X509_PUBKEY *pubkey = X509_PUBKEY_new(); - - ASN1_OBJECT_free(pubkey->algor->algorithm); - pubkey->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); + bool success; + u_char *p; - if (pubkey->algor->parameter == NULL || - pubkey->algor->parameter->type != V_ASN1_NULL) + if (lib->encoding->get_cache(lib->encoding, type, this, fingerprint)) { - ASN1_TYPE_free(pubkey->algor->parameter); - pubkey->algor->parameter = ASN1_TYPE_new(); - pubkey->algor->parameter->type = V_ASN1_NULL; + return TRUE; } - - enc = get_encoding_raw(rsa); - M_ASN1_BIT_STRING_set(pubkey->public_key, enc.ptr, enc.len); - chunk_free(&enc); - - enc = chunk_alloc(i2d_X509_PUBKEY(pubkey, NULL)); + enc = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); p = enc.ptr; - i2d_X509_PUBKEY(pubkey, &p); - X509_PUBKEY_free(pubkey); - return enc; + i2d_RSAPublicKey(this->rsa, &p); + success = lib->encoding->encode(lib->encoding, type, this, fingerprint, + KEY_PART_RSA_PUB_ASN1_DER, enc, KEY_PART_END); + free(enc.ptr); + + return success; } /* * Implementation of public_key_t.get_encoding. */ -static chunk_t get_encoding(private_openssl_rsa_public_key_t *this) +static bool get_encoding(private_openssl_rsa_public_key_t *this, + key_encoding_type_t type, chunk_t *encoding) { - return get_encoding_raw(this->rsa); + chunk_t enc; + bool success; + u_char *p; + + enc = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); + p = enc.ptr; + i2d_RSAPublicKey(this->rsa, &p); + success = lib->encoding->encode(lib->encoding, type, NULL, encoding, + KEY_PART_RSA_PUB_ASN1_DER, enc, KEY_PART_END); + free(enc.ptr); + return success; } /** * Implementation of public_key_t.get_ref. */ -static private_openssl_rsa_public_key_t* get_ref(private_openssl_rsa_public_key_t *this) +static public_key_t* get_ref(private_openssl_rsa_public_key_t *this) { ref_get(&this->ref); - return this; + return &this->public.interface; } /** @@ -292,8 +231,7 @@ static void destroy(private_openssl_rsa_public_key_t *this) { RSA_free(this->rsa); } - DESTROY_IF(this->keyid); - DESTROY_IF(this->keyid_info); + lib->encoding->clear_cache(lib->encoding, this); free(this); } } @@ -301,109 +239,46 @@ static void destroy(private_openssl_rsa_public_key_t *this) /** * Generic private constructor */ -static private_openssl_rsa_public_key_t *openssl_rsa_public_key_create_empty() +static private_openssl_rsa_public_key_t *create_empty() { private_openssl_rsa_public_key_t *this = malloc_thing(private_openssl_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.equals = (bool (*) (public_key_t*, public_key_t*))equals; + this->public.interface.equals = public_key_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; + this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))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; + this->rsa = NULL; this->ref = 1; return this; } /** - * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info). - * Also used in openssl_rsa_private_key.c. - */ -bool openssl_rsa_public_key_build_id(RSA *rsa, identification_t **keyid, - identification_t **keyid_info) -{ - chunk_t publicKeyInfo, publicKey, hash; - hasher_t *hasher; - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - DBG1("SHA1 hash algorithm not supported, unable to use RSA"); - return FALSE; - } - - publicKey = get_encoding_raw(rsa); - - hasher->allocate_hash(hasher, publicKey, &hash); - *keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash); - chunk_free(&hash); - - publicKeyInfo = get_encoding_with_algo(rsa); - - hasher->allocate_hash(hasher, publicKeyInfo, &hash); - *keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash); - chunk_free(&hash); - - hasher->destroy(hasher); - chunk_free(&publicKeyInfo); - chunk_free(&publicKey); - - return TRUE; -} - -/** - * Create a public key from BIGNUM values, used in openssl_rsa_private_key.c - */ -openssl_rsa_public_key_t *openssl_rsa_public_key_create_from_n_e(BIGNUM *n, BIGNUM *e) -{ - private_openssl_rsa_public_key_t *this = openssl_rsa_public_key_create_empty(); - - this->rsa = RSA_new(); - this->rsa->n = BN_dup(n); - this->rsa->e = BN_dup(e); - - if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } - return &this->public; -} - -/** * Load a public key from an ASN1 encoded blob */ static openssl_rsa_public_key_t *load(chunk_t blob) { u_char *p = blob.ptr; - private_openssl_rsa_public_key_t *this = openssl_rsa_public_key_create_empty(); - - this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&p, blob.len); + private_openssl_rsa_public_key_t *this = create_empty(); - chunk_clear(&blob); - + this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&p, blob.len); if (!this->rsa) { destroy(this); return NULL; } - - if (!openssl_rsa_public_key_build_id(this->rsa, &this->keyid, &this->keyid_info)) - { - destroy(this); - return NULL; - } + return &this->public; } typedef struct private_builder_t private_builder_t; + /** * Builder implementation for key loading */ @@ -433,15 +308,13 @@ static void add(private_builder_t *this, builder_part_t part, ...) if (!this->key) { va_list args; - chunk_t chunk; - + switch (part) { case BUILD_BLOB_ASN1_DER: { va_start(args, part); - chunk = va_arg(args, chunk_t); - this->key = load(chunk_clone(chunk)); + this->key = load(va_arg(args, chunk_t)); va_end(args); return; } diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index c8c453f64..67b732736 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -18,6 +19,7 @@ #include <debug.h> #include <openssl/evp.h> +#include <openssl/x509.h> /** * Described in header. @@ -121,3 +123,102 @@ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b) return TRUE; } + +/** + * Build fingerprints of a private/public RSA key. + */ +static bool build_fingerprint(chunk_t key, key_encoding_type_t type, int nid, + chunk_t *fingerprint) +{ + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + DBG1("SHA1 hash algorithm not supported, fingerprinting failed"); + return FALSE; + } + if (type == KEY_ID_PUBKEY_INFO_SHA1) + { + X509_PUBKEY *pubkey; + chunk_t enc; + u_char *p; + + /* wrap publicKey in subjectPublicKeyInfo */ + pubkey = X509_PUBKEY_new(); + ASN1_OBJECT_free(pubkey->algor->algorithm); + pubkey->algor->algorithm = OBJ_nid2obj(nid); + + if (pubkey->algor->parameter == NULL || + pubkey->algor->parameter->type != V_ASN1_NULL) + { + ASN1_TYPE_free(pubkey->algor->parameter); + pubkey->algor->parameter = ASN1_TYPE_new(); + pubkey->algor->parameter->type = V_ASN1_NULL; + } + M_ASN1_BIT_STRING_set(pubkey->public_key, enc.ptr, enc.len); + + enc = chunk_alloc(i2d_X509_PUBKEY(pubkey, NULL)); + p = enc.ptr; + i2d_X509_PUBKEY(pubkey, &p); + X509_PUBKEY_free(pubkey); + + hasher->allocate_hash(hasher, enc, fingerprint); + chunk_free(&enc); + } + else + { + hasher->allocate_hash(hasher, key, fingerprint); + } + hasher->destroy(hasher); + return TRUE; +} + +/** + * See header. + */ +bool openssl_encode(key_encoding_type_t type, chunk_t *encoding, va_list args) +{ + chunk_t key; + + switch (type) + { + case KEY_PUB_ASN1_DER: + if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key, + KEY_PART_END) || + key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key, + KEY_PART_END)) + { + *encoding = chunk_clone(key); + return TRUE; + } + return FALSE; + case KEY_PRIV_ASN1_DER: + if (key_encoding_args(args, KEY_PART_RSA_PRIV_ASN1_DER, &key, + KEY_PART_END) || + key_encoding_args(args, KEY_PART_ECDSA_PRIV_ASN1_DER, &key, + KEY_PART_END)) + { + *encoding = chunk_clone(key); + return TRUE; + } + return FALSE; + case KEY_ID_PUBKEY_SHA1: + case KEY_ID_PUBKEY_INFO_SHA1: + if (key_encoding_args(args, KEY_PART_RSA_PUB_ASN1_DER, &key, + KEY_PART_END)) + { + return build_fingerprint(key, type, NID_rsaEncryption, encoding); + } + else if (key_encoding_args(args, KEY_PART_ECDSA_PUB_ASN1_DER, &key, + KEY_PART_END)) + { + return build_fingerprint(key, type, NID_X9_62_id_ecPublicKey, + encoding); + } + return FALSE; + default: + return FALSE; + } +} + diff --git a/src/libstrongswan/plugins/openssl/openssl_util.h b/src/libstrongswan/plugins/openssl/openssl_util.h index 6ba1ff07b..921c52612 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.h +++ b/src/libstrongswan/plugins/openssl/openssl_util.h @@ -65,4 +65,14 @@ bool openssl_bn_cat(int len, BIGNUM *a, BIGNUM *b, chunk_t *chunk); */ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b); + +/** + * Fingerprinting/encdoing of PKCS#1/ASN.1 encoded keys. + * + * @param type type of the fingerprint/encoding to create. + * @param encoding receives fingerprint/encoding, allocated + * @param args variable argument list of encoding parts + */ +bool openssl_encode(key_encoding_type_t type, chunk_t *encoding, va_list args); + #endif /** OPENSSL_UTIL_H_ @}*/ |