From: Tobias Brunner Date: Thu, 3 Mar 2022 13:19:03 +0000 (+0100) Subject: openssl: Fixes for ECDSA with OpenSSL 3.0 X-Git-Tag: 5.9.6rc1~1^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=293a912c7de67bbd2720c77c0a9320aade54b2b0;p=thirdparty%2Fstrongswan.git openssl: Fixes for ECDSA with OpenSSL 3.0 --- diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c index 0c208be7e4..54c20dcb9a 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c @@ -46,7 +46,7 @@ struct private_openssl_ec_private_key_t { /** * EC key object */ - EC_KEY *ec; + EVP_PKEY *key; /** * TRUE if the key is from an OpenSSL ENGINE and might not be readable @@ -59,25 +59,78 @@ struct private_openssl_ec_private_key_t { refcount_t ref; }; -/* from ec public key */ -bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp); +/* from openssl_ec_public_key */ +bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve); + +/** + * Build a DER encoded signature as in RFC 3279 + */ +static bool build_der_signature(private_openssl_ec_private_key_t *this, + int nid_hash, chunk_t data, chunk_t *signature) +{ + EVP_MD_CTX *ctx; + const EVP_MD *md; + + md = EVP_get_digestbynid(nid_hash); + if (!md) + { + return FALSE; + } + *signature = chunk_alloc(EVP_PKEY_size(this->key)); + ctx = EVP_MD_CTX_create(); + if (!ctx || + EVP_DigestSignInit(ctx, NULL, md, NULL, this->key) <= 0 || + EVP_DigestSignUpdate(ctx, data.ptr, data.len) <= 0 || + EVP_DigestSignFinal(ctx, signature->ptr, &signature->len) != 1) + { + chunk_free(signature); + EVP_MD_CTX_destroy(ctx); + return FALSE; + } + EVP_MD_CTX_destroy(ctx); + return TRUE; +} /** * Build a signature as in RFC 4754 */ static bool build_signature(private_openssl_ec_private_key_t *this, - chunk_t hash, chunk_t *signature) + int nid_hash, chunk_t data, chunk_t *signature) { - const BIGNUM *r, *s; + EVP_PKEY_CTX *ctx; ECDSA_SIG *sig; + const BIGNUM *r, *s; + const u_char *p; + chunk_t der_sig; bool built = FALSE; - sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec); + if (!nid_hash) + { /* EVP_DigestSign*() has issues with NULL EVP_MD */ + der_sig = chunk_alloc(EVP_PKEY_size(this->key)); + ctx = EVP_PKEY_CTX_new(this->key, NULL); + if (!ctx || + EVP_PKEY_sign_init(ctx) <= 0 || + EVP_PKEY_sign(ctx, der_sig.ptr, &der_sig.len, data.ptr, data.len) <= 0) + { + chunk_free(&der_sig); + EVP_PKEY_CTX_free(ctx); + return FALSE; + } + EVP_PKEY_CTX_free(ctx); + } + else if (!build_der_signature(this, nid_hash, data, &der_sig)) + { + return FALSE; + } + /* extract r and s from the DER-encoded signature */ + p = der_sig.ptr; + sig = d2i_ECDSA_SIG(NULL, &p, der_sig.len); + chunk_free(&der_sig); if (sig) { ECDSA_SIG_get0(sig, &r, &s); /* concatenate BNs r/s to a signature chunk */ - built = openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec)), + built = openssl_bn_cat((EVP_PKEY_bits(this->key) + 7) / 8, r, s, signature); ECDSA_SIG_free(sig); } @@ -91,62 +144,13 @@ static bool build_curve_signature(private_openssl_ec_private_key_t *this, signature_scheme_t scheme, int nid_hash, int nid_curve, chunk_t data, chunk_t *signature) { - const EC_GROUP *my_group; - EC_GROUP *req_group; - chunk_t hash; - bool built; - - req_group = EC_GROUP_new_by_curve_name(nid_curve); - if (!req_group) - { - DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve " - "not supported)", signature_scheme_names, scheme); - return FALSE; - } - my_group = EC_KEY_get0_group(this->ec); - if (EC_GROUP_cmp(my_group, req_group, NULL) != 0) + if (!openssl_check_ec_key_curve(this->key, nid_curve)) { - DBG1(DBG_LIB, "signature scheme %N not supported by private key", + DBG1(DBG_LIB, "signature scheme %N not supported by key", signature_scheme_names, scheme); return FALSE; } - EC_GROUP_free(req_group); - if (!openssl_hash_chunk(nid_hash, data, &hash)) - { - return FALSE; - } - built = build_signature(this, hash, signature); - chunk_free(&hash); - return built; -} - -/** - * Build a DER encoded signature as in RFC 3279 - */ -static bool build_der_signature(private_openssl_ec_private_key_t *this, - int hash_nid, chunk_t data, chunk_t *signature) -{ - chunk_t hash, sig; - int siglen = 0; - bool built; - - if (!openssl_hash_chunk(hash_nid, data, &hash)) - { - return FALSE; - } - sig = chunk_alloc(ECDSA_size(this->ec)); - built = ECDSA_sign(0, hash.ptr, hash.len, sig.ptr, &siglen, this->ec) == 1; - sig.len = siglen; - if (built) - { - *signature = sig; - } - else - { - free(sig.ptr); - } - free(hash.ptr); - return built; + return build_signature(this, nid_hash, data, signature); } METHOD(private_key_t, sign, bool, @@ -156,7 +160,7 @@ METHOD(private_key_t, sign, bool, switch (scheme) { case SIGN_ECDSA_WITH_NULL: - return build_signature(this, data, signature); + return build_signature(this, 0, data, signature); case SIGN_ECDSA_WITH_SHA1_DER: return build_der_signature(this, NID_sha1, data, signature); case SIGN_ECDSA_WITH_SHA256_DER: @@ -192,7 +196,7 @@ METHOD(private_key_t, decrypt, bool, METHOD(private_key_t, get_keysize, int, private_openssl_ec_private_key_t *this) { - return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec)); + return EVP_PKEY_bits(this->key); } METHOD(private_key_t, get_type, key_type_t, @@ -206,12 +210,8 @@ METHOD(private_key_t, get_public_key, public_key_t*, { 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); + key = openssl_i2chunk(PUBKEY, this->key); public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER, key, BUILD_END); free(key.ptr); @@ -222,20 +222,17 @@ METHOD(private_key_t, get_fingerprint, bool, private_openssl_ec_private_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) { - return openssl_ec_fingerprint(this->ec, type, fingerprint); + return openssl_fingerprint(this->key, type, fingerprint); } METHOD(private_key_t, get_encoding, bool, private_openssl_ec_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding) { - u_char *p; - if (this->engine) { return FALSE; } - switch (type) { case PRIVKEY_ASN1_DER: @@ -243,9 +240,7 @@ METHOD(private_key_t, get_encoding, bool, { bool success = TRUE; - *encoding = chunk_alloc(i2d_ECPrivateKey(this->ec, NULL)); - p = encoding->ptr; - i2d_ECPrivateKey(this->ec, &p); + *encoding = openssl_i2chunk(PrivateKey, this->key); if (type == PRIVKEY_PEM) { @@ -275,10 +270,10 @@ METHOD(private_key_t, destroy, void, { if (ref_put(&this->ref)) { - if (this->ec) + if (this->key) { - lib->encoding->clear_cache(lib->encoding, this->ec); - EC_KEY_free(this->ec); + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); } free(this); } @@ -287,7 +282,7 @@ METHOD(private_key_t, destroy, void, /** * Internal generic constructor */ -static private_openssl_ec_private_key_t *create_empty(void) +static private_openssl_ec_private_key_t *create_internal(EVP_PKEY *key) { private_openssl_ec_private_key_t *this; @@ -309,6 +304,7 @@ static private_openssl_ec_private_key_t *create_empty(void) }, }, .ref = 1, + .key = key, ); return this; @@ -320,16 +316,13 @@ static private_openssl_ec_private_key_t *create_empty(void) private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine) { private_openssl_ec_private_key_t *this; - EC_KEY *ec; - ec = EVP_PKEY_get1_EC_KEY(key); - EVP_PKEY_free(key); - if (!ec) + if (EVP_PKEY_base_id(key) != EVP_PKEY_EC) { + EVP_PKEY_free(key); return NULL; } - this = create_empty(); - this->ec = ec; + this = create_internal(key); this->engine = engine; return &this->public.key; } @@ -341,6 +334,7 @@ openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type, va_list args) { private_openssl_ec_private_key_t *this; + EVP_PKEY *key = NULL; u_int key_size = 0; while (TRUE) @@ -361,32 +355,58 @@ openssl_ec_private_key_t *openssl_ec_private_key_gen(key_type_t type, { return NULL; } - this = create_empty(); + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L switch (key_size) { case 256: - this->ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + key = EVP_EC_gen("P-256"); break; case 384: - this->ec = EC_KEY_new_by_curve_name(NID_secp384r1); + key = EVP_EC_gen("P-384"); break; case 521: - this->ec = EC_KEY_new_by_curve_name(NID_secp521r1); + key = EVP_EC_gen("P-521"); break; default: DBG1(DBG_LIB, "EC private key size %d not supported", key_size); - destroy(this); return NULL; } - if (EC_KEY_generate_key(this->ec) != 1) +#else /* OPENSSL_VERSION_NUMBER */ + EC_KEY *ec; + + switch (key_size) + { + case 256: + ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + break; + case 384: + ec = EC_KEY_new_by_curve_name(NID_secp384r1); + break; + case 521: + ec = EC_KEY_new_by_curve_name(NID_secp521r1); + break; + default: + DBG1(DBG_LIB, "EC private key size %d not supported", key_size); + return NULL; + } + if (ec && EC_KEY_generate_key(ec) == 1) + { + key = EVP_PKEY_new(); + if (!EVP_PKEY_assign_EC_KEY(key, ec)) + { + EC_KEY_free(ec); + EVP_PKEY_free(key); + key = NULL; + } + } +#endif /* OPENSSL_VERSION_NUMBER */ + + if (!key) { - DBG1(DBG_LIB, "EC private key generation failed", key_size); - destroy(this); return NULL; } - /* encode as a named curve key (no parameters), uncompressed public key */ - EC_KEY_set_asn1_flag(this->ec, OPENSSL_EC_NAMED_CURVE); - EC_KEY_set_conv_form(this->ec, POINT_CONVERSION_UNCOMPRESSED); + this = create_internal(key); return &this->public; } @@ -397,7 +417,8 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, va_list args) { private_openssl_ec_private_key_t *this; - chunk_t par = chunk_empty, key = chunk_empty; + chunk_t par = chunk_empty, blob = chunk_empty; + EVP_PKEY *key = NULL; while (TRUE) { @@ -407,7 +428,7 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, par = va_arg(args, chunk_t); continue; case BUILD_BLOB_ASN1_DER: - key = va_arg(args, chunk_t); + blob = va_arg(args, chunk_t); continue; case BUILD_END: break; @@ -417,36 +438,46 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, break; } - this = create_empty(); - if (par.ptr) { - this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len); - if (!this->ec) + /* for OpenSSL 3, the combination of d2i_KeyParams/d2i_PrivateKey, which + * are intended to replace the functions below, does currently not work + * because OpenSSL does not pass the internal EC_KEY that stores the + * parameters from the first call to the call that parses the private + * key. however, since parsing PKCS#8 is the only use case for this and + * OpenSSL 3 parses this format directly, there isn't really any need + * for it anyway */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L + EC_KEY *ec; + + ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len); + if (ec && d2i_ECPrivateKey(&ec, (const u_char**)&blob.ptr, blob.len)) { - goto error; + key = EVP_PKEY_new(); + if (!EVP_PKEY_assign_EC_KEY(key, ec)) + { + EC_KEY_free(ec); + EVP_PKEY_free(key); + key = NULL; + } } - if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len)) + else { - goto error; + EC_KEY_free(ec); } +#endif } else { - this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len); - if (!this->ec) - { - goto error; - } + key = d2i_PrivateKey(EVP_PKEY_EC, NULL, (const u_char**)&blob.ptr, + blob.len); } - if (!EC_KEY_check_key(this->ec)) + + if (!key) { - goto error; + return NULL; } + this = create_internal(key); return &this->public; - -error: - destroy(this); - return NULL; } #endif /* OPENSSL_NO_ECDSA */ diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c index 79ab82db54..7b529719b0 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c @@ -27,6 +27,10 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif + #if OPENSSL_VERSION_NUMBER < 0x10100000L OPENSSL_KEY_FALLBACK(ECDSA_SIG, r, s) #endif @@ -45,7 +49,7 @@ struct private_openssl_ec_public_key_t { /** * EC key object */ - EC_KEY *ec; + EVP_PKEY *key; /** * reference counter @@ -53,14 +57,48 @@ struct private_openssl_ec_public_key_t { refcount_t ref; }; +/** + * Verification of a DER encoded signature as in RFC 3279 + */ +static bool verify_der_signature(private_openssl_ec_public_key_t *this, + int nid_hash, chunk_t data, chunk_t signature) +{ + EVP_MD_CTX *ctx; + const EVP_MD *md; + + /* remove any preceding 0-bytes from signature */ + while (signature.len && signature.ptr[0] == 0x00) + { + signature = chunk_skip(signature, 1); + } + md = EVP_get_digestbynid(nid_hash); + if (!md) + { + return FALSE; + } + ctx = EVP_MD_CTX_create(); + if (!ctx || + EVP_DigestVerifyInit(ctx, NULL, md, NULL, this->key) <= 0 || + EVP_DigestVerifyUpdate(ctx, data.ptr, data.len) <= 0 || + EVP_DigestVerifyFinal(ctx, signature.ptr, signature.len) != 1) + { + EVP_MD_CTX_destroy(ctx); + return FALSE; + } + EVP_MD_CTX_destroy(ctx); + return TRUE; +} + /** * Verification of a signature as in RFC 4754 */ static bool verify_signature(private_openssl_ec_public_key_t *this, - chunk_t hash, chunk_t signature) + int nid_hash, chunk_t data, chunk_t signature) { + EVP_PKEY_CTX *ctx; BIGNUM *r, *s; ECDSA_SIG *sig; + chunk_t der_sig; bool valid = FALSE; sig = ECDSA_SIG_new(); @@ -77,7 +115,20 @@ static bool verify_signature(private_openssl_ec_public_key_t *this, } if (ECDSA_SIG_set0(sig, r, s)) { - valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1); + der_sig = openssl_i2chunk(ECDSA_SIG, sig); + if (!nid_hash) + { /* EVP_DigestVerify*() has issues with NULL EVP_MD */ + ctx = EVP_PKEY_CTX_new(this->key, NULL); + valid = ctx && EVP_PKEY_verify_init(ctx) > 0 && + EVP_PKEY_verify(ctx, der_sig.ptr, der_sig.len, + data.ptr, data.len) > 0; + EVP_PKEY_CTX_free(ctx); + } + else + { + valid = verify_der_signature(this, nid_hash, data, der_sig); + } + chunk_free(&der_sig); } ECDSA_SIG_free(sig); } @@ -85,62 +136,66 @@ static bool verify_signature(private_openssl_ec_public_key_t *this, } /** - * Verify a RFC 4754 signature for a specified curve and hash algorithm + * Check that the given key's curve matches a specific one. Also used by + * private key. */ -static bool verify_curve_signature(private_openssl_ec_public_key_t *this, - signature_scheme_t scheme, int nid_hash, - int nid_curve, chunk_t data, chunk_t signature) +bool openssl_check_ec_key_curve(EVP_PKEY *key, int nid_curve) { - const EC_GROUP *my_group; - EC_GROUP *req_group; - chunk_t hash; - bool valid; + EC_GROUP *req_group, *my_group = NULL; + bool matches = FALSE; req_group = EC_GROUP_new_by_curve_name(nid_curve); if (!req_group) { - DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve " - "not supported)", signature_scheme_names, scheme); - return FALSE; + goto error; } - my_group = EC_KEY_get0_group(this->ec); - if (EC_GROUP_cmp(my_group, req_group, NULL) != 0) + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char name[BUF_LEN]; + OSSL_PARAM params[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, name, sizeof(name)), + OSSL_PARAM_END, + }; + + if (!EVP_PKEY_get_group_name(key, name, sizeof(name), NULL)) { - DBG1(DBG_LIB, "signature scheme %N not supported by private key", - signature_scheme_names, scheme); - return FALSE; + goto error; } - EC_GROUP_free(req_group); - if (!openssl_hash_chunk(nid_hash, data, &hash)) + my_group = EC_GROUP_new_from_params(params, NULL, NULL); +#elif OPENSSL_VERSION_NUMBER >= 0x1010000fL + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(key); + my_group = EC_GROUP_dup(EC_KEY_get0_group(ec)); +#else + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); + my_group = EC_GROUP_dup(EC_KEY_get0_group(ec)); + EC_KEY_free(ec); +#endif + + if (EC_GROUP_cmp(my_group, req_group, NULL) == 0) { - return FALSE; + matches = TRUE; } - valid = verify_signature(this, hash, signature); - chunk_free(&hash); - return valid; + +error: + EC_GROUP_free(my_group); + EC_GROUP_free(req_group); + return matches; } /** - * Verification of a DER encoded signature as in RFC 3279 + * Verify a RFC 4754 signature for a specified curve and hash algorithm */ -static bool verify_der_signature(private_openssl_ec_public_key_t *this, - int nid_hash, chunk_t data, chunk_t signature) +static bool verify_curve_signature(private_openssl_ec_public_key_t *this, + signature_scheme_t scheme, int nid_hash, + int nid_curve, chunk_t data, chunk_t signature) { - chunk_t hash; - bool valid = FALSE; - - /* remove any preceding 0-bytes from signature */ - while (signature.len && signature.ptr[0] == 0x00) + if (!openssl_check_ec_key_curve(this->key, nid_curve)) { - signature = chunk_skip(signature, 1); - } - if (openssl_hash_chunk(nid_hash, data, &hash)) - { - valid = ECDSA_verify(0, hash.ptr, hash.len, - signature.ptr, signature.len, this->ec) == 1; - free(hash.ptr); + DBG1(DBG_LIB, "signature scheme %N not supported by key", + signature_scheme_names, scheme); + return FALSE; } - return valid; + return verify_signature(this, nid_hash, data, signature); } METHOD(public_key_t, get_type, key_type_t, @@ -164,7 +219,7 @@ METHOD(public_key_t, verify, bool, case SIGN_ECDSA_WITH_SHA512_DER: return verify_der_signature(this, NID_sha512, data, signature); case SIGN_ECDSA_WITH_NULL: - return verify_signature(this, data, signature); + return verify_signature(this, 0, data, signature); case SIGN_ECDSA_256: return verify_curve_signature(this, scheme, NID_sha256, NID_X9_62_prime256v1, data, signature); @@ -192,56 +247,14 @@ METHOD(public_key_t, encrypt, bool, METHOD(public_key_t, get_keysize, int, private_openssl_ec_public_key_t *this) { - return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec)); -} - -/** - * Calculate fingerprint from a EC_KEY, also used in ec private key. - */ -bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp) -{ - hasher_t *hasher; - chunk_t key; - u_char *p; - - if (lib->encoding->get_cache(lib->encoding, type, ec, fp)) - { - return TRUE; - } - switch (type) - { - case KEYID_PUBKEY_SHA1: - key = chunk_alloc(i2o_ECPublicKey(ec, NULL)); - p = key.ptr; - i2o_ECPublicKey(ec, &p); - break; - case KEYID_PUBKEY_INFO_SHA1: - key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL)); - p = key.ptr; - i2d_EC_PUBKEY(ec, &p); - break; - default: - return FALSE; - } - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher || !hasher->allocate_hash(hasher, key, fp)) - { - DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); - DESTROY_IF(hasher); - free(key.ptr); - return FALSE; - } - hasher->destroy(hasher); - free(key.ptr); - lib->encoding->cache(lib->encoding, type, ec, *fp); - return TRUE; + return EVP_PKEY_bits(this->key); } METHOD(public_key_t, get_fingerprint, bool, private_openssl_ec_public_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) { - return openssl_ec_fingerprint(this->ec, type, fingerprint); + return openssl_fingerprint(this->key, type, fingerprint); } METHOD(public_key_t, get_encoding, bool, @@ -249,11 +262,8 @@ METHOD(public_key_t, get_encoding, bool, chunk_t *encoding) { bool success = TRUE; - u_char *p; - *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); - p = encoding->ptr; - i2d_EC_PUBKEY(this->ec, &p); + *encoding = openssl_i2chunk(PUBKEY, this->key); if (type != PUBKEY_SPKI_ASN1_DER) { @@ -279,43 +289,15 @@ METHOD(public_key_t, destroy, void, { if (ref_put(&this->ref)) { - if (this->ec) + if (this->key) { - lib->encoding->clear_cache(lib->encoding, this->ec); - EC_KEY_free(this->ec); + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); } free(this); } } -/** - * Generic private constructor - */ -static private_openssl_ec_public_key_t *create_empty() -{ - private_openssl_ec_public_key_t *this; - - INIT(this, - .public = { - .key = { - .get_type = _get_type, - .verify = _verify, - .encrypt = _encrypt, - .get_keysize = _get_keysize, - .equals = public_key_equals, - .get_fingerprint = _get_fingerprint, - .has_fingerprint = public_key_has_fingerprint, - .get_encoding = _get_encoding, - .get_ref = _get_ref, - .destroy = _destroy, - }, - }, - .ref = 1, - ); - - return this; -} - /** * See header. */ @@ -324,11 +306,7 @@ openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type, { private_openssl_ec_public_key_t *this; chunk_t blob = chunk_empty; - - if (type != KEY_ECDSA) - { - return NULL; - } + EVP_PKEY *key; while (TRUE) { @@ -344,14 +322,32 @@ openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type, } break; } - this = create_empty(); - this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); - if (!this->ec) + key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); + if (!key || EVP_PKEY_base_id(key) != EVP_PKEY_EC) { - destroy(this); + EVP_PKEY_free(key); return NULL; } + + INIT(this, + .public = { + .key = { + .get_type = _get_type, + .verify = _verify, + .encrypt = _encrypt, + .get_keysize = _get_keysize, + .equals = public_key_equals, + .get_fingerprint = _get_fingerprint, + .has_fingerprint = public_key_has_fingerprint, + .get_encoding = _get_encoding, + .get_ref = _get_ref, + .destroy = _destroy, + }, + }, + .ref = 1, + .key = key, + ); return &this->public; } -#endif /* OPENSSL_NO_ECDSA */ +#endif /* OPENSSL_NO_ECDSA */ diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 43ebe03623..c5a1eb7250 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -402,53 +402,21 @@ error: */ bool openssl_rsa_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp) { - hasher_t *hasher; - chunk_t enc; - u_char *p; - - if (lib->encoding->get_cache(lib->encoding, type, key, fp)) + if (!openssl_fingerprint(key, type, fp)) { - return TRUE; - } - switch (type) - { - case KEYID_PUBKEY_SHA1: - enc = chunk_alloc(i2d_PublicKey(key, NULL)); - p = enc.ptr; - i2d_PublicKey(key, &p); - break; - case KEYID_PUBKEY_INFO_SHA1: - enc = chunk_alloc(i2d_PUBKEY(key, NULL)); - p = enc.ptr; - i2d_PUBKEY(key, &p); - break; - default: - { - chunk_t n = chunk_empty, e = chunk_empty; - bool success = FALSE; + chunk_t n = chunk_empty, e = chunk_empty; + bool success = FALSE; - if (get_n_and_e(key, &n, &e)) - { - success = lib->encoding->encode(lib->encoding, type, key, fp, + if (get_n_and_e(key, &n, &e)) + { + success = lib->encoding->encode(lib->encoding, type, key, fp, CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END); - } - chunk_free(&n); - chunk_free(&e); - return success; } + chunk_free(&n); + chunk_free(&e); + return success; } - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher || !hasher->allocate_hash(hasher, enc, fp)) - { - DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); - DESTROY_IF(hasher); - free(enc.ptr); - return FALSE; - } - free(enc.ptr); - hasher->destroy(hasher); - lib->encoding->cache(lib->encoding, type, key, *fp); return TRUE; } diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index f01ac797e6..fce8d29a28 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -86,6 +86,48 @@ error: return success; } +/* + * Described in header + */ +bool openssl_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp) +{ + hasher_t *hasher; + chunk_t enc; + u_char *p; + + if (lib->encoding->get_cache(lib->encoding, type, key, fp)) + { + return TRUE; + } + switch (type) + { + case KEYID_PUBKEY_SHA1: + enc = chunk_alloc(i2d_PublicKey(key, NULL)); + p = enc.ptr; + i2d_PublicKey(key, &p); + break; + case KEYID_PUBKEY_INFO_SHA1: + enc = chunk_alloc(i2d_PUBKEY(key, NULL)); + p = enc.ptr; + i2d_PUBKEY(key, &p); + break; + default: + return FALSE; + } + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, enc, fp)) + { + DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed"); + DESTROY_IF(hasher); + free(enc.ptr); + return FALSE; + } + free(enc.ptr); + hasher->destroy(hasher); + lib->encoding->cache(lib->encoding, type, key, *fp); + return TRUE; +} + /** * Described in header. */ diff --git a/src/libstrongswan/plugins/openssl/openssl_util.h b/src/libstrongswan/plugins/openssl/openssl_util.h index 0b5562c4ed..150eebe201 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.h +++ b/src/libstrongswan/plugins/openssl/openssl_util.h @@ -46,6 +46,16 @@ */ bool openssl_compute_shared_key(EVP_PKEY *priv, EVP_PKEY *pub, chunk_t *shared); +/** + * Calculate a fingerprint from the given key (cached under it). + * + * @param key key object + * @param type encoding type + * @param fp allocated fingerprint + * @return TRUE on success, FALSE otherwise + */ +bool openssl_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp); + /** * Creates a hash of a given type of a chunk of data. *