blob: 50d7df8c7931d4c959e6843af8b0270fbedc485c [file] [log] [blame]
/*
* 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, &params);
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;
}