]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
openssl: Fixes for ECDSA with OpenSSL 3.0
authorTobias Brunner <tobias@strongswan.org>
Thu, 3 Mar 2022 13:19:03 +0000 (14:19 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Apr 2022 17:05:44 +0000 (19:05 +0200)
src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
src/libstrongswan/plugins/openssl/openssl_util.c
src/libstrongswan/plugins/openssl/openssl_util.h

index 0c208be7e4ac085069eabe71a0a882edf297fe2f..54c20dcb9a2940f35ccb9aa8cf0e18539b277631 100644 (file)
@@ -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 */
index 79ab82db548d06f32ecf4c919fc502d2d8c52d45..7b529719b0a2bb5ebc62fb3b0749ffc461caab5d 100644 (file)
 #include <openssl/ecdsa.h>
 #include <openssl/x509.h>
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#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 */
index 43ebe03623eb0b081faa1cb434cf42eeb60a77ef..c5a1eb7250ac8fbe898f2caf73ebec4ab2806004 100644 (file)
@@ -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;
 }
 
index f01ac797e6ade41c79d0ff569b8a6d860428dab0..fce8d29a284fc22a76c52085e0a7d1514157a5dc 100644 (file)
@@ -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.
  */
index 0b5562c4edf5ba4b00a131db3d7141089b261032..150eebe201093d386867f91168aea8ae5126377f 100644 (file)
  */
 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.
  *