Check return value of ECDSA_Verify() correctly
[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 switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(this->ec)))
183 {
184 case NID_X9_62_prime256v1:
185 return 256;
186 case NID_secp384r1:
187 return 384;
188 case NID_secp521r1:
189 return 521;
190 default:
191 return 0;
192 }
193 }
194
195 /**
196 * Calculate fingerprint from a EC_KEY, also used in ec private key.
197 */
198 bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp)
199 {
200 hasher_t *hasher;
201 chunk_t key;
202 u_char *p;
203
204 if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
205 {
206 return TRUE;
207 }
208 switch (type)
209 {
210 case KEYID_PUBKEY_SHA1:
211 key = chunk_alloc(i2o_ECPublicKey(ec, NULL));
212 p = key.ptr;
213 i2o_ECPublicKey(ec, &p);
214 break;
215 case KEYID_PUBKEY_INFO_SHA1:
216 key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL));
217 p = key.ptr;
218 i2d_EC_PUBKEY(ec, &p);
219 break;
220 default:
221 return FALSE;
222 }
223 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
224 if (!hasher || !hasher->allocate_hash(hasher, key, fp))
225 {
226 DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
227 DESTROY_IF(hasher);
228 free(key.ptr);
229 return FALSE;
230 }
231 hasher->destroy(hasher);
232 free(key.ptr);
233 lib->encoding->cache(lib->encoding, type, ec, *fp);
234 return TRUE;
235 }
236
237 METHOD(public_key_t, get_fingerprint, bool,
238 private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
239 chunk_t *fingerprint)
240 {
241 return openssl_ec_fingerprint(this->ec, type, fingerprint);
242 }
243
244 METHOD(public_key_t, get_encoding, bool,
245 private_openssl_ec_public_key_t *this, cred_encoding_type_t type,
246 chunk_t *encoding)
247 {
248 u_char *p;
249
250 switch (type)
251 {
252 case PUBKEY_SPKI_ASN1_DER:
253 case PUBKEY_PEM:
254 {
255 bool success = TRUE;
256
257 *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
258 p = encoding->ptr;
259 i2d_EC_PUBKEY(this->ec, &p);
260
261 if (type == PUBKEY_PEM)
262 {
263 chunk_t asn1_encoding = *encoding;
264
265 success = lib->encoding->encode(lib->encoding, PUBKEY_PEM,
266 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
267 asn1_encoding, CRED_PART_END);
268 chunk_clear(&asn1_encoding);
269 }
270 return success;
271 }
272 default:
273 return FALSE;
274 }
275 }
276
277 METHOD(public_key_t, get_ref, public_key_t*,
278 private_openssl_ec_public_key_t *this)
279 {
280 ref_get(&this->ref);
281 return &this->public.key;
282 }
283
284 METHOD(public_key_t, destroy, void,
285 private_openssl_ec_public_key_t *this)
286 {
287 if (ref_put(&this->ref))
288 {
289 if (this->ec)
290 {
291 lib->encoding->clear_cache(lib->encoding, this->ec);
292 EC_KEY_free(this->ec);
293 }
294 free(this);
295 }
296 }
297
298 /**
299 * Generic private constructor
300 */
301 static private_openssl_ec_public_key_t *create_empty()
302 {
303 private_openssl_ec_public_key_t *this;
304
305 INIT(this,
306 .public = {
307 .key = {
308 .get_type = _get_type,
309 .verify = _verify,
310 .encrypt = _encrypt,
311 .get_keysize = _get_keysize,
312 .equals = public_key_equals,
313 .get_fingerprint = _get_fingerprint,
314 .has_fingerprint = public_key_has_fingerprint,
315 .get_encoding = _get_encoding,
316 .get_ref = _get_ref,
317 .destroy = _destroy,
318 },
319 },
320 .ref = 1,
321 );
322
323 return this;
324 }
325
326 /**
327 * See header.
328 */
329 openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
330 va_list args)
331 {
332 private_openssl_ec_public_key_t *this;
333 chunk_t blob = chunk_empty;
334
335 if (type != KEY_ECDSA)
336 {
337 return NULL;
338 }
339
340 while (TRUE)
341 {
342 switch (va_arg(args, builder_part_t))
343 {
344 case BUILD_BLOB_ASN1_DER:
345 blob = va_arg(args, chunk_t);
346 continue;
347 case BUILD_END:
348 break;
349 default:
350 return NULL;
351 }
352 break;
353 }
354 this = create_empty();
355 this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
356 if (!this->ec)
357 {
358 destroy(this);
359 return NULL;
360 }
361 return &this->public;
362 }
363 #endif /* OPENSSL_NO_ECDSA */
364