Fix -O3 -Werror=unused-result build in dcache.c (#420)
[heimdal.git] / lib / hx509 / crypto-ec.c
blob4777171cae5228dae38c07d0174ae3df798abee2
1 /*
2 * Copyright (c) 2016 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include <config.h>
36 #ifdef HAVE_HCRYPTO_W_OPENSSL
37 #include <openssl/ec.h>
38 #include <openssl/ecdsa.h>
39 #include <openssl/rsa.h>
40 #include <openssl/bn.h>
41 #include <openssl/objects.h>
42 #define HEIM_NO_CRYPTO_HDRS
43 #endif /* HAVE_HCRYPTO_W_OPENSSL */
45 #include "hx_locl.h"
47 extern const AlgorithmIdentifier _hx509_signature_sha512_data;
48 extern const AlgorithmIdentifier _hx509_signature_sha384_data;
49 extern const AlgorithmIdentifier _hx509_signature_sha256_data;
50 extern const AlgorithmIdentifier _hx509_signature_sha1_data;
52 void
53 _hx509_private_eckey_free(void *eckey)
55 #ifdef HAVE_HCRYPTO_W_OPENSSL
56 EC_KEY_free(eckey);
57 #endif
60 #ifdef HAVE_HCRYPTO_W_OPENSSL
61 static int
62 heim_oid2ecnid(heim_oid *oid)
65 * Now map to openssl OID fun
68 if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP256R1) == 0)
69 return NID_X9_62_prime256v1;
70 #ifdef NID_secp521r1
71 else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP521R1) == 0)
72 return NID_secp521r1;
73 #endif
74 #ifdef NID_secp384r1
75 else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP384R1) == 0)
76 return NID_secp384r1;
77 #endif
78 #ifdef NID_secp160r1
79 else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP160R1) == 0)
80 return NID_secp160r1;
81 #endif
82 #ifdef NID_secp160r2
83 else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP160R2) == 0)
84 return NID_secp160r2;
85 #endif
87 return NID_undef;
90 static int
91 parse_ECParameters(hx509_context context,
92 heim_octet_string *parameters, int *nid)
94 ECParameters ecparam;
95 size_t size;
96 int ret;
98 if (parameters == NULL) {
99 ret = HX509_PARSING_KEY_FAILED;
100 hx509_set_error_string(context, 0, ret,
101 "EC parameters missing");
102 return ret;
105 ret = decode_ECParameters(parameters->data, parameters->length,
106 &ecparam, &size);
107 if (ret) {
108 hx509_set_error_string(context, 0, ret,
109 "Failed to decode EC parameters");
110 return ret;
113 if (ecparam.element != choice_ECParameters_namedCurve) {
114 free_ECParameters(&ecparam);
115 hx509_set_error_string(context, 0, ret,
116 "EC parameters is not a named curve");
117 return HX509_CRYPTO_SIG_INVALID_FORMAT;
120 *nid = heim_oid2ecnid(&ecparam.u.namedCurve);
121 free_ECParameters(&ecparam);
122 if (*nid == NID_undef) {
123 hx509_set_error_string(context, 0, ret,
124 "Failed to find matcing NID for EC curve");
125 return HX509_CRYPTO_SIG_INVALID_FORMAT;
127 return 0;
135 static int
136 ecdsa_verify_signature(hx509_context context,
137 const struct signature_alg *sig_alg,
138 const Certificate *signer,
139 const AlgorithmIdentifier *alg,
140 const heim_octet_string *data,
141 const heim_octet_string *sig)
143 const AlgorithmIdentifier *digest_alg;
144 const SubjectPublicKeyInfo *spi;
145 heim_octet_string digest;
146 int ret;
147 EC_KEY *key = NULL;
148 int groupnid;
149 EC_GROUP *group;
150 const unsigned char *p;
151 long len;
153 digest_alg = sig_alg->digest_alg;
155 ret = _hx509_create_signature(context,
156 NULL,
157 digest_alg,
158 data,
159 NULL,
160 &digest);
161 if (ret)
162 return ret;
164 /* set up EC KEY */
165 spi = &signer->tbsCertificate.subjectPublicKeyInfo;
167 if (der_heim_oid_cmp(&spi->algorithm.algorithm, ASN1_OID_ID_ECPUBLICKEY) != 0)
168 return HX509_CRYPTO_SIG_INVALID_FORMAT;
171 * Find the group id
174 ret = parse_ECParameters(context, spi->algorithm.parameters, &groupnid);
175 if (ret) {
176 der_free_octet_string(&digest);
177 return ret;
181 * Create group, key, parse key
184 key = EC_KEY_new();
185 group = EC_GROUP_new_by_curve_name(groupnid);
186 EC_KEY_set_group(key, group);
187 EC_GROUP_free(group);
189 p = spi->subjectPublicKey.data;
190 len = spi->subjectPublicKey.length / 8;
192 if (o2i_ECPublicKey(&key, &p, len) == NULL) {
193 EC_KEY_free(key);
194 return HX509_CRYPTO_SIG_INVALID_FORMAT;
197 ret = ECDSA_verify(-1, digest.data, digest.length,
198 sig->data, sig->length, key);
199 der_free_octet_string(&digest);
200 EC_KEY_free(key);
201 if (ret != 1) {
202 ret = HX509_CRYPTO_SIG_INVALID_FORMAT;
203 return ret;
206 return 0;
209 static int
210 ecdsa_create_signature(hx509_context context,
211 const struct signature_alg *sig_alg,
212 const hx509_private_key signer,
213 const AlgorithmIdentifier *alg,
214 const heim_octet_string *data,
215 AlgorithmIdentifier *signatureAlgorithm,
216 heim_octet_string *sig)
218 const AlgorithmIdentifier *digest_alg;
219 heim_octet_string indata;
220 const heim_oid *sig_oid;
221 unsigned int siglen;
222 int ret;
224 if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0)
225 _hx509_abort("internal error passing private key to wrong ops");
227 sig_oid = sig_alg->sig_oid;
228 digest_alg = sig_alg->digest_alg;
230 if (signatureAlgorithm) {
231 ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid,
232 "\x05\x00", 2);
233 if (ret) {
234 hx509_clear_error_string(context);
235 return ret;
239 ret = _hx509_create_signature(context,
240 NULL,
241 digest_alg,
242 data,
243 NULL,
244 &indata);
245 if (ret)
246 goto error;
248 sig->length = ECDSA_size(signer->private_key.ecdsa);
249 sig->data = malloc(sig->length);
250 if (sig->data == NULL) {
251 der_free_octet_string(&indata);
252 ret = ENOMEM;
253 hx509_set_error_string(context, 0, ret, "out of memory");
254 goto error;
257 siglen = sig->length;
259 ret = ECDSA_sign(-1, indata.data, indata.length,
260 sig->data, &siglen, signer->private_key.ecdsa);
261 der_free_octet_string(&indata);
262 if (ret != 1) {
263 ret = HX509_CMS_FAILED_CREATE_SIGATURE;
264 hx509_set_error_string(context, 0, ret,
265 "ECDSA sign failed: %d", ret);
266 goto error;
268 if (siglen > sig->length)
269 _hx509_abort("ECDSA signature prelen longer the output len");
271 sig->length = siglen;
273 return 0;
274 error:
275 if (signatureAlgorithm)
276 free_AlgorithmIdentifier(signatureAlgorithm);
277 return ret;
280 static int
281 ecdsa_available(const hx509_private_key signer,
282 const AlgorithmIdentifier *sig_alg)
284 const struct signature_alg *sig;
285 const EC_GROUP *group;
286 BN_CTX *bnctx = NULL;
287 BIGNUM *order = NULL;
288 int ret = 0;
290 if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0)
291 _hx509_abort("internal error passing private key to wrong ops");
293 sig = _hx509_find_sig_alg(&sig_alg->algorithm);
295 if (sig == NULL || sig->digest_size == 0)
296 return 0;
298 group = EC_KEY_get0_group(signer->private_key.ecdsa);
299 if (group == NULL)
300 return 0;
302 bnctx = BN_CTX_new();
303 order = BN_new();
304 if (order == NULL)
305 goto err;
307 if (EC_GROUP_get_order(group, order, bnctx) != 1)
308 goto err;
310 #if 0
311 /* If anything, require a digest at least as wide as the EC key size */
312 if (BN_num_bytes(order) > sig->digest_size)
313 #endif
314 ret = 1;
315 err:
316 if (bnctx)
317 BN_CTX_free(bnctx);
318 if (order)
319 BN_clear_free(order);
321 return ret;
324 static int
325 ecdsa_private_key2SPKI(hx509_context context,
326 hx509_private_key private_key,
327 SubjectPublicKeyInfo *spki)
329 memset(spki, 0, sizeof(*spki));
330 return ENOMEM;
333 static int
334 ecdsa_private_key_export(hx509_context context,
335 const hx509_private_key key,
336 hx509_key_format_t format,
337 heim_octet_string *data)
339 return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED;
342 static int
343 ecdsa_private_key_import(hx509_context context,
344 const AlgorithmIdentifier *keyai,
345 const void *data,
346 size_t len,
347 hx509_key_format_t format,
348 hx509_private_key private_key)
350 const unsigned char *p = data;
351 EC_KEY **pkey = NULL;
352 EC_KEY *key;
354 if (keyai->parameters) {
355 EC_GROUP *group;
356 int groupnid;
357 int ret;
359 ret = parse_ECParameters(context, keyai->parameters, &groupnid);
360 if (ret)
361 return ret;
363 key = EC_KEY_new();
364 if (key == NULL)
365 return ENOMEM;
367 group = EC_GROUP_new_by_curve_name(groupnid);
368 if (group == NULL) {
369 EC_KEY_free(key);
370 return ENOMEM;
372 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
373 if (EC_KEY_set_group(key, group) == 0) {
374 EC_KEY_free(key);
375 EC_GROUP_free(group);
376 return ENOMEM;
378 EC_GROUP_free(group);
379 pkey = &key;
382 switch (format) {
383 case HX509_KEY_FORMAT_DER:
385 private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len);
386 if (private_key->private_key.ecdsa == NULL) {
387 hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
388 "Failed to parse EC private key");
389 return HX509_PARSING_KEY_FAILED;
391 private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256;
392 break;
394 default:
395 return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED;
398 return 0;
401 static int
402 ecdsa_generate_private_key(hx509_context context,
403 struct hx509_generate_private_context *ctx,
404 hx509_private_key private_key)
406 return ENOMEM;
409 static BIGNUM *
410 ecdsa_get_internal(hx509_context context,
411 hx509_private_key key,
412 const char *type)
414 return NULL;
417 static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 };
418 const AlgorithmIdentifier _hx509_signature_ecPublicKey = {
419 { 6, rk_UNCONST(ecPublicKey) }, NULL
422 static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 };
423 const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = {
424 { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL
427 static const unsigned ecdsa_with_sha384_oid[] ={ 1, 2, 840, 10045, 4, 3, 3 };
428 const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha384_data = {
429 { 7, rk_UNCONST(ecdsa_with_sha384_oid) }, NULL
432 static const unsigned ecdsa_with_sha512_oid[] ={ 1, 2, 840, 10045, 4, 3, 4 };
433 const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha512_data = {
434 { 7, rk_UNCONST(ecdsa_with_sha512_oid) }, NULL
437 static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 };
438 const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = {
439 { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL
442 hx509_private_key_ops ecdsa_private_key_ops = {
443 "EC PRIVATE KEY",
444 ASN1_OID_ID_ECPUBLICKEY,
445 ecdsa_available,
446 ecdsa_private_key2SPKI,
447 ecdsa_private_key_export,
448 ecdsa_private_key_import,
449 ecdsa_generate_private_key,
450 ecdsa_get_internal
453 const struct signature_alg ecdsa_with_sha512_alg = {
454 "ecdsa-with-sha512",
455 ASN1_OID_ID_ECDSA_WITH_SHA512,
456 &_hx509_signature_ecdsa_with_sha512_data,
457 ASN1_OID_ID_ECPUBLICKEY,
458 &_hx509_signature_sha512_data,
459 PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|
460 SIG_PUBLIC_SIG|SELF_SIGNED_OK,
462 NULL,
463 ecdsa_verify_signature,
464 ecdsa_create_signature,
468 const struct signature_alg ecdsa_with_sha384_alg = {
469 "ecdsa-with-sha384",
470 ASN1_OID_ID_ECDSA_WITH_SHA384,
471 &_hx509_signature_ecdsa_with_sha384_data,
472 ASN1_OID_ID_ECPUBLICKEY,
473 &_hx509_signature_sha384_data,
474 PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|
475 SIG_PUBLIC_SIG|SELF_SIGNED_OK,
477 NULL,
478 ecdsa_verify_signature,
479 ecdsa_create_signature,
483 const struct signature_alg ecdsa_with_sha256_alg = {
484 "ecdsa-with-sha256",
485 ASN1_OID_ID_ECDSA_WITH_SHA256,
486 &_hx509_signature_ecdsa_with_sha256_data,
487 ASN1_OID_ID_ECPUBLICKEY,
488 &_hx509_signature_sha256_data,
489 PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|
490 SIG_PUBLIC_SIG|SELF_SIGNED_OK,
492 NULL,
493 ecdsa_verify_signature,
494 ecdsa_create_signature,
498 const struct signature_alg ecdsa_with_sha1_alg = {
499 "ecdsa-with-sha1",
500 ASN1_OID_ID_ECDSA_WITH_SHA1,
501 &_hx509_signature_ecdsa_with_sha1_data,
502 ASN1_OID_ID_ECPUBLICKEY,
503 &_hx509_signature_sha1_data,
504 PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|
505 SIG_PUBLIC_SIG|SELF_SIGNED_OK,
507 NULL,
508 ecdsa_verify_signature,
509 ecdsa_create_signature,
513 #endif /* HAVE_HCRYPTO_W_OPENSSL */
515 const AlgorithmIdentifier *
516 hx509_signature_ecPublicKey(void)
518 #ifdef HAVE_HCRYPTO_W_OPENSSL
519 return &_hx509_signature_ecPublicKey;
520 #else
521 return NULL;
522 #endif /* HAVE_HCRYPTO_W_OPENSSL */
525 const AlgorithmIdentifier *
526 hx509_signature_ecdsa_with_sha256(void)
528 #ifdef HAVE_HCRYPTO_W_OPENSSL
529 return &_hx509_signature_ecdsa_with_sha256_data;
530 #else
531 return NULL;
532 #endif /* HAVE_HCRYPTO_W_OPENSSL */