]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
Add a return value to hasher_t.allocate_hash()
[thirdparty/strongswan.git] / src / libstrongswan / plugins / openssl / openssl_ec_public_key.c
CommitLineData
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
30typedef struct private_openssl_ec_public_key_t private_openssl_ec_public_key_t;
31
32/**
33 * Private data structure with signing context.
34 */
35struct 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 */
55static 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 */
77static 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 113static 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
133METHOD(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
139METHOD(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 171METHOD(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 179METHOD(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 198bool 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
237METHOD(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
244METHOD(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
277METHOD(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
284METHOD(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 301static 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
329openssl_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