2 * Copyright (C) 2008-2012 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * 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>
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 typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t
;
34 * Private data of a openssl_ec_private_key_t object.
36 struct private_openssl_ec_private_key_t
{
38 * Public interface for this signer.
40 openssl_ec_private_key_t
public;
53 /* from ec public key */
54 bool openssl_ec_fingerprint(EC_KEY
*ec
, cred_encoding_type_t type
, chunk_t
*fp
);
57 * Build a signature as in RFC 4754
59 static bool build_signature(private_openssl_ec_private_key_t
*this,
60 chunk_t hash
, chunk_t
*signature
)
65 sig
= ECDSA_do_sign(hash
.ptr
, hash
.len
, this->ec
);
68 /* concatenate BNs r/s to a signature chunk */
69 built
= openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec
)),
70 sig
->r
, sig
->s
, signature
);
77 * Build a RFC 4754 signature for a specified curve and hash algorithm
79 static bool build_curve_signature(private_openssl_ec_private_key_t
*this,
80 signature_scheme_t scheme
, int nid_hash
,
81 int nid_curve
, chunk_t data
, chunk_t
*signature
)
83 const EC_GROUP
*my_group
;
88 req_group
= EC_GROUP_new_by_curve_name(nid_curve
);
91 DBG1(DBG_LIB
, "signature scheme %N not supported in EC (required curve "
92 "not supported)", signature_scheme_names
, scheme
);
95 my_group
= EC_KEY_get0_group(this->ec
);
96 if (EC_GROUP_cmp(my_group
, req_group
, NULL
) != 0)
98 DBG1(DBG_LIB
, "signature scheme %N not supported by private key",
99 signature_scheme_names
, scheme
);
102 EC_GROUP_free(req_group
);
103 if (!openssl_hash_chunk(nid_hash
, data
, &hash
))
107 built
= build_signature(this, hash
, signature
);
113 * Build a DER encoded signature as in RFC 3279
115 static bool build_der_signature(private_openssl_ec_private_key_t
*this,
116 int hash_nid
, chunk_t data
, chunk_t
*signature
)
122 if (!openssl_hash_chunk(hash_nid
, data
, &hash
))
126 sig
= chunk_alloc(ECDSA_size(this->ec
));
127 built
= ECDSA_sign(0, hash
.ptr
, hash
.len
, sig
.ptr
, &siglen
, this->ec
) == 1;
141 METHOD(private_key_t
, sign
, bool,
142 private_openssl_ec_private_key_t
*this, signature_scheme_t scheme
,
143 chunk_t data
, chunk_t
*signature
)
147 case SIGN_ECDSA_WITH_NULL
:
148 return build_signature(this, data
, signature
);
149 case SIGN_ECDSA_WITH_SHA1_DER
:
150 return build_der_signature(this, NID_sha1
, data
, signature
);
151 case SIGN_ECDSA_WITH_SHA256_DER
:
152 return build_der_signature(this, NID_sha256
, data
, signature
);
153 case SIGN_ECDSA_WITH_SHA384_DER
:
154 return build_der_signature(this, NID_sha384
, data
, signature
);
155 case SIGN_ECDSA_WITH_SHA512_DER
:
156 return build_der_signature(this, NID_sha512
, data
, signature
);
158 return build_curve_signature(this, scheme
, NID_sha256
,
159 NID_X9_62_prime256v1
, data
, signature
);
161 return build_curve_signature(this, scheme
, NID_sha384
,
162 NID_secp384r1
, data
, signature
);
164 return build_curve_signature(this, scheme
, NID_sha512
,
165 NID_secp521r1
, data
, signature
);
167 DBG1(DBG_LIB
, "signature scheme %N not supported",
168 signature_scheme_names
, scheme
);
173 METHOD(private_key_t
, decrypt
, bool,
174 private_openssl_ec_private_key_t
*this, encryption_scheme_t scheme
,
175 chunk_t crypto
, chunk_t
*plain
)
177 DBG1(DBG_LIB
, "EC private key decryption not implemented");
181 METHOD(private_key_t
, get_keysize
, int,
182 private_openssl_ec_private_key_t
*this)
184 switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(this->ec
)))
186 case NID_X9_62_prime256v1
:
197 METHOD(private_key_t
, get_type
, key_type_t
,
198 private_openssl_ec_private_key_t
*this)
203 METHOD(private_key_t
, get_public_key
, public_key_t
*,
204 private_openssl_ec_private_key_t
*this)
206 public_key_t
*public;
210 key
= chunk_alloc(i2d_EC_PUBKEY(this->ec
, NULL
));
212 i2d_EC_PUBKEY(this->ec
, &p
);
214 public = lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_ECDSA
,
215 BUILD_BLOB_ASN1_DER
, key
, BUILD_END
);
220 METHOD(private_key_t
, get_fingerprint
, bool,
221 private_openssl_ec_private_key_t
*this, cred_encoding_type_t type
,
222 chunk_t
*fingerprint
)
224 return openssl_ec_fingerprint(this->ec
, type
, fingerprint
);
227 METHOD(private_key_t
, get_encoding
, bool,
228 private_openssl_ec_private_key_t
*this, cred_encoding_type_t type
,
235 case PRIVKEY_ASN1_DER
:
240 *encoding
= chunk_alloc(i2d_ECPrivateKey(this->ec
, NULL
));
242 i2d_ECPrivateKey(this->ec
, &p
);
244 if (type
== PRIVKEY_PEM
)
246 chunk_t asn1_encoding
= *encoding
;
248 success
= lib
->encoding
->encode(lib
->encoding
, PRIVKEY_PEM
,
249 NULL
, encoding
, CRED_PART_ECDSA_PRIV_ASN1_DER
,
250 asn1_encoding
, CRED_PART_END
);
251 chunk_clear(&asn1_encoding
);
260 METHOD(private_key_t
, get_ref
, private_key_t
*,
261 private_openssl_ec_private_key_t
*this)
264 return &this->public.key
;
267 METHOD(private_key_t
, destroy
, void,
268 private_openssl_ec_private_key_t
*this)
270 if (ref_put(&this->ref
))
274 lib
->encoding
->clear_cache(lib
->encoding
, this->ec
);
275 EC_KEY_free(this->ec
);
282 * Internal generic constructor
284 static private_openssl_ec_private_key_t
*create_empty(void)
286 private_openssl_ec_private_key_t
*this;
291 .get_type
= _get_type
,
294 .get_keysize
= _get_keysize
,
295 .get_public_key
= _get_public_key
,
296 .equals
= private_key_equals
,
297 .belongs_to
= private_key_belongs_to
,
298 .get_fingerprint
= _get_fingerprint
,
299 .has_fingerprint
= private_key_has_fingerprint
,
300 .get_encoding
= _get_encoding
,
314 openssl_ec_private_key_t
*openssl_ec_private_key_gen(key_type_t type
,
317 private_openssl_ec_private_key_t
*this;
322 switch (va_arg(args
, builder_part_t
))
325 key_size
= va_arg(args
, u_int
);
338 this = create_empty();
342 this->ec
= EC_KEY_new_by_curve_name(NID_X9_62_prime256v1
);
345 this->ec
= EC_KEY_new_by_curve_name(NID_secp384r1
);
348 this->ec
= EC_KEY_new_by_curve_name(NID_secp521r1
);
351 DBG1(DBG_LIB
, "EC private key size %d not supported", key_size
);
355 if (EC_KEY_generate_key(this->ec
) != 1)
357 DBG1(DBG_LIB
, "EC private key generation failed", key_size
);
361 /* encode as a named curve key (no parameters), uncompressed public key */
362 EC_KEY_set_asn1_flag(this->ec
, OPENSSL_EC_NAMED_CURVE
);
363 EC_KEY_set_conv_form(this->ec
, POINT_CONVERSION_UNCOMPRESSED
);
364 return &this->public;
370 openssl_ec_private_key_t
*openssl_ec_private_key_load(key_type_t type
,
373 private_openssl_ec_private_key_t
*this;
374 chunk_t par
= chunk_empty
, key
= chunk_empty
;
378 switch (va_arg(args
, builder_part_t
))
380 case BUILD_BLOB_ALGID_PARAMS
:
381 par
= va_arg(args
, chunk_t
);
383 case BUILD_BLOB_ASN1_DER
:
384 key
= va_arg(args
, chunk_t
);
394 this = create_empty();
398 this->ec
= d2i_ECParameters(NULL
, (const u_char
**)&par
.ptr
, par
.len
);
403 if (!d2i_ECPrivateKey(&this->ec
, (const u_char
**)&key
.ptr
, key
.len
))
410 this->ec
= d2i_ECPrivateKey(NULL
, (const u_char
**)&key
.ptr
, key
.len
);
416 if (!EC_KEY_check_key(this->ec
))
420 return &this->public;
426 #endif /* OPENSSL_NO_EC */