openssl: Report correct key length for EC keys when not using NIST curves
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_ec_public_key.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 */
16
17 #include <openssl/opensslconf.h>
18
19 #ifndef OPENSSL_NO_ECDSA
20
21 #include "openssl_ec_public_key.h"
22 #include "openssl_util.h"
23
24 #include <utils/debug.h>
25
26 #include <openssl/evp.h>
27 #include <openssl/ecdsa.h>
28 #include <openssl/x509.h>
29
30 typedef struct private_openssl_ec_public_key_t private_openssl_ec_public_key_t;
31
32 /**
33 * Private data structure with signing context.
34 */
35 struct private_openssl_ec_public_key_t {
36 /**
37 * Public interface for this signer.
38 */
39 openssl_ec_public_key_t public;
40
41 /**
42 * EC key object
43 */
44 EC_KEY *ec;
45
46 /**
47 * reference counter
48 */
49 refcount_t ref;
50 };
51
52 /**
53 * Verification of a signature as in RFC 4754
54 */
55 static bool verify_signature(private_openssl_ec_public_key_t *this,
56 chunk_t hash, chunk_t signature)
57 {
58 bool valid = FALSE;
59 ECDSA_SIG *sig;
60
61 sig = ECDSA_SIG_new();
62 if (sig)
63 {
64 /* split the signature chunk in r and s */
65 if (openssl_bn_split(signature, sig->r, sig->s))
66 {
67 valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1);
68 }
69 ECDSA_SIG_free(sig);
70 }
71 return valid;
72 }
73
74 /**
75 * Verify a RFC 4754 signature for a specified curve and hash algorithm
76 */
77 static bool verify_curve_signature(private_openssl_ec_public_key_t *this,
78 signature_scheme_t scheme, int nid_hash,
79 int nid_curve, chunk_t data, chunk_t signature)
80 {
81 const EC_GROUP *my_group;
82 EC_GROUP *req_group;
83 chunk_t hash;
84 bool valid;
85
86 req_group = EC_GROUP_new_by_curve_name(nid_curve);
87 if (!req_group)
88 {
89 DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve "
90 "not supported)", signature_scheme_names, scheme);
91 return FALSE;
92 }
93 my_group = EC_KEY_get0_group(this->ec);
94 if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
95 {
96 DBG1(DBG_LIB, "signature scheme %N not supported by private key",
97 signature_scheme_names, scheme);
98 return FALSE;
99 }
100 EC_GROUP_free(req_group);
101 if (!openssl_hash_chunk(nid_hash, data, &hash))
102 {
103 return FALSE;
104 }
105 valid = verify_signature(this, hash, signature);
106 chunk_free(&hash);
107 return valid;
108 }
109
110 /**
111 * Verification of a DER encoded signature as in RFC 3279
112 */
113 static bool verify_der_signature(private_openssl_ec_public_key_t *this,
114 int nid_hash, chunk_t data, chunk_t signature)
115 {
116 chunk_t hash;
117 bool valid = FALSE;
118
119 /* remove any preceding 0-bytes from signature */
120 while (signature.len && signature.ptr[0] == 0x00)
121 {
122 signature = chunk_skip(signature, 1);
123 }
124 if (openssl_hash_chunk(nid_hash, data, &hash))
125 {
126 valid = ECDSA_verify(0, hash.ptr, hash.len,
127 signature.ptr, signature.len, this->ec) == 1;
128 free(hash.ptr);
129 }
130 return valid;
131 }
132
133 METHOD(public_key_t, get_type, key_type_t,
134 private_openssl_ec_public_key_t *this)
135 {
136 return KEY_ECDSA;
137 }
138
139 METHOD(public_key_t, verify, bool,
140 private_openssl_ec_public_key_t *this, signature_scheme_t scheme,
141 chunk_t data, chunk_t signature)
142 {
143 switch (scheme)
144 {
145 case SIGN_ECDSA_WITH_SHA1_DER:
146 return verify_der_signature(this, NID_sha1, data, signature);
147 case SIGN_ECDSA_WITH_SHA256_DER:
148 return verify_der_signature(this, NID_sha256, data, signature);
149 case SIGN_ECDSA_WITH_SHA384_DER:
150 return verify_der_signature(this, NID_sha384, data, signature);
151 case SIGN_ECDSA_WITH_SHA512_DER:
152 return verify_der_signature(this, NID_sha512, data, signature);
153 case SIGN_ECDSA_WITH_NULL:
154 return verify_signature(this, data, signature);
155 case SIGN_ECDSA_256:
156 return verify_curve_signature(this, scheme, NID_sha256,
157 NID_X9_62_prime256v1, data, signature);
158 case SIGN_ECDSA_384:
159 return verify_curve_signature(this, scheme, NID_sha384,
160 NID_secp384r1, data, signature);
161 case SIGN_ECDSA_521:
162 return verify_curve_signature(this, scheme, NID_sha512,
163 NID_secp521r1, data, signature);
164 default:
165 DBG1(DBG_LIB, "signature scheme %N not supported in EC",
166 signature_scheme_names, scheme);
167 return FALSE;
168 }
169 }
170
171 METHOD(public_key_t, encrypt, bool,
172 private_openssl_ec_public_key_t *this, encryption_scheme_t scheme,
173 chunk_t crypto, chunk_t *plain)
174 {
175 DBG1(DBG_LIB, "EC public key encryption not implemented");
176 return FALSE;
177 }
178
179 METHOD(public_key_t, get_keysize, int,
180 private_openssl_ec_public_key_t *this)
181 {
182 return EC_GROUP_get_degree(EC_KEY_get0_group(this->ec));
183 }
184
185 /**
186 * Calculate fingerprint from a EC_KEY, also used in ec private key.
187 */
188 bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp)
189 {
190 hasher_t *hasher;
191 chunk_t key;
192 u_char *p;
193
194 if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
195 {
196 return TRUE;
197 }
198 switch (type)
199 {
200 case KEYID_PUBKEY_SHA1:
201 key = chunk_alloc(i2o_ECPublicKey(ec, NULL));
202 p = key.ptr;
203 i2o_ECPublicKey(ec, &p);
204 break;
205 case KEYID_PUBKEY_INFO_SHA1:
206 key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL));
207 p = key.ptr;
208 i2d_EC_PUBKEY(ec, &p);
209 break;
210 default:
211 return FALSE;
212 }
213 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
214 if (!hasher || !hasher->allocate_hash(hasher, key, fp))
215 {
216 DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
217 DESTROY_IF(hasher);
218 free(key.ptr);
219 return FALSE;
220 }
221 hasher->destroy(hasher);
222 free(key.ptr);
223 lib->encoding->cache(lib->encoding, type, ec, *fp);
224 return TRUE;
225 }
226
227 METHOD(public_key_t, get_fingerprint, bool,
228 private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
229 chunk_t *fingerprint)
230 {
231 return openssl_ec_fingerprint(this->ec, type, fingerprint);
232 }
233
234 METHOD(public_key_t, get_encoding, bool,
235 private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
236 chunk_t *encoding)
237 {
238 bool success = TRUE;
239 u_char *p;
240
241 *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
242 p = encoding->ptr;
243 i2d_EC_PUBKEY(this->ec, &p);
244
245 if (type != PUBKEY_SPKI_ASN1_DER)
246 {
247 chunk_t asn1_encoding = *encoding;
248
249 success = lib->encoding->encode(lib->encoding, type,
250 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
251 asn1_encoding, CRED_PART_END);
252 chunk_clear(&asn1_encoding);
253 }
254 return success;
255 }
256
257 METHOD(public_key_t, get_ref, public_key_t*,
258 private_openssl_ec_public_key_t *this)
259 {
260 ref_get(&this->ref);
261 return &this->public.key;
262 }
263
264 METHOD(public_key_t, destroy, void,
265 private_openssl_ec_public_key_t *this)
266 {
267 if (ref_put(&this->ref))
268 {
269 if (this->ec)
270 {
271 lib->encoding->clear_cache(lib->encoding, this->ec);
272 EC_KEY_free(this->ec);
273 }
274 free(this);
275 }
276 }
277
278 /**
279 * Generic private constructor
280 */
281 static private_openssl_ec_public_key_t *create_empty()
282 {
283 private_openssl_ec_public_key_t *this;
284
285 INIT(this,
286 .public = {
287 .key = {
288 .get_type = _get_type,
289 .verify = _verify,
290 .encrypt = _encrypt,
291 .get_keysize = _get_keysize,
292 .equals = public_key_equals,
293 .get_fingerprint = _get_fingerprint,
294 .has_fingerprint = public_key_has_fingerprint,
295 .get_encoding = _get_encoding,
296 .get_ref = _get_ref,
297 .destroy = _destroy,
298 },
299 },
300 .ref = 1,
301 );
302
303 return this;
304 }
305
306 /**
307 * See header.
308 */
309 openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
310 va_list args)
311 {
312 private_openssl_ec_public_key_t *this;
313 chunk_t blob = chunk_empty;
314
315 if (type != KEY_ECDSA)
316 {
317 return NULL;
318 }
319
320 while (TRUE)
321 {
322 switch (va_arg(args, builder_part_t))
323 {
324 case BUILD_BLOB_ASN1_DER:
325 blob = va_arg(args, chunk_t);
326 continue;
327 case BUILD_END:
328 break;
329 default:
330 return NULL;
331 }
332 break;
333 }
334 this = create_empty();
335 this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
336 if (!this->ec)
337 {
338 destroy(this);
339 return NULL;
340 }
341 return &this->public;
342 }
343 #endif /* OPENSSL_NO_ECDSA */
344