16257178d54f85bcdc48d64de2ada49f4492f7fa
[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_EC
20
21 #include "openssl_ec_public_key.h"
22 #include "openssl_util.h"
23
24 #include <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);
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, size_t,
180 private_openssl_ec_public_key_t *this)
181 {
182 return EC_FIELD_ELEMENT_LEN(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)
215 {
216 DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
217 free(key.ptr);
218 return FALSE;
219 }
220 hasher->allocate_hash(hasher, key, fp);
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 u_char *p;
239
240 switch (type)
241 {
242 case PUBKEY_SPKI_ASN1_DER:
243 case PUBKEY_PEM:
244 {
245 bool success = TRUE;
246
247 *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
248 p = encoding->ptr;
249 i2d_EC_PUBKEY(this->ec, &p);
250
251 if (type == PUBKEY_PEM)
252 {
253 chunk_t asn1_encoding = *encoding;
254
255 success = lib->encoding->encode(lib->encoding, PUBKEY_PEM,
256 NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
257 asn1_encoding, CRED_PART_END);
258 chunk_clear(&asn1_encoding);
259 }
260 return success;
261 }
262 default:
263 return FALSE;
264 }
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.key = {
297 .get_type = _get_type,
298 .verify = _verify,
299 .encrypt = _encrypt,
300 .get_keysize = _get_keysize,
301 .equals = public_key_equals,
302 .get_fingerprint = _get_fingerprint,
303 .has_fingerprint = public_key_has_fingerprint,
304 .get_encoding = _get_encoding,
305 .get_ref = _get_ref,
306 .destroy = _destroy,
307 },
308 .ref = 1,
309 );
310
311 return this;
312 }
313
314 /**
315 * See header.
316 */
317 openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
318 va_list args)
319 {
320 private_openssl_ec_public_key_t *this;
321 chunk_t blob = chunk_empty;
322
323 if (type != KEY_ECDSA)
324 {
325 return NULL;
326 }
327
328 while (TRUE)
329 {
330 switch (va_arg(args, builder_part_t))
331 {
332 case BUILD_BLOB_ASN1_DER:
333 blob = va_arg(args, chunk_t);
334 continue;
335 case BUILD_END:
336 break;
337 default:
338 return NULL;
339 }
340 break;
341 }
342 this = create_empty();
343 this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
344 if (!this->ec)
345 {
346 destroy(this);
347 return NULL;
348 }
349 return &this->public;
350 }
351 #endif /* OPENSSL_NO_EC */
352