| /* |
| * Handle the RSA specific openssl crypto functions |
| * |
| * Copyright (C) 2019 James.Bottomley@HansenPartnership.com |
| * |
| * SPDX-License-Identifier: LGPL-2.1-only |
| */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <openssl/evp.h> |
| #include <openssl/ec.h> |
| #include <openssl/ecdsa.h> |
| #include <openssl/buffer.h> |
| #include <openssl/err.h> |
| |
| #include "openssl-pkcs11.h" |
| #include "crypto.h" |
| |
| #if OPENSSL_VERSION_NUMBER < 0x10100000 |
| static EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) |
| { |
| return pkey->pkey.ec; |
| } |
| static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, |
| const BIGNUM **ps) |
| { |
| if (pr != NULL) |
| *pr = sig->r; |
| if (ps != NULL) |
| *ps = sig->s; |
| } |
| static int EC_GROUP_order_bits(const EC_GROUP *group) |
| { |
| BIGNUM *order = BN_new(); |
| int bits; |
| |
| EC_GROUP_get_order(group, order, NULL); |
| bits = BN_num_bits(order); |
| BN_free(order); |
| |
| return bits; |
| } |
| |
| #endif |
| |
| void |
| crypto_ec_populate(int sec_num, EVP_PKEY *pkey) |
| { |
| EC_KEY *eck = EVP_PKEY_get0_EC_KEY(pkey); |
| ASN1_OCTET_STRING *asn1pub = ASN1_OCTET_STRING_new(); |
| EVP_MD_CTX *ctx; |
| unsigned char *pubpoint = NULL, *params = NULL; |
| int pubpoint_len, params_len; |
| |
| pubpoint_len = i2o_ECPublicKey(eck, &pubpoint); |
| ASN1_STRING_set0(asn1pub, pubpoint, pubpoint_len); |
| /* pubpoint has been consumed by ASN1_STRING_set0, so NULL the |
| * pointer to allow reallocation */ |
| pubpoint = NULL; |
| pubpoint_len = i2d_ASN1_OCTET_STRING(asn1pub, &pubpoint); |
| params_len = i2d_ECParameters(eck, ¶ms); |
| |
| ctx = EVP_MD_CTX_create(); |
| EVP_DigestInit(ctx, EVP_sha256()); |
| |
| EVP_DigestUpdate(ctx, pubpoint, pubpoint_len); |
| cache_add_by_secnum(sec_num, "CKA_EC_POINT", (const char *)pubpoint, |
| pubpoint_len); |
| EVP_DigestUpdate(ctx, params, params_len); |
| cache_add_by_secnum(sec_num, "CKA_EC_PARAMS", (const char *)params, |
| params_len); |
| crypto_add_serial(sec_num, ctx); |
| |
| cache_add_by_secnum(sec_num, "CKA_KEY_TYPE", |
| (const char *)CKK_EC, CACHE_INT); |
| cache_add_by_secnum(sec_num, "CKA_DERIVE", |
| (const char *)BOOL_FOR_PRIVATE, CACHE_INT); |
| } |
| |
| static CK_MECHANISM_TYPE mechanism_types[] = { |
| CKM_ECDSA, |
| CKM_ECDH1_DERIVE, |
| }; |
| |
| void crypto_ec_fill_mechanism_list(int sec_num, unsigned long *mechs, |
| unsigned long *count) |
| { |
| *count = ARRAY_SIZE(mechanism_types); |
| if (mechs) |
| memcpy(mechs, mechanism_types, sizeof(mechanism_types)); |
| } |
| |
| int crypto_ec_check_mechanism(int sec_num, CK_MECHANISM_TYPE mech, |
| CK_MECHANISM_INFO_PTR info) |
| { |
| int i, found = 0; |
| |
| for (i = 0; i < ARRAY_SIZE(mechanism_types); i++) |
| if (mech == mechanism_types[i]) |
| found = 1; |
| |
| if (!found) |
| return 0; |
| |
| info->ulMinKeySize = 128; |
| info->ulMaxKeySize = 512; |
| info->flags = CKF_HW|CKF_SIGN|CKF_DERIVE; |
| |
| return 1; |
| } |
| |
| int crypto_ec_sign(EVP_PKEY_CTX *ctx, void *data, unsigned long data_len, |
| void *sig, unsigned long *sig_len) |
| { |
| EC_KEY *eck = EVP_PKEY_get0_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx)); |
| const EC_GROUP *g = EC_KEY_get0_group(eck); |
| int size = (EC_GROUP_order_bits(g) + 7)/8; |
| ECDSA_SIG *ecdsa_sig; |
| const BIGNUM *r, *s; |
| int ret = -1; |
| |
| if (!sig) { |
| *sig_len = size * 2; |
| return 0; |
| } |
| ecdsa_sig = ECDSA_do_sign(data, data_len, eck); |
| if (!ecdsa_sig) { |
| ERR_print_errors_fp(stderr); |
| goto out; |
| } |
| ECDSA_SIG_get0(ecdsa_sig, &r, &s); |
| BN_bn2bin(r, sig); |
| BN_bn2bin(s, sig + size); |
| ret = 0; |
| out: |
| EVP_PKEY_CTX_free(ctx); |
| |
| return ret; |
| } |