2 * Copyright (C) 2008-2016 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include <openssl/opensslconf.h>
19 #ifndef OPENSSL_NO_ECDSA
21 #include "openssl_ec_private_key.h"
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 < 0x10100000L
32 OPENSSL_KEY_FALLBACK(ECDSA_SIG
, r
, s
)
35 typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t
;
38 * Private data of a openssl_ec_private_key_t object.
40 struct private_openssl_ec_private_key_t
{
42 * Public interface for this signer.
44 openssl_ec_private_key_t
public;
52 * TRUE if the key is from an OpenSSL ENGINE and might not be readable
62 /* from ec public key */
63 bool openssl_ec_fingerprint(EC_KEY
*ec
, cred_encoding_type_t type
, chunk_t
*fp
);
66 * Build a signature as in RFC 4754
68 static bool build_signature(private_openssl_ec_private_key_t
*this,
69 chunk_t hash
, chunk_t
*signature
)
75 sig
= ECDSA_do_sign(hash
.ptr
, hash
.len
, this->ec
);
78 ECDSA_SIG_get0(sig
, &r
, &s
);
79 /* concatenate BNs r/s to a signature chunk */
80 built
= openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec
)),
88 * Build a RFC 4754 signature for a specified curve and hash algorithm
90 static bool build_curve_signature(private_openssl_ec_private_key_t
*this,
91 signature_scheme_t scheme
, int nid_hash
,
92 int nid_curve
, chunk_t data
, chunk_t
*signature
)
94 const EC_GROUP
*my_group
;
99 req_group
= EC_GROUP_new_by_curve_name(nid_curve
);
102 DBG1(DBG_LIB
, "signature scheme %N not supported in EC (required curve "
103 "not supported)", signature_scheme_names
, scheme
);
106 my_group
= EC_KEY_get0_group(this->ec
);
107 if (EC_GROUP_cmp(my_group
, req_group
, NULL
) != 0)
109 DBG1(DBG_LIB
, "signature scheme %N not supported by private key",
110 signature_scheme_names
, scheme
);
113 EC_GROUP_free(req_group
);
114 if (!openssl_hash_chunk(nid_hash
, data
, &hash
))
118 built
= build_signature(this, hash
, signature
);
124 * Build a DER encoded signature as in RFC 3279
126 static bool build_der_signature(private_openssl_ec_private_key_t
*this,
127 int hash_nid
, chunk_t data
, chunk_t
*signature
)
133 if (!openssl_hash_chunk(hash_nid
, data
, &hash
))
137 sig
= chunk_alloc(ECDSA_size(this->ec
));
138 built
= ECDSA_sign(0, hash
.ptr
, hash
.len
, sig
.ptr
, &siglen
, this->ec
) == 1;
152 METHOD(private_key_t
, sign
, bool,
153 private_openssl_ec_private_key_t
*this, signature_scheme_t scheme
,
154 void *params
, chunk_t data
, chunk_t
*signature
)
158 case SIGN_ECDSA_WITH_NULL
:
159 return build_signature(this, data
, signature
);
160 case SIGN_ECDSA_WITH_SHA1_DER
:
161 return build_der_signature(this, NID_sha1
, data
, signature
);
162 case SIGN_ECDSA_WITH_SHA256_DER
:
163 return build_der_signature(this, NID_sha256
, data
, signature
);
164 case SIGN_ECDSA_WITH_SHA384_DER
:
165 return build_der_signature(this, NID_sha384
, data
, signature
);
166 case SIGN_ECDSA_WITH_SHA512_DER
:
167 return build_der_signature(this, NID_sha512
, data
, signature
);
169 return build_curve_signature(this, scheme
, NID_sha256
,
170 NID_X9_62_prime256v1
, data
, signature
);
172 return build_curve_signature(this, scheme
, NID_sha384
,
173 NID_secp384r1
, data
, signature
);
175 return build_curve_signature(this, scheme
, NID_sha512
,
176 NID_secp521r1
, data
, signature
);
178 DBG1(DBG_LIB
, "signature scheme %N not supported",
179 signature_scheme_names
, scheme
);
184 METHOD(private_key_t
, decrypt
, bool,
185 private_openssl_ec_private_key_t
*this, encryption_scheme_t scheme
,
186 chunk_t crypto
, chunk_t
*plain
)
188 DBG1(DBG_LIB
, "EC private key decryption not implemented");
192 METHOD(private_key_t
, get_keysize
, int,
193 private_openssl_ec_private_key_t
*this)
195 return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec
));
198 METHOD(private_key_t
, get_type
, key_type_t
,
199 private_openssl_ec_private_key_t
*this)
204 METHOD(private_key_t
, get_public_key
, public_key_t
*,
205 private_openssl_ec_private_key_t
*this)
207 public_key_t
*public;
211 key
= chunk_alloc(i2d_EC_PUBKEY(this->ec
, NULL
));
213 i2d_EC_PUBKEY(this->ec
, &p
);
215 public = lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_ECDSA
,
216 BUILD_BLOB_ASN1_DER
, key
, BUILD_END
);
221 METHOD(private_key_t
, get_fingerprint
, bool,
222 private_openssl_ec_private_key_t
*this, cred_encoding_type_t type
,
223 chunk_t
*fingerprint
)
225 return openssl_ec_fingerprint(this->ec
, type
, fingerprint
);
228 METHOD(private_key_t
, get_encoding
, bool,
229 private_openssl_ec_private_key_t
*this, cred_encoding_type_t type
,
241 case PRIVKEY_ASN1_DER
:
246 *encoding
= chunk_alloc(i2d_ECPrivateKey(this->ec
, NULL
));
248 i2d_ECPrivateKey(this->ec
, &p
);
250 if (type
== PRIVKEY_PEM
)
252 chunk_t asn1_encoding
= *encoding
;
254 success
= lib
->encoding
->encode(lib
->encoding
, PRIVKEY_PEM
,
255 NULL
, encoding
, CRED_PART_ECDSA_PRIV_ASN1_DER
,
256 asn1_encoding
, CRED_PART_END
);
257 chunk_clear(&asn1_encoding
);
266 METHOD(private_key_t
, get_ref
, private_key_t
*,
267 private_openssl_ec_private_key_t
*this)
270 return &this->public.key
;
273 METHOD(private_key_t
, destroy
, void,
274 private_openssl_ec_private_key_t
*this)
276 if (ref_put(&this->ref
))
280 lib
->encoding
->clear_cache(lib
->encoding
, this->ec
);
281 EC_KEY_free(this->ec
);
288 * Internal generic constructor
290 static private_openssl_ec_private_key_t
*create_empty(void)
292 private_openssl_ec_private_key_t
*this;
297 .get_type
= _get_type
,
300 .get_keysize
= _get_keysize
,
301 .get_public_key
= _get_public_key
,
302 .equals
= private_key_equals
,
303 .belongs_to
= private_key_belongs_to
,
304 .get_fingerprint
= _get_fingerprint
,
305 .has_fingerprint
= private_key_has_fingerprint
,
306 .get_encoding
= _get_encoding
,
320 private_key_t
*openssl_ec_private_key_create(EVP_PKEY
*key
, bool engine
)
322 private_openssl_ec_private_key_t
*this;
325 ec
= EVP_PKEY_get1_EC_KEY(key
);
331 this = create_empty();
333 this->engine
= engine
;
334 return &this->public.key
;
340 openssl_ec_private_key_t
*openssl_ec_private_key_gen(key_type_t type
,
343 private_openssl_ec_private_key_t
*this;
348 switch (va_arg(args
, builder_part_t
))
351 key_size
= va_arg(args
, u_int
);
364 this = create_empty();
368 this->ec
= EC_KEY_new_by_curve_name(NID_X9_62_prime256v1
);
371 this->ec
= EC_KEY_new_by_curve_name(NID_secp384r1
);
374 this->ec
= EC_KEY_new_by_curve_name(NID_secp521r1
);
377 DBG1(DBG_LIB
, "EC private key size %d not supported", key_size
);
381 if (EC_KEY_generate_key(this->ec
) != 1)
383 DBG1(DBG_LIB
, "EC private key generation failed", key_size
);
387 /* encode as a named curve key (no parameters), uncompressed public key */
388 EC_KEY_set_asn1_flag(this->ec
, OPENSSL_EC_NAMED_CURVE
);
389 EC_KEY_set_conv_form(this->ec
, POINT_CONVERSION_UNCOMPRESSED
);
390 return &this->public;
396 openssl_ec_private_key_t
*openssl_ec_private_key_load(key_type_t type
,
399 private_openssl_ec_private_key_t
*this;
400 chunk_t par
= chunk_empty
, key
= chunk_empty
;
404 switch (va_arg(args
, builder_part_t
))
406 case BUILD_BLOB_ALGID_PARAMS
:
407 par
= va_arg(args
, chunk_t
);
409 case BUILD_BLOB_ASN1_DER
:
410 key
= va_arg(args
, chunk_t
);
420 this = create_empty();
424 this->ec
= d2i_ECParameters(NULL
, (const u_char
**)&par
.ptr
, par
.len
);
429 if (!d2i_ECPrivateKey(&this->ec
, (const u_char
**)&key
.ptr
, key
.len
))
436 this->ec
= d2i_ECPrivateKey(NULL
, (const u_char
**)&key
.ptr
, key
.len
);
442 if (!EC_KEY_check_key(this->ec
))
446 return &this->public;
452 #endif /* OPENSSL_NO_ECDSA */