382c5541861afebf7f53b8f631d23c8eff85cc98
[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 bool success = TRUE;
249 u_char *p;
250
251 *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
252 p = encoding->ptr;
253 i2d_EC_PUBKEY(this->ec, &p);
254
255 if (type != PUBKEY_SPKI_ASN1_DER)
256 {
257 chunk_t asn1_encoding = *encoding;
258
259 success = lib->encoding->encode(lib->encoding, type,
260 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
261 asn1_encoding, CRED_PART_END);
262 chunk_clear(&asn1_encoding);
263 }
264 return success;
265 }
266
267 METHOD(public_key_t, get_ref, public_key_t*,
268 private_openssl_ec_public_key_t *this)
269 {
270 ref_get(&this->ref);
271 return &this->public.key;
272 }
273
274 METHOD(public_key_t, destroy, void,
275 private_openssl_ec_public_key_t *this)
276 {
277 if (ref_put(&this->ref))
278 {
279 if (this->ec)
280 {
281 lib->encoding->clear_cache(lib->encoding, this->ec);
282 EC_KEY_free(this->ec);
283 }
284 free(this);
285 }
286 }
287
288 /**
289 * Generic private constructor
290 */
291 static private_openssl_ec_public_key_t *create_empty()
292 {
293 private_openssl_ec_public_key_t *this;
294
295 INIT(this,
296 .public = {
297 .key = {
298 .get_type = _get_type,
299 .verify = _verify,
300 .encrypt = _encrypt,
301 .get_keysize = _get_keysize,
302 .equals = public_key_equals,
303 .get_fingerprint = _get_fingerprint,
304 .has_fingerprint = public_key_has_fingerprint,
305 .get_encoding = _get_encoding,
306 .get_ref = _get_ref,
307 .destroy = _destroy,
308 },
309 },
310 .ref = 1,
311 );
312
313 return this;
314 }
315
316 /**
317 * See header.
318 */
319 openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
320 va_list args)
321 {
322 private_openssl_ec_public_key_t *this;
323 chunk_t blob = chunk_empty;
324
325 if (type != KEY_ECDSA)
326 {
327 return NULL;
328 }
329
330 while (TRUE)
331 {
332 switch (va_arg(args, builder_part_t))
333 {
334 case BUILD_BLOB_ASN1_DER:
335 blob = va_arg(args, chunk_t);
336 continue;
337 case BUILD_END:
338 break;
339 default:
340 return NULL;
341 }
342 break;
343 }
344 this = create_empty();
345 this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
346 if (!this->ec)
347 {
348 destroy(this);
349 return NULL;
350 }
351 return &this->public;
352 }
353 #endif /* OPENSSL_NO_ECDSA */
354