Updated openssl plugin to the new builder API
[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_ec_public_key.h"
18 #include "openssl_util.h"
19
20 #include <debug.h>
21
22 #include <openssl/evp.h>
23 #include <openssl/ecdsa.h>
24 #include <openssl/x509.h>
25
26 typedef struct private_openssl_ec_public_key_t private_openssl_ec_public_key_t;
27
28 /**
29 * Private data structure with signing context.
30 */
31 struct private_openssl_ec_public_key_t {
32 /**
33 * Public interface for this signer.
34 */
35 openssl_ec_public_key_t public;
36
37 /**
38 * EC key object
39 */
40 EC_KEY *ec;
41
42 /**
43 * reference counter
44 */
45 refcount_t ref;
46 };
47
48 /**
49 * Verification of a signature as in RFC 4754
50 */
51 static bool verify_signature(private_openssl_ec_public_key_t *this,
52 chunk_t hash, chunk_t signature)
53 {
54 bool valid = FALSE;
55 ECDSA_SIG *sig;
56
57 sig = ECDSA_SIG_new();
58 if (sig)
59 {
60 /* split the signature chunk in r and s */
61 if (openssl_bn_split(signature, sig->r, sig->s))
62 {
63 valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1);
64 }
65 ECDSA_SIG_free(sig);
66 }
67 return valid;
68 }
69
70 /**
71 * Verify a RFC 4754 signature for a specified curve and hash algorithm
72 */
73 static bool verify_curve_signature(private_openssl_ec_public_key_t *this,
74 signature_scheme_t scheme, int nid_hash,
75 int nid_curve, chunk_t data, chunk_t signature)
76 {
77 const EC_GROUP *my_group;
78 EC_GROUP *req_group;
79 chunk_t hash;
80 bool valid;
81
82 req_group = EC_GROUP_new_by_curve_name(nid_curve);
83 if (!req_group)
84 {
85 DBG1("signature scheme %N not supported in EC (required curve "
86 "not supported)", signature_scheme_names, scheme);
87 return FALSE;
88 }
89 my_group = EC_KEY_get0_group(this->ec);
90 if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
91 {
92 DBG1("signature scheme %N not supported by private key",
93 signature_scheme_names, scheme);
94 return FALSE;
95 }
96 EC_GROUP_free(req_group);
97 if (!openssl_hash_chunk(nid_hash, data, &hash))
98 {
99 return FALSE;
100 }
101 valid = verify_signature(this, hash, signature);
102 chunk_free(&hash);
103 return valid;
104 }
105
106 /**
107 * Verification of a DER encoded signature as in RFC 3279
108 */
109 static bool verify_der_signature(private_openssl_ec_public_key_t *this,
110 int nid_hash, chunk_t data, chunk_t signature)
111 {
112 chunk_t hash;
113 bool valid = FALSE;
114
115 /* remove any preceding 0-bytes from signature */
116 while (signature.len && signature.ptr[0] == 0x00)
117 {
118 signature = chunk_skip(signature, 1);
119 }
120 if (openssl_hash_chunk(nid_hash, data, &hash))
121 {
122 valid = ECDSA_verify(0, hash.ptr, hash.len,
123 signature.ptr, signature.len, this->ec);
124 free(hash.ptr);
125 }
126 return valid;
127 }
128
129 /**
130 * Implementation of public_key_t.get_type.
131 */
132 static key_type_t get_type(private_openssl_ec_public_key_t *this)
133 {
134 return KEY_ECDSA;
135 }
136
137 /**
138 * Implementation of public_key_t.verify.
139 */
140 static bool verify(private_openssl_ec_public_key_t *this,
141 signature_scheme_t scheme, 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("signature scheme %N not supported in EC",
166 signature_scheme_names, scheme);
167 return FALSE;
168 }
169 }
170
171 /**
172 * Implementation of public_key_t.get_keysize.
173 */
174 static bool encrypt_(private_openssl_ec_public_key_t *this,
175 chunk_t crypto, chunk_t *plain)
176 {
177 DBG1("EC public key encryption not implemented");
178 return FALSE;
179 }
180
181 /**
182 * Implementation of public_key_t.get_keysize.
183 */
184 static size_t get_keysize(private_openssl_ec_public_key_t *this)
185 {
186 return EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec));
187 }
188
189 /**
190 * Calculate fingerprint from a EC_KEY, also used in ec private key.
191 */
192 bool openssl_ec_fingerprint(EC_KEY *ec, key_encoding_type_t type, chunk_t *fp)
193 {
194 hasher_t *hasher;
195 chunk_t key;
196 u_char *p;
197
198 if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
199 {
200 return TRUE;
201 }
202 switch (type)
203 {
204 case KEY_ID_PUBKEY_SHA1:
205 key = chunk_alloc(i2o_ECPublicKey(ec, NULL));
206 p = key.ptr;
207 i2o_ECPublicKey(ec, &p);
208 break;
209 case KEY_ID_PUBKEY_INFO_SHA1:
210 key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL));
211 p = key.ptr;
212 i2d_EC_PUBKEY(ec, &p);
213 break;
214 default:
215 return FALSE;
216 }
217 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
218 if (!hasher)
219 {
220 DBG1("SHA1 hash algorithm not supported, fingerprinting failed");
221 free(key.ptr);
222 return FALSE;
223 }
224 hasher->allocate_hash(hasher, key, fp);
225 hasher->destroy(hasher);
226 free(key.ptr);
227 lib->encoding->cache(lib->encoding, type, ec, *fp);
228 return TRUE;
229 }
230
231 /**
232 * Implementation of private_key_t.get_fingerprint.
233 */
234 static bool get_fingerprint(private_openssl_ec_public_key_t *this,
235 key_encoding_type_t type, chunk_t *fingerprint)
236 {
237 return openssl_ec_fingerprint(this->ec, type, fingerprint);
238 }
239
240 /**
241 * Implementation of private_key_t.get_encoding.
242 */
243 static bool get_encoding(private_openssl_ec_public_key_t *this,
244 key_encoding_type_t type, chunk_t *encoding)
245 {
246 u_char *p;
247
248 switch (type)
249 {
250 case KEY_PUB_SPKI_ASN1_DER:
251 {
252 *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL));
253 p = encoding->ptr;
254 i2d_EC_PUBKEY(this->ec, &p);
255 return TRUE;
256 }
257 default:
258 return FALSE;
259 }
260 }
261
262 /**
263 * Implementation of public_key_t.get_ref.
264 */
265 static public_key_t* get_ref(private_openssl_ec_public_key_t *this)
266 {
267 ref_get(&this->ref);
268 return &this->public.interface;
269 }
270
271 /**
272 * Implementation of openssl_ec_public_key.destroy.
273 */
274 static void destroy(private_openssl_ec_public_key_t *this)
275 {
276 if (ref_put(&this->ref))
277 {
278 if (this->ec)
279 {
280 lib->encoding->clear_cache(lib->encoding, this->ec);
281 EC_KEY_free(this->ec);
282 }
283 free(this);
284 }
285 }
286
287 /**
288 * Generic private constructor
289 */
290 static private_openssl_ec_public_key_t *create_empty()
291 {
292 private_openssl_ec_public_key_t *this = malloc_thing(private_openssl_ec_public_key_t);
293
294 this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
295 this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
296 this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_;
297 this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
298 this->public.interface.equals = public_key_equals;
299 this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint;
300 this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding;
301 this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
302 this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
303
304 this->ec = NULL;
305 this->ref = 1;
306
307 return this;
308 }
309
310 /**
311 * See header.
312 */
313 openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type,
314 va_list args)
315 {
316 private_openssl_ec_public_key_t *this;
317 chunk_t blob = chunk_empty;
318
319 if (type != KEY_ECDSA)
320 {
321 return NULL;
322 }
323
324 while (TRUE)
325 {
326 switch (va_arg(args, builder_part_t))
327 {
328 case BUILD_BLOB_ASN1_DER:
329 blob = va_arg(args, chunk_t);
330 continue;
331 case BUILD_END:
332 break;
333 default:
334 return NULL;
335 }
336 break;
337 }
338 this = create_empty();
339 this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len);
340 if (!this->ec)
341 {
342 destroy(this);
343 return NULL;
344 }
345 return &this->public;
346 }
347