]>
Commit | Line | Data |
---|---|---|
ea0823df | 1 | /* |
e35c3e2a | 2 | * Copyright (C) 2009 Martin Willi |
ea0823df TB |
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. | |
ea0823df TB |
15 | */ |
16 | ||
5a367e99 TB |
17 | #include <openssl/opensslconf.h> |
18 | ||
19 | #ifndef OPENSSL_NO_EC | |
20 | ||
ea0823df TB |
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; | |
7daf5226 | 40 | |
ea0823df TB |
41 | /** |
42 | * EC key object | |
43 | */ | |
44 | EC_KEY *ec; | |
7daf5226 | 45 | |
ea0823df TB |
46 | /** |
47 | * reference counter | |
48 | */ | |
49 | refcount_t ref; | |
50 | }; | |
51 | ||
ea0823df TB |
52 | /** |
53 | * Verification of a signature as in RFC 4754 | |
54 | */ | |
55 | static bool verify_signature(private_openssl_ec_public_key_t *this, | |
ac6a0d50 | 56 | chunk_t hash, chunk_t signature) |
ea0823df | 57 | { |
ea0823df | 58 | bool valid = FALSE; |
472cb4ce | 59 | ECDSA_SIG *sig; |
7daf5226 | 60 | |
ea0823df | 61 | sig = ECDSA_SIG_new(); |
ea0823df TB |
62 | if (sig) |
63 | { | |
472cb4ce MW |
64 | /* split the signature chunk in r and s */ |
65 | if (openssl_bn_split(signature, sig->r, sig->s)) | |
66 | { | |
ac6a0d50 | 67 | valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1); |
472cb4ce | 68 | } |
ea0823df TB |
69 | ECDSA_SIG_free(sig); |
70 | } | |
10b2898d MW |
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; | |
7daf5226 | 85 | |
10b2898d MW |
86 | req_group = EC_GROUP_new_by_curve_name(nid_curve); |
87 | if (!req_group) | |
88 | { | |
8b0e0910 | 89 | DBG1(DBG_LIB, "signature scheme %N not supported in EC (required curve " |
10b2898d MW |
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 | { | |
8b0e0910 | 96 | DBG1(DBG_LIB, "signature scheme %N not supported by private key", |
10b2898d MW |
97 | signature_scheme_names, scheme); |
98 | return FALSE; | |
99 | } | |
100 | EC_GROUP_free(req_group); | |
101 | if (!openssl_hash_chunk(nid_hash, data, &hash)) | |
11e6d285 | 102 | { |
10b2898d | 103 | return FALSE; |
11e6d285 | 104 | } |
ac6a0d50 | 105 | valid = verify_signature(this, hash, signature); |
10b2898d | 106 | chunk_free(&hash); |
ea0823df TB |
107 | return valid; |
108 | } | |
109 | ||
ea0823df | 110 | /** |
472cb4ce | 111 | * Verification of a DER encoded signature as in RFC 3279 |
ea0823df | 112 | */ |
472cb4ce | 113 | static bool verify_der_signature(private_openssl_ec_public_key_t *this, |
10b2898d | 114 | int nid_hash, chunk_t data, chunk_t signature) |
ea0823df | 115 | { |
472cb4ce | 116 | chunk_t hash; |
ea0823df | 117 | bool valid = FALSE; |
7daf5226 | 118 | |
ea0823df | 119 | /* remove any preceding 0-bytes from signature */ |
472cb4ce | 120 | while (signature.len && signature.ptr[0] == 0x00) |
ea0823df | 121 | { |
472cb4ce | 122 | signature = chunk_skip(signature, 1); |
ea0823df | 123 | } |
10b2898d | 124 | if (openssl_hash_chunk(nid_hash, data, &hash)) |
ea0823df | 125 | { |
472cb4ce MW |
126 | valid = ECDSA_verify(0, hash.ptr, hash.len, |
127 | signature.ptr, signature.len, this->ec); | |
128 | free(hash.ptr); | |
ea0823df | 129 | } |
ea0823df TB |
130 | return valid; |
131 | } | |
132 | ||
57202484 MW |
133 | METHOD(public_key_t, get_type, key_type_t, |
134 | private_openssl_ec_public_key_t *this) | |
ea0823df TB |
135 | { |
136 | return KEY_ECDSA; | |
137 | } | |
138 | ||
57202484 MW |
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) | |
ea0823df TB |
142 | { |
143 | switch (scheme) | |
144 | { | |
472cb4ce MW |
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); | |
11e6d285 | 153 | case SIGN_ECDSA_WITH_NULL: |
10b2898d | 154 | return verify_signature(this, data, signature); |
ea0823df | 155 | case SIGN_ECDSA_256: |
c8128024 AS |
156 | return verify_curve_signature(this, scheme, NID_sha256, |
157 | NID_X9_62_prime256v1, data, signature); | |
ea0823df | 158 | case SIGN_ECDSA_384: |
c8128024 AS |
159 | return verify_curve_signature(this, scheme, NID_sha384, |
160 | NID_secp384r1, data, signature); | |
ea0823df | 161 | case SIGN_ECDSA_521: |
c8128024 AS |
162 | return verify_curve_signature(this, scheme, NID_sha512, |
163 | NID_secp521r1, data, signature); | |
ea0823df | 164 | default: |
8b0e0910 | 165 | DBG1(DBG_LIB, "signature scheme %N not supported in EC", |
ea0823df TB |
166 | signature_scheme_names, scheme); |
167 | return FALSE; | |
168 | } | |
169 | } | |
170 | ||
57202484 | 171 | METHOD(public_key_t, encrypt, bool, |
33ddaaab MW |
172 | private_openssl_ec_public_key_t *this, encryption_scheme_t scheme, |
173 | chunk_t crypto, chunk_t *plain) | |
ea0823df | 174 | { |
8b0e0910 | 175 | DBG1(DBG_LIB, "EC public key encryption not implemented"); |
ea0823df TB |
176 | return FALSE; |
177 | } | |
178 | ||
a944d209 | 179 | METHOD(public_key_t, get_keysize, int, |
57202484 | 180 | private_openssl_ec_public_key_t *this) |
ea0823df | 181 | { |
a944d209 MW |
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 | } | |
ea0823df TB |
193 | } |
194 | ||
195 | /** | |
b12c6d16 | 196 | * Calculate fingerprint from a EC_KEY, also used in ec private key. |
ea0823df | 197 | */ |
da9724e6 | 198 | bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp) |
ea0823df | 199 | { |
b12c6d16 | 200 | hasher_t *hasher; |
e35c3e2a MW |
201 | chunk_t key; |
202 | u_char *p; | |
7daf5226 | 203 | |
b12c6d16 | 204 | if (lib->encoding->get_cache(lib->encoding, type, ec, fp)) |
ea0823df | 205 | { |
e35c3e2a | 206 | return TRUE; |
ea0823df | 207 | } |
b12c6d16 MW |
208 | switch (type) |
209 | { | |
da9724e6 | 210 | case KEYID_PUBKEY_SHA1: |
b12c6d16 MW |
211 | key = chunk_alloc(i2o_ECPublicKey(ec, NULL)); |
212 | p = key.ptr; | |
213 | i2o_ECPublicKey(ec, &p); | |
214 | break; | |
da9724e6 | 215 | case KEYID_PUBKEY_INFO_SHA1: |
b12c6d16 MW |
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); | |
87dd205b | 224 | if (!hasher || !hasher->allocate_hash(hasher, key, fp)) |
b12c6d16 | 225 | { |
8b0e0910 | 226 | DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); |
87dd205b | 227 | DESTROY_IF(hasher); |
b12c6d16 MW |
228 | free(key.ptr); |
229 | return FALSE; | |
230 | } | |
b12c6d16 | 231 | hasher->destroy(hasher); |
1a8ef8aa | 232 | free(key.ptr); |
b12c6d16 MW |
233 | lib->encoding->cache(lib->encoding, type, ec, *fp); |
234 | return TRUE; | |
235 | } | |
236 | ||
57202484 MW |
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) | |
b12c6d16 MW |
240 | { |
241 | return openssl_ec_fingerprint(this->ec, type, fingerprint); | |
ea0823df TB |
242 | } |
243 | ||
57202484 MW |
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) | |
ea0823df | 247 | { |
e35c3e2a | 248 | u_char *p; |
7daf5226 | 249 | |
b12c6d16 MW |
250 | switch (type) |
251 | { | |
da9724e6 MW |
252 | case PUBKEY_SPKI_ASN1_DER: |
253 | case PUBKEY_PEM: | |
b12c6d16 | 254 | { |
29cf15a9 AS |
255 | bool success = TRUE; |
256 | ||
b12c6d16 MW |
257 | *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); |
258 | p = encoding->ptr; | |
259 | i2d_EC_PUBKEY(this->ec, &p); | |
29cf15a9 | 260 | |
da9724e6 | 261 | if (type == PUBKEY_PEM) |
29cf15a9 AS |
262 | { |
263 | chunk_t asn1_encoding = *encoding; | |
264 | ||
da9724e6 MW |
265 | success = lib->encoding->encode(lib->encoding, PUBKEY_PEM, |
266 | NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER, | |
267 | asn1_encoding, CRED_PART_END); | |
29cf15a9 | 268 | chunk_clear(&asn1_encoding); |
0a4dc787 | 269 | } |
29cf15a9 | 270 | return success; |
b12c6d16 MW |
271 | } |
272 | default: | |
273 | return FALSE; | |
274 | } | |
ea0823df TB |
275 | } |
276 | ||
57202484 MW |
277 | METHOD(public_key_t, get_ref, public_key_t*, |
278 | private_openssl_ec_public_key_t *this) | |
ea0823df TB |
279 | { |
280 | ref_get(&this->ref); | |
57202484 | 281 | return &this->public.key; |
ea0823df TB |
282 | } |
283 | ||
57202484 MW |
284 | METHOD(public_key_t, destroy, void, |
285 | private_openssl_ec_public_key_t *this) | |
ea0823df TB |
286 | { |
287 | if (ref_put(&this->ref)) | |
288 | { | |
289 | if (this->ec) | |
290 | { | |
b12c6d16 | 291 | lib->encoding->clear_cache(lib->encoding, this->ec); |
ea0823df TB |
292 | EC_KEY_free(this->ec); |
293 | } | |
ea0823df TB |
294 | free(this); |
295 | } | |
296 | } | |
297 | ||
298 | /** | |
299 | * Generic private constructor | |
300 | */ | |
e35c3e2a | 301 | static private_openssl_ec_public_key_t *create_empty() |
ea0823df | 302 | { |
57202484 MW |
303 | private_openssl_ec_public_key_t *this; |
304 | ||
305 | INIT(this, | |
ba31fe1f MW |
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 | }, | |
57202484 MW |
319 | }, |
320 | .ref = 1, | |
321 | ); | |
7daf5226 | 322 | |
ea0823df TB |
323 | return this; |
324 | } | |
325 | ||
ea0823df | 326 | /** |
30c06407 | 327 | * See header. |
ea0823df | 328 | */ |
30c06407 MW |
329 | openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type, |
330 | va_list args) | |
ea0823df | 331 | { |
30c06407 MW |
332 | private_openssl_ec_public_key_t *this; |
333 | chunk_t blob = chunk_empty; | |
7daf5226 | 334 | |
30c06407 | 335 | if (type != KEY_ECDSA) |
ea0823df | 336 | { |
ea0823df TB |
337 | return NULL; |
338 | } | |
e35c3e2a | 339 | |
30c06407 | 340 | while (TRUE) |
ea0823df | 341 | { |
30c06407 | 342 | switch (va_arg(args, builder_part_t)) |
ea0823df | 343 | { |
f7c17aa1 | 344 | case BUILD_BLOB_ASN1_DER: |
30c06407 MW |
345 | blob = va_arg(args, chunk_t); |
346 | continue; | |
347 | case BUILD_END: | |
f7c17aa1 | 348 | break; |
30c06407 MW |
349 | default: |
350 | return NULL; | |
ea0823df | 351 | } |
30c06407 | 352 | break; |
ea0823df | 353 | } |
30c06407 MW |
354 | this = create_empty(); |
355 | this->ec = d2i_EC_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); | |
356 | if (!this->ec) | |
ea0823df | 357 | { |
30c06407 | 358 | destroy(this); |
ea0823df TB |
359 | return NULL; |
360 | } | |
ea0823df TB |
361 | return &this->public; |
362 | } | |
5a367e99 | 363 | #endif /* OPENSSL_NO_EC */ |
ea0823df | 364 |