/src/samba/third_party/heimdal/lib/hx509/crypto-ec.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016 Kungliga Tekniska Högskolan |
3 | | * (Royal Institute of Technology, Stockholm, Sweden). |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in the |
15 | | * documentation and/or other materials provided with the distribution. |
16 | | * |
17 | | * 3. Neither the name of the Institute nor the names of its contributors |
18 | | * may be used to endorse or promote products derived from this software |
19 | | * without specific prior written permission. |
20 | | * |
21 | | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND |
22 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE |
25 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | | * SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | #include <config.h> |
35 | | |
36 | | #ifdef HAVE_HCRYPTO_W_OPENSSL |
37 | | #include <openssl/evp.h> |
38 | | #include <openssl/ec.h> |
39 | | #include <openssl/ecdsa.h> |
40 | | #include <openssl/rsa.h> |
41 | | #include <openssl/bn.h> |
42 | | #include <openssl/objects.h> |
43 | | #ifdef HAVE_OPENSSL_30 |
44 | | #include <openssl/asn1.h> |
45 | | #include <openssl/core_names.h> |
46 | | #endif |
47 | | #define HEIM_NO_CRYPTO_HDRS |
48 | | #endif /* HAVE_HCRYPTO_W_OPENSSL */ |
49 | | |
50 | | #include "hx_locl.h" |
51 | | |
52 | | extern const AlgorithmIdentifier _hx509_signature_sha512_data; |
53 | | extern const AlgorithmIdentifier _hx509_signature_sha384_data; |
54 | | extern const AlgorithmIdentifier _hx509_signature_sha256_data; |
55 | | extern const AlgorithmIdentifier _hx509_signature_sha1_data; |
56 | | |
57 | | HX509_LIB_FUNCTION void HX509_LIB_CALL |
58 | | _hx509_private_eckey_free(void *eckey) |
59 | 0 | { |
60 | | #ifdef HAVE_HCRYPTO_W_OPENSSL |
61 | | #ifdef HAVE_OPENSSL_30 |
62 | | EVP_PKEY_free(eckey); |
63 | | #else |
64 | | EC_KEY_free(eckey); |
65 | | #endif |
66 | | #endif |
67 | 0 | } |
68 | | |
69 | | #ifdef HAVE_HCRYPTO_W_OPENSSL |
70 | | static struct oid2nid_st { |
71 | | const heim_oid *oid; |
72 | | int nid; |
73 | | } oid2nid[] = { |
74 | | { ASN1_OID_ID_EC_GROUP_SECP256R1, NID_X9_62_prime256v1 }, |
75 | | #ifdef NID_secp521r1 |
76 | | { ASN1_OID_ID_EC_GROUP_SECP521R1, NID_secp521r1 }, |
77 | | #endif |
78 | | #ifdef NID_secp384r1 |
79 | | { ASN1_OID_ID_EC_GROUP_SECP384R1, NID_secp384r1 }, |
80 | | #endif |
81 | | #ifdef NID_secp160r1 |
82 | | { ASN1_OID_ID_EC_GROUP_SECP160R1, NID_secp160r1 }, |
83 | | #endif |
84 | | #ifdef NID_secp160r2 |
85 | | { ASN1_OID_ID_EC_GROUP_SECP160R2, NID_secp160r2 }, |
86 | | #endif |
87 | | /* XXX Add more! Add X25519! */ |
88 | | }; |
89 | | |
90 | | int |
91 | | _hx509_ossl_oid2nid(heim_oid *oid) |
92 | | { |
93 | | size_t i; |
94 | | |
95 | | for (i = 0; i < sizeof(oid2nid)/sizeof(oid2nid[0]); i++) |
96 | | if (der_heim_oid_cmp(oid, oid2nid[i].oid) == 0) |
97 | | return oid2nid[i].nid; |
98 | | return NID_undef; |
99 | | } |
100 | | |
101 | | static int |
102 | | ECParameters2nid(hx509_context context, |
103 | | heim_octet_string *parameters, |
104 | | int *nid) |
105 | | { |
106 | | ECParameters ecparam; |
107 | | size_t size; |
108 | | int ret; |
109 | | |
110 | | if (parameters == NULL) { |
111 | | ret = HX509_PARSING_KEY_FAILED; |
112 | | hx509_set_error_string(context, 0, ret, |
113 | | "EC parameters missing"); |
114 | | return ret; |
115 | | } |
116 | | |
117 | | ret = decode_ECParameters(parameters->data, parameters->length, |
118 | | &ecparam, &size); |
119 | | if (ret) { |
120 | | hx509_set_error_string(context, 0, ret, |
121 | | "Failed to decode EC parameters"); |
122 | | return ret; |
123 | | } |
124 | | |
125 | | if (ecparam.element != choice_ECParameters_namedCurve) { |
126 | | free_ECParameters(&ecparam); |
127 | | hx509_set_error_string(context, 0, ret, |
128 | | "EC parameters is not a named curve"); |
129 | | return HX509_CRYPTO_SIG_INVALID_FORMAT; |
130 | | } |
131 | | |
132 | | *nid = _hx509_ossl_oid2nid(&ecparam.u.namedCurve); |
133 | | free_ECParameters(&ecparam); |
134 | | if (*nid == NID_undef) { |
135 | | hx509_set_error_string(context, 0, ret, |
136 | | "Failed to find matcing NID for EC curve"); |
137 | | return HX509_CRYPTO_SIG_INVALID_FORMAT; |
138 | | } |
139 | | return 0; |
140 | | } |
141 | | |
142 | | #ifdef HAVE_OPENSSL_30 |
143 | | static const EVP_MD * |
144 | | signature_alg2digest_evp_md(hx509_context context, |
145 | | const AlgorithmIdentifier *digest_alg) |
146 | | { |
147 | | if ((&digest_alg->algorithm == &asn1_oid_id_sha512 || |
148 | | der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_sha512) == 0)) |
149 | | return EVP_sha512(); |
150 | | if ((&digest_alg->algorithm == &asn1_oid_id_sha384 || |
151 | | der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_sha384) == 0)) |
152 | | return EVP_sha384(); |
153 | | if ((&digest_alg->algorithm == &asn1_oid_id_sha256 || |
154 | | der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_sha256) == 0)) |
155 | | return EVP_sha256(); |
156 | | if ((&digest_alg->algorithm == &asn1_oid_id_secsig_sha_1 || |
157 | | der_heim_oid_cmp(&digest_alg->algorithm, &asn1_oid_id_secsig_sha_1) == 0)) |
158 | | return EVP_sha1(); |
159 | | if ((&digest_alg->algorithm == &asn1_oid_id_rsa_digest_md5 || |
160 | | der_heim_oid_cmp(&digest_alg->algorithm, |
161 | | &asn1_oid_id_rsa_digest_md5) == 0)) |
162 | | return EVP_md5(); |
163 | | |
164 | | /* |
165 | | * XXX Decode the `digest_alg->algorithm' OID and include it in the error |
166 | | * message. |
167 | | */ |
168 | | hx509_set_error_string(context, 0, EINVAL, |
169 | | "Digest algorithm not found"); |
170 | | return NULL; |
171 | | } |
172 | | #endif |
173 | | |
174 | | |
175 | | |
176 | | /* |
177 | | * |
178 | | */ |
179 | | |
180 | | static int |
181 | | ecdsa_verify_signature(hx509_context context, |
182 | | const struct signature_alg *sig_alg, |
183 | | const Certificate *signer, |
184 | | const AlgorithmIdentifier *alg, |
185 | | const heim_octet_string *data, |
186 | | const heim_octet_string *sig) |
187 | | { |
188 | | #ifdef HAVE_OPENSSL_30 |
189 | | const AlgorithmIdentifier *digest_alg = sig_alg->digest_alg; |
190 | | const EVP_MD *md = signature_alg2digest_evp_md(context, digest_alg); |
191 | | const SubjectPublicKeyInfo *spi; |
192 | | const char *curve_sn = NULL; /* sn == short name in OpenSSL parlance */ |
193 | | OSSL_PARAM params[2]; |
194 | | EVP_PKEY_CTX *pctx = NULL; |
195 | | EVP_MD_CTX *mdctx = NULL; |
196 | | EVP_PKEY *template = NULL; |
197 | | EVP_PKEY *public = NULL; |
198 | | const unsigned char *p; |
199 | | size_t len; |
200 | | char *curve_sn_dup = NULL; |
201 | | int groupnid; |
202 | | int ret = 0; |
203 | | |
204 | | spi = &signer->tbsCertificate.subjectPublicKeyInfo; |
205 | | if (der_heim_oid_cmp(&spi->algorithm.algorithm, |
206 | | ASN1_OID_ID_ECPUBLICKEY) != 0) |
207 | | hx509_set_error_string(context, 0, |
208 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT, |
209 | | /* XXX Include the OID in the message */ |
210 | | "Unsupported subjectPublicKey algorithm"); |
211 | | if (ret == 0) |
212 | | ret = ECParameters2nid(context, spi->algorithm.parameters, &groupnid); |
213 | | if (ret == 0 && (curve_sn = OBJ_nid2sn(groupnid)) == NULL) |
214 | | hx509_set_error_string(context, 0, |
215 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT, |
216 | | "Could not resolve curve NID %d to its short name", |
217 | | groupnid); |
218 | | if (ret == 0 && (curve_sn_dup = strdup(curve_sn)) == NULL) |
219 | | ret = hx509_enomem(context); |
220 | | if (ret == 0 && (mdctx = EVP_MD_CTX_new()) == NULL) |
221 | | ret = hx509_enomem(context); |
222 | | |
223 | | /* |
224 | | * In order for d2i_PublicKey() to work we need to create a template key |
225 | | * that has the curve parameters for the subjectPublicKey. |
226 | | * |
227 | | * Or maybe we could learn to use the OSSL_DECODER(3) API. But this works, |
228 | | * at least until OpenSSL deprecates d2i_PublicKey() and forces us to use |
229 | | * OSSL_DECODER(3). |
230 | | */ |
231 | | if (ret == 0) { |
232 | | /* |
233 | | * Apparently there's no error checking to be done here? Why does |
234 | | * OSSL_PARAM_construct_utf8_string() want a non-const for the value? |
235 | | * Is that a bug in OpenSSL? |
236 | | */ |
237 | | params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, |
238 | | curve_sn_dup, 0); |
239 | | params[1] = OSSL_PARAM_construct_end(); |
240 | | |
241 | | if ((pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) |
242 | | ret = hx509_enomem(context); |
243 | | } |
244 | | if (ret == 0 && EVP_PKEY_fromdata_init(pctx) != 1) |
245 | | ret = hx509_enomem(context); |
246 | | if (ret == 0 && |
247 | | EVP_PKEY_fromdata(pctx, &template, |
248 | | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, params) != 1) |
249 | | hx509_set_error_string(context, 0, |
250 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT, |
251 | | "Could not set up to parse key for curve %s", |
252 | | curve_sn); |
253 | | |
254 | | /* Finally we can decode the subjectPublicKey */ |
255 | | p = spi->subjectPublicKey.data; |
256 | | len = spi->subjectPublicKey.length / 8; |
257 | | if (ret == 0 && |
258 | | (public = d2i_PublicKey(EVP_PKEY_EC, &template, &p, len)) == NULL) |
259 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT; |
260 | | |
261 | | /* EVP_DigestVerifyInit() will allocate a new pctx */ |
262 | | EVP_PKEY_CTX_free(pctx); |
263 | | pctx = NULL; |
264 | | |
265 | | if (ret == 0 && |
266 | | EVP_DigestVerifyInit(mdctx, &pctx, md, NULL, public) != 1) |
267 | | hx509_set_error_string(context, 0, |
268 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT, |
269 | | "Could not initialize " |
270 | | "OpenSSL signature verification"); |
271 | | if (ret == 0 && |
272 | | EVP_DigestVerifyUpdate(mdctx, data->data, data->length) != 1) |
273 | | hx509_set_error_string(context, 0, |
274 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT, |
275 | | "Could not initialize " |
276 | | "OpenSSL signature verification"); |
277 | | if (ret == 0 && |
278 | | EVP_DigestVerifyFinal(mdctx, sig->data, sig->length) != 1) |
279 | | hx509_set_error_string(context, 0, |
280 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT, |
281 | | "Signature verification failed"); |
282 | | |
283 | | EVP_MD_CTX_free(mdctx); |
284 | | EVP_PKEY_free(template); |
285 | | free(curve_sn_dup); |
286 | | return ret; |
287 | | #else |
288 | | const AlgorithmIdentifier *digest_alg; |
289 | | const SubjectPublicKeyInfo *spi; |
290 | | heim_octet_string digest; |
291 | | int ret; |
292 | | EC_KEY *key = NULL; |
293 | | int groupnid; |
294 | | EC_GROUP *group; |
295 | | const unsigned char *p; |
296 | | long len; |
297 | | |
298 | | digest_alg = sig_alg->digest_alg; |
299 | | |
300 | | ret = _hx509_create_signature(context, |
301 | | NULL, |
302 | | digest_alg, |
303 | | data, |
304 | | NULL, |
305 | | &digest); |
306 | | if (ret) |
307 | | return ret; |
308 | | |
309 | | /* set up EC KEY */ |
310 | | spi = &signer->tbsCertificate.subjectPublicKeyInfo; |
311 | | |
312 | | if (der_heim_oid_cmp(&spi->algorithm.algorithm, ASN1_OID_ID_ECPUBLICKEY) != 0) |
313 | | return HX509_CRYPTO_SIG_INVALID_FORMAT; |
314 | | |
315 | | /* |
316 | | * Find the group id |
317 | | */ |
318 | | |
319 | | ret = ECParameters2nid(context, spi->algorithm.parameters, &groupnid); |
320 | | if (ret) { |
321 | | der_free_octet_string(&digest); |
322 | | return ret; |
323 | | } |
324 | | |
325 | | /* |
326 | | * Create group, key, parse key |
327 | | */ |
328 | | |
329 | | key = EC_KEY_new(); |
330 | | group = EC_GROUP_new_by_curve_name(groupnid); |
331 | | EC_KEY_set_group(key, group); |
332 | | EC_GROUP_free(group); |
333 | | |
334 | | p = spi->subjectPublicKey.data; |
335 | | len = spi->subjectPublicKey.length / 8; |
336 | | |
337 | | if (o2i_ECPublicKey(&key, &p, len) == NULL) { |
338 | | EC_KEY_free(key); |
339 | | return HX509_CRYPTO_SIG_INVALID_FORMAT; |
340 | | } |
341 | | |
342 | | ret = ECDSA_verify(-1, digest.data, digest.length, |
343 | | sig->data, sig->length, key); |
344 | | der_free_octet_string(&digest); |
345 | | EC_KEY_free(key); |
346 | | if (ret != 1) { |
347 | | ret = HX509_CRYPTO_SIG_INVALID_FORMAT; |
348 | | return ret; |
349 | | } |
350 | | |
351 | | return 0; |
352 | | #endif |
353 | | } |
354 | | |
355 | | static int |
356 | | ecdsa_create_signature(hx509_context context, |
357 | | const struct signature_alg *sig_alg, |
358 | | const hx509_private_key signer, |
359 | | const AlgorithmIdentifier *alg, |
360 | | const heim_octet_string *data, |
361 | | AlgorithmIdentifier *signatureAlgorithm, |
362 | | heim_octet_string *sig) |
363 | | { |
364 | | #ifdef HAVE_OPENSSL_30 |
365 | | const AlgorithmIdentifier *digest_alg = sig_alg->digest_alg; |
366 | | const EVP_MD *md = signature_alg2digest_evp_md(context, digest_alg); |
367 | | EVP_MD_CTX *mdctx = NULL; |
368 | | EVP_PKEY_CTX *pctx = NULL; |
369 | | const heim_oid *sig_oid; |
370 | | int ret = 0; |
371 | | |
372 | | sig->data = NULL; |
373 | | sig->length = 0; |
374 | | if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0) |
375 | | _hx509_abort("internal error passing private key to wrong ops"); |
376 | | |
377 | | sig_oid = sig_alg->sig_oid; |
378 | | digest_alg = sig_alg->digest_alg; |
379 | | |
380 | | if (signatureAlgorithm) |
381 | | ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, |
382 | | "\x05\x00", 2); |
383 | | mdctx = EVP_MD_CTX_new(); |
384 | | if (mdctx == NULL) |
385 | | ret = hx509_enomem(context); |
386 | | if (ret == 0 && EVP_DigestSignInit(mdctx, &pctx, md, NULL, |
387 | | signer->private_key.ecdsa) != 1) |
388 | | ret = HX509_CMS_FAILED_CREATE_SIGATURE; |
389 | | if (ret == 0 && EVP_DigestSignUpdate(mdctx, data->data, data->length) != 1) |
390 | | ret = HX509_CMS_FAILED_CREATE_SIGATURE; |
391 | | if (ret == 0 && EVP_DigestSignFinal(mdctx, NULL, &sig->length) != 1) |
392 | | ret = HX509_CMS_FAILED_CREATE_SIGATURE; |
393 | | if (ret == 0 && (sig->data = malloc(sig->length)) == NULL) |
394 | | ret = hx509_enomem(context); |
395 | | if (ret == 0 && EVP_DigestSignFinal(mdctx, sig->data, &sig->length) != 1) |
396 | | ret = HX509_CMS_FAILED_CREATE_SIGATURE; |
397 | | |
398 | | if (ret == HX509_CMS_FAILED_CREATE_SIGATURE) { |
399 | | /* XXX Extract error detail from OpenSSL */ |
400 | | hx509_set_error_string(context, 0, ret, |
401 | | "ECDSA sign failed"); |
402 | | } |
403 | | |
404 | | if (ret) { |
405 | | if (signatureAlgorithm) |
406 | | free_AlgorithmIdentifier(signatureAlgorithm); |
407 | | free(sig->data); |
408 | | sig->data = NULL; |
409 | | sig->length = 0; |
410 | | } |
411 | | EVP_MD_CTX_free(mdctx); |
412 | | return ret; |
413 | | #else |
414 | | const AlgorithmIdentifier *digest_alg; |
415 | | heim_octet_string indata; |
416 | | const heim_oid *sig_oid; |
417 | | unsigned int siglen; |
418 | | int ret; |
419 | | |
420 | | if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0) |
421 | | _hx509_abort("internal error passing private key to wrong ops"); |
422 | | |
423 | | sig_oid = sig_alg->sig_oid; |
424 | | digest_alg = sig_alg->digest_alg; |
425 | | |
426 | | if (signatureAlgorithm) { |
427 | | ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, |
428 | | "\x05\x00", 2); |
429 | | if (ret) { |
430 | | hx509_clear_error_string(context); |
431 | | return ret; |
432 | | } |
433 | | } |
434 | | |
435 | | ret = _hx509_create_signature(context, |
436 | | NULL, |
437 | | digest_alg, |
438 | | data, |
439 | | NULL, |
440 | | &indata); |
441 | | if (ret) |
442 | | goto error; |
443 | | |
444 | | sig->length = ECDSA_size(signer->private_key.ecdsa); |
445 | | sig->data = malloc(sig->length); |
446 | | if (sig->data == NULL) { |
447 | | der_free_octet_string(&indata); |
448 | | ret = ENOMEM; |
449 | | hx509_set_error_string(context, 0, ret, "out of memory"); |
450 | | goto error; |
451 | | } |
452 | | |
453 | | siglen = sig->length; |
454 | | |
455 | | ret = ECDSA_sign(-1, indata.data, indata.length, |
456 | | sig->data, &siglen, signer->private_key.ecdsa); |
457 | | der_free_octet_string(&indata); |
458 | | if (ret != 1) { |
459 | | ret = HX509_CMS_FAILED_CREATE_SIGATURE; |
460 | | hx509_set_error_string(context, 0, ret, |
461 | | "ECDSA sign failed: %d", ret); |
462 | | goto error; |
463 | | } |
464 | | if (siglen > sig->length) |
465 | | _hx509_abort("ECDSA signature prelen longer than output len"); |
466 | | |
467 | | sig->length = siglen; |
468 | | |
469 | | return 0; |
470 | | error: |
471 | | if (signatureAlgorithm) |
472 | | free_AlgorithmIdentifier(signatureAlgorithm); |
473 | | return ret; |
474 | | #endif |
475 | | } |
476 | | |
477 | | static int |
478 | | ecdsa_available(const hx509_private_key signer, |
479 | | const AlgorithmIdentifier *sig_alg) |
480 | | { |
481 | | #ifdef HAVE_OPENSSL_30 |
482 | | const struct signature_alg *sig; |
483 | | size_t group_name_len = 0; |
484 | | char group_name_buf[96]; |
485 | | EC_GROUP *group = NULL; |
486 | | BN_CTX *bnctx = NULL; |
487 | | BIGNUM *order = NULL; |
488 | | int ret = 0; |
489 | | |
490 | | if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) |
491 | | _hx509_abort("internal error passing private key to wrong ops"); |
492 | | |
493 | | sig = _hx509_find_sig_alg(&sig_alg->algorithm); |
494 | | if (sig == NULL || sig->digest_size == 0) |
495 | | return 0; |
496 | | |
497 | | if (EVP_PKEY_get_group_name(signer->private_key.ecdsa, group_name_buf, |
498 | | sizeof(group_name_buf), |
499 | | &group_name_len) != 1 || |
500 | | group_name_len >= sizeof(group_name_buf)) { |
501 | | return 0; |
502 | | } |
503 | | group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(group_name_buf)); |
504 | | bnctx = BN_CTX_new(); |
505 | | order = BN_new(); |
506 | | if (group && bnctx && order && |
507 | | EC_GROUP_get_order(group, order, bnctx) == 1) |
508 | | ret = 1; |
509 | | |
510 | | #if 0 |
511 | | /* |
512 | | * If anything, require a digest at least as wide as the EC key size |
513 | | * |
514 | | * if (BN_num_bytes(order) > sig->digest_size) |
515 | | * ret = 0; |
516 | | */ |
517 | | #endif |
518 | | |
519 | | BN_CTX_free(bnctx); |
520 | | BN_clear_free(order); |
521 | | EC_GROUP_free(group); |
522 | | return ret; |
523 | | #else |
524 | | const struct signature_alg *sig; |
525 | | const EC_GROUP *group; |
526 | | BN_CTX *bnctx = NULL; |
527 | | BIGNUM *order = NULL; |
528 | | int ret = 0; |
529 | | |
530 | | if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) |
531 | | _hx509_abort("internal error passing private key to wrong ops"); |
532 | | |
533 | | sig = _hx509_find_sig_alg(&sig_alg->algorithm); |
534 | | |
535 | | if (sig == NULL || sig->digest_size == 0) |
536 | | return 0; |
537 | | |
538 | | group = EC_KEY_get0_group(signer->private_key.ecdsa); |
539 | | if (group == NULL) |
540 | | return 0; |
541 | | |
542 | | bnctx = BN_CTX_new(); |
543 | | order = BN_new(); |
544 | | if (order == NULL) |
545 | | goto err; |
546 | | |
547 | | if (EC_GROUP_get_order(group, order, bnctx) != 1) |
548 | | goto err; |
549 | | |
550 | | #if 0 |
551 | | /* If anything, require a digest at least as wide as the EC key size */ |
552 | | if (BN_num_bytes(order) > sig->digest_size) |
553 | | #endif |
554 | | ret = 1; |
555 | | err: |
556 | | if (bnctx) |
557 | | BN_CTX_free(bnctx); |
558 | | if (order) |
559 | | BN_clear_free(order); |
560 | | |
561 | | return ret; |
562 | | #endif |
563 | | } |
564 | | |
565 | | static int |
566 | | ecdsa_private_key2SPKI(hx509_context context, |
567 | | hx509_private_key private_key, |
568 | | SubjectPublicKeyInfo *spki) |
569 | | { |
570 | | memset(spki, 0, sizeof(*spki)); |
571 | | return ENOMEM; |
572 | | } |
573 | | |
574 | | static int |
575 | | ecdsa_private_key_export(hx509_context context, |
576 | | const hx509_private_key key, |
577 | | hx509_key_format_t format, |
578 | | heim_octet_string *data) |
579 | | { |
580 | | return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; |
581 | | } |
582 | | |
583 | | static int |
584 | | ecdsa_private_key_import(hx509_context context, |
585 | | const AlgorithmIdentifier *keyai, |
586 | | const void *data, |
587 | | size_t len, |
588 | | hx509_key_format_t format, |
589 | | hx509_private_key private_key) |
590 | | { |
591 | | #ifdef HAVE_OPENSSL_30 |
592 | | const unsigned char *p = data; |
593 | | EVP_PKEY *key = NULL; |
594 | | int ret = 0; |
595 | | |
596 | | switch (format) { |
597 | | case HX509_KEY_FORMAT_PKCS8: |
598 | | key = d2i_PrivateKey(EVP_PKEY_EC, NULL, &p, len); |
599 | | if (key == NULL) { |
600 | | hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, |
601 | | "Failed to parse EC private key"); |
602 | | return HX509_PARSING_KEY_FAILED; |
603 | | } |
604 | | break; |
605 | | |
606 | | default: |
607 | | return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; |
608 | | } |
609 | | |
610 | | /* |
611 | | * We used to have to call EC_KEY_new(), then EC_KEY_set_group() the group |
612 | | * (curve) on the resulting EC_KEY _before_ we could d2i_ECPrivateKey() the |
613 | | * key, but that's all deprecated in OpenSSL 3.0. |
614 | | * |
615 | | * In fact, it's not clear how ever to assign a group to a private key, |
616 | | * but that's what the documentation for d2i_PrivateKey() says: that |
617 | | * its `EVP_PKEY **' argument must be non-NULL pointing to a key that |
618 | | * has had the group set. |
619 | | * |
620 | | * However, from code inspection it's clear that when the ECParameters |
621 | | * are present in the private key payload passed to d2i_PrivateKey(), |
622 | | * the group will be taken from that. |
623 | | * |
624 | | * What we'll do is that if we have `keyai->parameters' we'll check if the |
625 | | * key we got is for the same group. |
626 | | */ |
627 | | if (keyai->parameters) { |
628 | | size_t gname_len = 0; |
629 | | char buf[96]; |
630 | | int got_group_nid = NID_undef; |
631 | | int want_groupnid = NID_undef; |
632 | | |
633 | | ret = ECParameters2nid(context, keyai->parameters, &want_groupnid); |
634 | | if (ret == 0 && |
635 | | (EVP_PKEY_get_group_name(key, buf, sizeof(buf), &gname_len) != 1 || |
636 | | gname_len >= sizeof(buf))) |
637 | | ret = HX509_ALG_NOT_SUPP; |
638 | | if (ret == 0) |
639 | | got_group_nid = OBJ_txt2nid(buf); |
640 | | if (ret == 0 && |
641 | | (got_group_nid == NID_undef || want_groupnid != got_group_nid)) |
642 | | ret = HX509_ALG_NOT_SUPP; |
643 | | } |
644 | | |
645 | | if (ret == 0) { |
646 | | private_key->private_key.ecdsa = key; |
647 | | private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; |
648 | | key = NULL; |
649 | | } |
650 | | |
651 | | EVP_PKEY_free(key); |
652 | | return ret; |
653 | | #else |
654 | | const unsigned char *p = data; |
655 | | EC_KEY **pkey = NULL; |
656 | | EC_KEY *key; |
657 | | |
658 | | if (keyai->parameters) { |
659 | | EC_GROUP *group; |
660 | | int groupnid; |
661 | | int ret; |
662 | | |
663 | | ret = ECParameters2nid(context, keyai->parameters, &groupnid); |
664 | | if (ret) |
665 | | return ret; |
666 | | |
667 | | key = EC_KEY_new(); |
668 | | if (key == NULL) |
669 | | return ENOMEM; |
670 | | |
671 | | group = EC_GROUP_new_by_curve_name(groupnid); |
672 | | if (group == NULL) { |
673 | | EC_KEY_free(key); |
674 | | return ENOMEM; |
675 | | } |
676 | | EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); |
677 | | if (EC_KEY_set_group(key, group) != 1) { |
678 | | EC_KEY_free(key); |
679 | | EC_GROUP_free(group); |
680 | | return ENOMEM; |
681 | | } |
682 | | EC_GROUP_free(group); |
683 | | pkey = &key; |
684 | | } |
685 | | |
686 | | switch (format) { |
687 | | case HX509_KEY_FORMAT_DER: |
688 | | |
689 | | private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); |
690 | | if (private_key->private_key.ecdsa == NULL) { |
691 | | hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, |
692 | | "Failed to parse EC private key"); |
693 | | return HX509_PARSING_KEY_FAILED; |
694 | | } |
695 | | private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; |
696 | | break; |
697 | | |
698 | | default: |
699 | | return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; |
700 | | } |
701 | | |
702 | | return 0; |
703 | | #endif |
704 | | } |
705 | | |
706 | | static int |
707 | | ecdsa_generate_private_key(hx509_context context, |
708 | | struct hx509_generate_private_context *ctx, |
709 | | hx509_private_key private_key) |
710 | | { |
711 | | return ENOMEM; |
712 | | } |
713 | | |
714 | | static BIGNUM * |
715 | | ecdsa_get_internal(hx509_context context, |
716 | | hx509_private_key key, |
717 | | const char *type) |
718 | | { |
719 | | return NULL; |
720 | | } |
721 | | |
722 | | static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 }; |
723 | | const AlgorithmIdentifier _hx509_signature_ecPublicKey = { |
724 | | { 6, rk_UNCONST(ecPublicKey) }, NULL |
725 | | }; |
726 | | |
727 | | static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 }; |
728 | | const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = { |
729 | | { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL |
730 | | }; |
731 | | |
732 | | static const unsigned ecdsa_with_sha384_oid[] ={ 1, 2, 840, 10045, 4, 3, 3 }; |
733 | | const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha384_data = { |
734 | | { 7, rk_UNCONST(ecdsa_with_sha384_oid) }, NULL |
735 | | }; |
736 | | |
737 | | static const unsigned ecdsa_with_sha512_oid[] ={ 1, 2, 840, 10045, 4, 3, 4 }; |
738 | | const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha512_data = { |
739 | | { 7, rk_UNCONST(ecdsa_with_sha512_oid) }, NULL |
740 | | }; |
741 | | |
742 | | static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 }; |
743 | | const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = { |
744 | | { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL |
745 | | }; |
746 | | |
747 | | hx509_private_key_ops ecdsa_private_key_ops = { |
748 | | "EC PRIVATE KEY", |
749 | | ASN1_OID_ID_ECPUBLICKEY, |
750 | | ecdsa_available, |
751 | | ecdsa_private_key2SPKI, |
752 | | ecdsa_private_key_export, |
753 | | ecdsa_private_key_import, |
754 | | ecdsa_generate_private_key, |
755 | | ecdsa_get_internal |
756 | | }; |
757 | | |
758 | | const struct signature_alg ecdsa_with_sha512_alg = { |
759 | | "ecdsa-with-sha512", |
760 | | ASN1_OID_ID_ECDSA_WITH_SHA512, |
761 | | &_hx509_signature_ecdsa_with_sha512_data, |
762 | | ASN1_OID_ID_ECPUBLICKEY, |
763 | | &_hx509_signature_sha512_data, |
764 | | PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| |
765 | | SIG_PUBLIC_SIG|SELF_SIGNED_OK, |
766 | | 0, |
767 | | NULL, |
768 | | ecdsa_verify_signature, |
769 | | ecdsa_create_signature, |
770 | | 64 |
771 | | }; |
772 | | |
773 | | const struct signature_alg ecdsa_with_sha384_alg = { |
774 | | "ecdsa-with-sha384", |
775 | | ASN1_OID_ID_ECDSA_WITH_SHA384, |
776 | | &_hx509_signature_ecdsa_with_sha384_data, |
777 | | ASN1_OID_ID_ECPUBLICKEY, |
778 | | &_hx509_signature_sha384_data, |
779 | | PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| |
780 | | SIG_PUBLIC_SIG|SELF_SIGNED_OK, |
781 | | 0, |
782 | | NULL, |
783 | | ecdsa_verify_signature, |
784 | | ecdsa_create_signature, |
785 | | 48 |
786 | | }; |
787 | | |
788 | | const struct signature_alg ecdsa_with_sha256_alg = { |
789 | | "ecdsa-with-sha256", |
790 | | ASN1_OID_ID_ECDSA_WITH_SHA256, |
791 | | &_hx509_signature_ecdsa_with_sha256_data, |
792 | | ASN1_OID_ID_ECPUBLICKEY, |
793 | | &_hx509_signature_sha256_data, |
794 | | PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| |
795 | | SIG_PUBLIC_SIG|SELF_SIGNED_OK, |
796 | | 0, |
797 | | NULL, |
798 | | ecdsa_verify_signature, |
799 | | ecdsa_create_signature, |
800 | | 32 |
801 | | }; |
802 | | |
803 | | const struct signature_alg ecdsa_with_sha1_alg = { |
804 | | "ecdsa-with-sha1", |
805 | | ASN1_OID_ID_ECDSA_WITH_SHA1, |
806 | | &_hx509_signature_ecdsa_with_sha1_data, |
807 | | ASN1_OID_ID_ECPUBLICKEY, |
808 | | &_hx509_signature_sha1_data, |
809 | | PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| |
810 | | SIG_PUBLIC_SIG|SELF_SIGNED_OK, |
811 | | 0, |
812 | | NULL, |
813 | | ecdsa_verify_signature, |
814 | | ecdsa_create_signature, |
815 | | 20 |
816 | | }; |
817 | | |
818 | | #endif /* HAVE_HCRYPTO_W_OPENSSL */ |
819 | | |
820 | | HX509_LIB_FUNCTION const AlgorithmIdentifier * HX509_LIB_CALL |
821 | | hx509_signature_ecPublicKey(void) |
822 | 0 | { |
823 | | #ifdef HAVE_HCRYPTO_W_OPENSSL |
824 | | return &_hx509_signature_ecPublicKey; |
825 | | #else |
826 | 0 | return NULL; |
827 | 0 | #endif /* HAVE_HCRYPTO_W_OPENSSL */ |
828 | 0 | } |
829 | | |
830 | | HX509_LIB_FUNCTION const AlgorithmIdentifier * HX509_LIB_CALL |
831 | | hx509_signature_ecdsa_with_sha256(void) |
832 | 0 | { |
833 | | #ifdef HAVE_HCRYPTO_W_OPENSSL |
834 | | return &_hx509_signature_ecdsa_with_sha256_data; |
835 | | #else |
836 | | return NULL; |
837 | 0 | #endif /* HAVE_HCRYPTO_W_OPENSSL */ |
838 | 0 | } |