2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
5 * Copyright (C) secunet Security Networks AG
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include <openssl/opensslconf.h>
20 #ifndef OPENSSL_NO_ECDSA
22 #include "openssl_ec_public_key.h"
23 #include "openssl_util.h"
25 #include <utils/debug.h>
27 #include <openssl/evp.h>
28 #include <openssl/ecdsa.h>
29 #include <openssl/x509.h>
31 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
32 #include <openssl/core_names.h>
35 #if OPENSSL_VERSION_NUMBER < 0x10100000L
36 OPENSSL_KEY_FALLBACK(ECDSA_SIG
, r
, s
)
39 typedef struct private_openssl_ec_public_key_t private_openssl_ec_public_key_t
;
42 * Private data structure with signing context.
44 struct private_openssl_ec_public_key_t
{
46 * Public interface for this signer.
48 openssl_ec_public_key_t
public;
62 * Verification of a DER encoded signature as in RFC 3279
64 static bool verify_der_signature(private_openssl_ec_public_key_t
*this,
65 int nid_hash
, chunk_t data
, chunk_t signature
)
70 /* remove any preceding 0-bytes from signature */
71 while (signature
.len
&& signature
.ptr
[0] == 0x00)
73 signature
= chunk_skip(signature
, 1);
75 md
= EVP_get_digestbynid(nid_hash
);
80 ctx
= EVP_MD_CTX_create();
82 EVP_DigestVerifyInit(ctx
, NULL
, md
, NULL
, this->key
) <= 0 ||
83 EVP_DigestVerifyUpdate(ctx
, data
.ptr
, data
.len
) <= 0 ||
84 EVP_DigestVerifyFinal(ctx
, signature
.ptr
, signature
.len
) != 1)
86 EVP_MD_CTX_destroy(ctx
);
89 EVP_MD_CTX_destroy(ctx
);
94 * Verification of a signature as in RFC 4754
96 static bool verify_signature(private_openssl_ec_public_key_t
*this,
97 int nid_hash
, chunk_t data
, chunk_t signature
)
105 sig
= ECDSA_SIG_new();
110 if (!openssl_bn_split(signature
, r
, s
))
117 if (ECDSA_SIG_set0(sig
, r
, s
))
119 der_sig
= openssl_i2chunk(ECDSA_SIG
, sig
);
121 { /* EVP_DigestVerify*() has issues with NULL EVP_MD */
122 ctx
= EVP_PKEY_CTX_new(this->key
, NULL
);
123 valid
= ctx
&& EVP_PKEY_verify_init(ctx
) > 0 &&
124 EVP_PKEY_verify(ctx
, der_sig
.ptr
, der_sig
.len
,
125 data
.ptr
, data
.len
) > 0;
126 EVP_PKEY_CTX_free(ctx
);
130 valid
= verify_der_signature(this, nid_hash
, data
, der_sig
);
132 chunk_free(&der_sig
);
140 * Check that the given key's curve matches a specific one. Also used by
143 bool openssl_check_ec_key_curve(EVP_PKEY
*key
, int nid_curve
)
145 EC_GROUP
*req_group
, *my_group
= NULL
;
146 bool matches
= FALSE
;
148 req_group
= EC_GROUP_new_by_curve_name(nid_curve
);
154 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
156 OSSL_PARAM params
[] = {
157 OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME
, name
, sizeof(name
)),
161 if (!EVP_PKEY_get_group_name(key
, name
, sizeof(name
), NULL
))
165 my_group
= EC_GROUP_new_from_params(params
, NULL
, NULL
);
166 #elif OPENSSL_VERSION_NUMBER >= 0x1010000fL
167 EC_KEY
*ec
= EVP_PKEY_get0_EC_KEY(key
);
168 my_group
= EC_GROUP_dup(EC_KEY_get0_group(ec
));
170 EC_KEY
*ec
= EVP_PKEY_get1_EC_KEY(key
);
171 my_group
= EC_GROUP_dup(EC_KEY_get0_group(ec
));
175 if (EC_GROUP_cmp(my_group
, req_group
, NULL
) == 0)
181 EC_GROUP_free(my_group
);
182 EC_GROUP_free(req_group
);
187 * Verify a RFC 4754 signature for a specified curve and hash algorithm
189 static bool verify_curve_signature(private_openssl_ec_public_key_t
*this,
190 signature_scheme_t scheme
, int nid_hash
,
191 int nid_curve
, chunk_t data
, chunk_t signature
)
193 if (!openssl_check_ec_key_curve(this->key
, nid_curve
))
195 DBG1(DBG_LIB
, "signature scheme %N not supported by key",
196 signature_scheme_names
, scheme
);
199 return verify_signature(this, nid_hash
, data
, signature
);
202 METHOD(public_key_t
, get_type
, key_type_t
,
203 private_openssl_ec_public_key_t
*this)
208 METHOD(public_key_t
, verify
, bool,
209 private_openssl_ec_public_key_t
*this, signature_scheme_t scheme
,
210 void *params
, chunk_t data
, chunk_t signature
)
214 case SIGN_ECDSA_WITH_SHA1_DER
:
215 return verify_der_signature(this, NID_sha1
, data
, signature
);
216 case SIGN_ECDSA_WITH_SHA256_DER
:
217 return verify_der_signature(this, NID_sha256
, data
, signature
);
218 case SIGN_ECDSA_WITH_SHA384_DER
:
219 return verify_der_signature(this, NID_sha384
, data
, signature
);
220 case SIGN_ECDSA_WITH_SHA512_DER
:
221 return verify_der_signature(this, NID_sha512
, data
, signature
);
222 case SIGN_ECDSA_WITH_NULL
:
223 return verify_signature(this, 0, data
, signature
);
225 return verify_curve_signature(this, scheme
, NID_sha256
,
226 NID_X9_62_prime256v1
, data
, signature
);
228 return verify_curve_signature(this, scheme
, NID_sha384
,
229 NID_secp384r1
, data
, signature
);
231 return verify_curve_signature(this, scheme
, NID_sha512
,
232 NID_secp521r1
, data
, signature
);
234 DBG1(DBG_LIB
, "signature scheme %N not supported in EC",
235 signature_scheme_names
, scheme
);
240 METHOD(public_key_t
, encrypt
, bool,
241 private_openssl_ec_public_key_t
*this, encryption_scheme_t scheme
,
242 void *params
, chunk_t crypto
, chunk_t
*plain
)
244 DBG1(DBG_LIB
, "EC public key encryption not implemented");
248 METHOD(public_key_t
, get_keysize
, int,
249 private_openssl_ec_public_key_t
*this)
251 return EVP_PKEY_bits(this->key
);
254 METHOD(public_key_t
, get_fingerprint
, bool,
255 private_openssl_ec_public_key_t
*this, cred_encoding_type_t type
,
256 chunk_t
*fingerprint
)
258 return openssl_fingerprint(this->key
, type
, fingerprint
);
261 METHOD(public_key_t
, get_encoding
, bool,
262 private_openssl_ec_public_key_t
*this, cred_encoding_type_t type
,
267 *encoding
= openssl_i2chunk(PUBKEY
, this->key
);
269 if (type
!= PUBKEY_SPKI_ASN1_DER
)
271 chunk_t asn1_encoding
= *encoding
;
273 success
= lib
->encoding
->encode(lib
->encoding
, type
,
274 NULL
, encoding
, CRED_PART_ECDSA_PUB_ASN1_DER
,
275 asn1_encoding
, CRED_PART_END
);
276 chunk_clear(&asn1_encoding
);
281 METHOD(public_key_t
, get_ref
, public_key_t
*,
282 private_openssl_ec_public_key_t
*this)
285 return &this->public.key
;
288 METHOD(public_key_t
, destroy
, void,
289 private_openssl_ec_public_key_t
*this)
291 if (ref_put(&this->ref
))
295 lib
->encoding
->clear_cache(lib
->encoding
, this->key
);
296 EVP_PKEY_free(this->key
);
303 * Check whether the EC key was decoded with explicit curve parameters instead
306 bool openssl_check_explicit_params(const EVP_PKEY
*key
)
310 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
311 if (!EVP_PKEY_get_int_param(key
, OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS
,
316 #elif OPENSSL_VERSION_NUMBER >= 0x1010108fL
317 explicit = EC_KEY_decoded_from_explicit_params(EVP_PKEY_get0_EC_KEY((EVP_PKEY
*)key
));
319 return explicit == 1;
325 openssl_ec_public_key_t
*openssl_ec_public_key_load(key_type_t type
,
328 private_openssl_ec_public_key_t
*this;
329 chunk_t blob
= chunk_empty
;
334 switch (va_arg(args
, builder_part_t
))
336 case BUILD_BLOB_ASN1_DER
:
337 blob
= va_arg(args
, chunk_t
);
346 key
= d2i_PUBKEY(NULL
, (const u_char
**)&blob
.ptr
, blob
.len
);
347 if (!key
|| EVP_PKEY_base_id(key
) != EVP_PKEY_EC
||
348 openssl_check_explicit_params(key
))
357 .get_type
= _get_type
,
360 .get_keysize
= _get_keysize
,
361 .equals
= public_key_equals
,
362 .get_fingerprint
= _get_fingerprint
,
363 .has_fingerprint
= public_key_has_fingerprint
,
364 .get_encoding
= _get_encoding
,
372 return &this->public;
375 #endif /* OPENSSL_NO_ECDSA */