2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "openssl_ec_private_key.h"
17 #include "openssl_ec_public_key.h"
18 #include "openssl_util.h"
22 #include <openssl/evp.h>
23 #include <openssl/ecdsa.h>
25 typedef struct private_openssl_ec_private_key_t private_openssl_ec_private_key_t
;
28 * Private data of a openssl_ec_private_key_t object.
30 struct private_openssl_ec_private_key_t
{
32 * Public interface for this signer.
34 openssl_ec_private_key_t
public;
42 * Keyid formed as a SHA-1 hash of a privateKey object
44 identification_t
* keyid
;
47 * Keyid formed as a SHA-1 hash of a privateKeyInfo object
49 identification_t
* keyid_info
;
58 * Mapping from the signature scheme defined in (RFC 4754) to the elliptic
59 * curve and the hash algorithm
63 * Scheme specified in RFC 4754
76 } openssl_ecdsa_scheme_t
;
78 #define END_OF_LIST -1
83 static openssl_ecdsa_scheme_t ecdsa_schemes
[] = {
84 {SIGN_ECDSA_256
, NID_sha256
, NID_X9_62_prime256v1
},
85 {SIGN_ECDSA_384
, NID_sha384
, NID_secp384r1
},
86 {SIGN_ECDSA_521
, NID_sha512
, NID_secp521r1
},
91 * Look up the hash and curve of a signature scheme
93 static bool lookup_scheme(int scheme
, int *hash
, int *curve
)
95 openssl_ecdsa_scheme_t
*ecdsa_scheme
= ecdsa_schemes
;
96 while (ecdsa_scheme
->scheme
!= END_OF_LIST
)
98 if (scheme
== ecdsa_scheme
->scheme
)
100 *hash
= ecdsa_scheme
->hash
;
101 *curve
= ecdsa_scheme
->curve
;
110 * shared functions, implemented in openssl_ec_public_key.c
112 bool openssl_ec_public_key_build_id(EC_KEY
*ec
, identification_t
**keyid
,
113 identification_t
**keyid_info
);
115 openssl_ec_public_key_t
*openssl_ec_public_key_create_from_private_key(EC_KEY
*ec
);
119 * Convert an ECDSA_SIG to a chunk by concatenating r and s.
120 * This function allocates memory for the chunk.
122 static bool sig2chunk(const EC_GROUP
*group
, ECDSA_SIG
*sig
, chunk_t
*chunk
)
124 return openssl_bn_cat(EC_FIELD_ELEMENT_LEN(group
), sig
->r
, sig
->s
, chunk
);
128 * Build the signature
130 static bool build_signature(private_openssl_ec_private_key_t
*this,
131 chunk_t hash
, chunk_t
*signature
)
133 ECDSA_SIG
*sig
= ECDSA_do_sign(hash
.ptr
, hash
.len
, this->ec
);
140 success
= sig2chunk(EC_KEY_get0_group(this->ec
), sig
, signature
);
146 * Implementation of private_key_t.get_type.
148 static key_type_t
get_type(private_openssl_ec_private_key_t
*this)
154 * Implementation of private_key_t.sign.
156 static bool sign(private_openssl_ec_private_key_t
*this, signature_scheme_t scheme
,
157 chunk_t data
, chunk_t
*signature
)
161 if (scheme
== SIGN_ECDSA_WITH_NULL
)
163 success
= build_signature(this, data
, signature
);
168 const EC_GROUP
*my_group
;
169 chunk_t hash
= chunk_empty
;
170 int hash_type
, curve
;
172 if (!lookup_scheme(scheme
, &hash_type
, &curve
))
174 DBG1("signature scheme %N not supported in EC",
175 signature_scheme_names
, scheme
);
179 req_group
= EC_GROUP_new_by_curve_name(curve
);
182 DBG1("signature scheme %N not supported in EC (required curve not supported)",
183 signature_scheme_names
, scheme
);
187 my_group
= EC_KEY_get0_group(this->ec
);
188 if (EC_GROUP_cmp(my_group
, req_group
, NULL
) != 0)
190 DBG1("signature scheme %N not supported by private key",
191 signature_scheme_names
, scheme
);
194 EC_GROUP_free(req_group
);
196 if (!openssl_hash_chunk(hash_type
, data
, &hash
))
200 success
= build_signature(this, hash
, signature
);
207 * Implementation of private_key_t.destroy.
209 static bool decrypt(private_openssl_ec_private_key_t
*this,
210 chunk_t crypto
, chunk_t
*plain
)
212 DBG1("EC private key decryption not implemented");
217 * Implementation of private_key_t.get_keysize.
219 static size_t get_keysize(private_openssl_ec_private_key_t
*this)
221 return EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec
));
225 * Implementation of private_key_t.get_id.
227 static identification_t
* get_id(private_openssl_ec_private_key_t
*this,
232 case ID_PUBKEY_INFO_SHA1
:
233 return this->keyid_info
;
242 * Implementation of private_key_t.get_public_key.
244 static openssl_ec_public_key_t
* get_public_key(private_openssl_ec_private_key_t
*this)
246 return openssl_ec_public_key_create_from_private_key(this->ec
);
250 * Implementation of private_key_t.belongs_to.
252 static bool belongs_to(private_openssl_ec_private_key_t
*this, public_key_t
*public)
254 identification_t
*keyid
;
256 if (public->get_type(public) != KEY_ECDSA
)
260 keyid
= public->get_id(public, ID_PUBKEY_SHA1
);
261 if (keyid
&& keyid
->equals(keyid
, this->keyid
))
265 keyid
= public->get_id(public, ID_PUBKEY_INFO_SHA1
);
266 if (keyid
&& keyid
->equals(keyid
, this->keyid_info
))
274 * Implementation of private_key_t.get_encoding.
276 static chunk_t
get_encoding(private_openssl_ec_private_key_t
*this)
278 chunk_t enc
= chunk_alloc(i2d_ECPrivateKey(this->ec
, NULL
));
280 i2d_ECPrivateKey(this->ec
, &p
);
285 * Implementation of private_key_t.get_ref.
287 static private_openssl_ec_private_key_t
* get_ref(private_openssl_ec_private_key_t
*this)
295 * Implementation of private_key_t.destroy.
297 static void destroy(private_openssl_ec_private_key_t
*this)
299 if (ref_put(&this->ref
))
303 EC_KEY_free(this->ec
);
305 DESTROY_IF(this->keyid
);
306 DESTROY_IF(this->keyid_info
);
312 * Internal generic constructor
314 static private_openssl_ec_private_key_t
*openssl_ec_private_key_create_empty(void)
316 private_openssl_ec_private_key_t
*this = malloc_thing(private_openssl_ec_private_key_t
);
318 this->public.interface
.get_type
= (key_type_t (*)(private_key_t
*this))get_type
;
319 this->public.interface
.sign
= (bool (*)(private_key_t
*this, signature_scheme_t scheme
, chunk_t data
, chunk_t
*signature
))sign
;
320 this->public.interface
.decrypt
= (bool (*)(private_key_t
*this, chunk_t crypto
, chunk_t
*plain
))decrypt
;
321 this->public.interface
.get_keysize
= (size_t (*) (private_key_t
*this))get_keysize
;
322 this->public.interface
.get_id
= (identification_t
* (*) (private_key_t
*this,id_type_t
))get_id
;
323 this->public.interface
.get_public_key
= (public_key_t
* (*)(private_key_t
*this))get_public_key
;
324 this->public.interface
.belongs_to
= (bool (*) (private_key_t
*this, public_key_t
*public))belongs_to
;
325 this->public.interface
.get_encoding
= (chunk_t(*)(private_key_t
*))get_encoding
;
326 this->public.interface
.get_ref
= (private_key_t
* (*)(private_key_t
*this))get_ref
;
327 this->public.interface
.destroy
= (void (*)(private_key_t
*this))destroy
;
331 this->keyid_info
= NULL
;
338 * load private key from an ASN1 encoded blob
340 static openssl_ec_private_key_t
*load(chunk_t blob
)
342 u_char
*p
= blob
.ptr
;
343 private_openssl_ec_private_key_t
*this = openssl_ec_private_key_create_empty();
345 this->ec
= d2i_ECPrivateKey(NULL
, (const u_char
**)&p
, blob
.len
);
355 if (!openssl_ec_public_key_build_id(this->ec
, &this->keyid
, &this->keyid_info
))
361 if (!EC_KEY_check_key(this->ec
))
367 return &this->public;
370 typedef struct private_builder_t private_builder_t
;
372 * Builder implementation for key loading/generation
374 struct private_builder_t
{
375 /** implements the builder interface */
377 /** loaded/generated private key */
378 openssl_ec_private_key_t
*key
;
382 * Implementation of builder_t.build
384 static openssl_ec_private_key_t
*build(private_builder_t
*this)
386 openssl_ec_private_key_t
*key
= this->key
;
393 * Implementation of builder_t.add
395 static void add(private_builder_t
*this, builder_part_t part
, ...)
404 case BUILD_BLOB_ASN1_DER
:
406 va_start(args
, part
);
407 chunk
= va_arg(args
, chunk_t
);
408 this->key
= load(chunk_clone(chunk
));
418 destroy((private_openssl_ec_private_key_t
*)this->key
);
420 builder_cancel(&this->public);
424 * Builder construction function
426 builder_t
*openssl_ec_private_key_builder(key_type_t type
)
428 private_builder_t
*this;
430 if (type
!= KEY_ECDSA
)
435 this = malloc_thing(private_builder_t
);
438 this->public.add
= (void(*)(builder_t
*this, builder_part_t part
, ...))add
;
439 this->public.build
= (void*(*)(builder_t
*this))build
;
441 return &this->public;