mirror of
https://github.com/chris2511/xca.git
synced 2026-09-12 19:51:05 +05:00
WIP: Extract ENGINE / PROVIDER functionality
This commit is contained in:
parent
7dcc2b6194
commit
e062f620f4
@ -39,9 +39,8 @@ XcaProgress.h XcaWarningCore.cpp XcaWarningCore.h
|
||||
PwDialogCore.cpp PwDialogCore.h digest.h
|
||||
digest.cpp pki_export.cpp debug_info.h
|
||||
func_base.cpp func_base.h debug_info.cpp
|
||||
cmdline.cpp
|
||||
cmdline.cpp pkcs11_provider.cpp
|
||||
)
|
||||
|
||||
macro(ExpandSources target)
|
||||
list(TRANSFORM ${target}_sources PREPEND ${PROJECT_SOURCE_DIR}/lib/)
|
||||
list(APPEND ${target} ${PROJECT_BINARY_DIR}/local.h)
|
||||
|
||||
377
lib/pkcs11.cpp
377
lib/pkcs11.cpp
@ -649,376 +649,39 @@ int pkcs11::encrypt(int flen, const unsigned char *from,
|
||||
return size;
|
||||
}
|
||||
|
||||
static int rsa_privdata_free(RSA *rsa)
|
||||
{
|
||||
pkcs11 *priv = (pkcs11*)RSA_get_app_data(rsa);
|
||||
delete priv;
|
||||
return 0;
|
||||
}
|
||||
#include <openssl/provider.h>
|
||||
#include <openssl/core_names.h>
|
||||
|
||||
static int rsa_encrypt(int flen, const unsigned char *from,
|
||||
unsigned char *to, RSA * rsa, int padding)
|
||||
{
|
||||
pkcs11 *priv = (pkcs11*)RSA_get_app_data(rsa);
|
||||
const BIGNUM *n = NULL;
|
||||
|
||||
if (padding != RSA_PKCS1_PADDING) {
|
||||
return -1;
|
||||
}
|
||||
RSA_get0_key(rsa, &n, NULL, NULL);
|
||||
return priv->encrypt(flen, from, to, BN_num_bytes(n), CKM_RSA_PKCS);
|
||||
}
|
||||
|
||||
static int rsa_decrypt(int flen, const unsigned char *from,
|
||||
unsigned char *to, RSA * rsa, int padding)
|
||||
{
|
||||
pkcs11 *priv = (pkcs11*)RSA_get_app_data(rsa);
|
||||
|
||||
if (padding != RSA_PKCS1_PADDING) {
|
||||
return -1;
|
||||
}
|
||||
return priv->decrypt(flen, from, to, flen, CKM_RSA_PKCS);
|
||||
}
|
||||
|
||||
static int dsa_privdata_free(DSA *dsa)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11*)DSA_get_ex_data(dsa, 0);
|
||||
delete p11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DSA_SIG *dsa_sign(const unsigned char *dgst, int dlen, DSA *dsa)
|
||||
{
|
||||
int len, rs_len;
|
||||
unsigned char rs_buf[128];
|
||||
pkcs11 *p11 = (pkcs11*)DSA_get_ex_data(dsa, 0);
|
||||
DSA_SIG *dsa_sig = DSA_SIG_new();
|
||||
BIGNUM *r, *s;
|
||||
|
||||
// siglen is unsigned and can't cope with -1 as return value
|
||||
len = p11->encrypt(dlen, dgst, rs_buf, sizeof rs_buf, CKM_DSA);
|
||||
if (len & 0x01) // Must be even
|
||||
goto out;
|
||||
|
||||
rs_len = len / 2;
|
||||
r = BN_bin2bn(rs_buf, rs_len, NULL);
|
||||
s = BN_bin2bn(rs_buf + rs_len, rs_len, NULL);
|
||||
DSA_SIG_set0(dsa_sig, r, s);
|
||||
if (r && s)
|
||||
return dsa_sig;
|
||||
out:
|
||||
DSA_SIG_free(dsa_sig);
|
||||
ign_openssl_error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
|
||||
static void ec_privdata_free(EC_KEY *ec)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11*)EC_KEY_get_ex_data(ec, 0);
|
||||
delete p11;
|
||||
}
|
||||
|
||||
static int ec_sign_setup(EC_KEY *ec, BN_CTX *ctx, BIGNUM **kinvp, BIGNUM **rp)
|
||||
{
|
||||
(void) ec;
|
||||
(void) ctx;
|
||||
(void) kinvp;
|
||||
(void) rp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ECDSA_SIG *ec_do_sign(const unsigned char *dgst, int dgst_len,
|
||||
const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *ec)
|
||||
{
|
||||
int len, rs_len;
|
||||
unsigned char rs_buf[512];
|
||||
ECDSA_SIG *ec_sig = ECDSA_SIG_new();
|
||||
pkcs11 *p11 = (pkcs11 *) EC_KEY_get_ex_data(ec, 0);
|
||||
BIGNUM *r, *s;
|
||||
|
||||
(void) in_kinv;
|
||||
(void) in_r;
|
||||
|
||||
// siglen is unsigned and can' cope with -1 as return value
|
||||
len = p11->encrypt(dgst_len, dgst, rs_buf, sizeof rs_buf, CKM_ECDSA);
|
||||
if (len & 0x01) // Must be even
|
||||
goto out;
|
||||
/* The buffer contains r and s concatenated
|
||||
* Both of equal size
|
||||
* pkcs-11v2-20.pdf chapter 12.13.1, page 232
|
||||
*/
|
||||
rs_len = len / 2;
|
||||
r = BN_bin2bn(rs_buf, rs_len, NULL);
|
||||
s = BN_bin2bn(rs_buf + rs_len, rs_len, NULL);
|
||||
ECDSA_SIG_set0(ec_sig, r, s);
|
||||
if (r && s)
|
||||
return ec_sig;
|
||||
|
||||
out:
|
||||
ECDSA_SIG_free(ec_sig);
|
||||
ign_openssl_error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ec_sign(int type, const unsigned char *dgst, int dlen,
|
||||
unsigned char *sig, unsigned int *siglen,
|
||||
const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec)
|
||||
{
|
||||
ECDSA_SIG *ec_sig;
|
||||
int ret = 0;
|
||||
int len;
|
||||
|
||||
(void) type;
|
||||
ec_sig = ec_do_sign(dgst, dlen, kinv, r, ec);
|
||||
if (!ec_sig)
|
||||
return 0;
|
||||
|
||||
len = i2d_ECDSA_SIG(ec_sig, &sig);
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
*siglen = len;
|
||||
ret = 1;
|
||||
out:
|
||||
ECDSA_SIG_free(ec_sig);
|
||||
ign_openssl_error();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static EC_KEY_METHOD *setup_ec_key_meth()
|
||||
{
|
||||
EC_KEY_METHOD *ec_key_meth;
|
||||
int (*ec_init_proc)(EC_KEY *key);
|
||||
void (*ec_finish_proc)(EC_KEY *key);
|
||||
int (*ec_copy_proc)(EC_KEY *dest, const EC_KEY *src);
|
||||
int (*ec_set_group_proc)(EC_KEY *key, const EC_GROUP *grp);
|
||||
int (*ec_set_private_proc)(EC_KEY *key, const BIGNUM *priv_key);
|
||||
int (*ec_set_public_proc)(EC_KEY *key, const EC_POINT *pub_key);
|
||||
|
||||
ec_key_meth = EC_KEY_METHOD_new(EC_KEY_get_default_method());
|
||||
EC_KEY_METHOD_set_sign(ec_key_meth, ec_sign, ec_sign_setup, ec_do_sign);
|
||||
EC_KEY_METHOD_get_init(ec_key_meth, &ec_init_proc, &ec_finish_proc,
|
||||
&ec_copy_proc, &ec_set_group_proc,
|
||||
&ec_set_private_proc, &ec_set_public_proc);
|
||||
EC_KEY_METHOD_set_init(ec_key_meth, ec_init_proc, ec_privdata_free,
|
||||
ec_copy_proc, ec_set_group_proc,
|
||||
ec_set_private_proc, ec_set_public_proc);
|
||||
return ec_key_meth;
|
||||
}
|
||||
|
||||
|
||||
#if defined(EVP_PKEY_ED25519) && OPENSSL_VERSION_NUMBER < 0x40000000L
|
||||
|
||||
#include <openssl/engine.h>
|
||||
|
||||
static EVP_PKEY_METHOD *p11_eddsa_method;
|
||||
|
||||
// Shared between libressl and openssl
|
||||
static int eng_idx = -1;
|
||||
static int eng_finish(ENGINE *e)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11 *)ENGINE_get_ex_data(e, eng_idx);
|
||||
delete p11;
|
||||
ENGINE_set_ex_data(e, eng_idx, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
static int eng_pmeth_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
|
||||
#else
|
||||
static int eng_pmeth_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
|
||||
#endif
|
||||
{
|
||||
void *p = EVP_PKEY_CTX_get_app_data((EVP_PKEY_CTX *)src);
|
||||
EVP_PKEY_CTX_set_app_data(dst, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int eddsa_eng_meths(ENGINE *e, EVP_PKEY_METHOD **m, const int **nids, int nid)
|
||||
{
|
||||
static const int my_nids[] = {EVP_PKEY_ED25519 };
|
||||
(void)e;
|
||||
if (m) {
|
||||
switch (nid) {
|
||||
case EVP_PKEY_ED25519:
|
||||
*m = p11_eddsa_method;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (nids) {
|
||||
*nids = my_nids;
|
||||
return ARRAY_SIZE(my_nids);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int eng_pmeth_sign_eddsa(EVP_MD_CTX *ctx,
|
||||
unsigned char *sig, size_t *siglen,
|
||||
const unsigned char *tbs, size_t tbslen)
|
||||
{
|
||||
int len, ret = -1;
|
||||
unsigned char rs_buf[64];
|
||||
EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
|
||||
pkcs11 *p11 = (pkcs11 *)ENGINE_get_ex_data(EVP_PKEY_get0_engine(pkey), eng_idx);
|
||||
*siglen = EVP_PKEY_size(pkey);
|
||||
if (sig == NULL) {
|
||||
// caller needs only size
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// siglen is unsigned and can' cope with -1 as return value
|
||||
len = p11->encrypt(tbslen, tbs, rs_buf, sizeof rs_buf, CKM_EDDSA);
|
||||
if ((len & 0x01) || (*siglen != (size_t)len)) // Must be even
|
||||
goto out;
|
||||
memcpy(sig, rs_buf, len);
|
||||
*siglen = len;
|
||||
ret = 1;
|
||||
out:
|
||||
ign_openssl_error();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eng_pmeth_ctrl_eddsa(EVP_PKEY_CTX *, int type, int p1, void *p2)
|
||||
{
|
||||
(void)p1;
|
||||
switch (type) {
|
||||
case EVP_PKEY_CTRL_MD:
|
||||
if (p2 == NULL || (const EVP_MD *)p2 == EVP_md_null())
|
||||
return 1;
|
||||
ECerr(EC_F_PKEY_ECD_CTRL, EC_R_INVALID_DIGEST_TYPE);
|
||||
return 0;
|
||||
}
|
||||
qWarning() << "EC Don't call me" << type;
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
// Forward declaration from pkcs11_provider.cpp
|
||||
extern "C" void *pkcs11_create_sig_ctx(void *provctx, pkcs11 *p11,
|
||||
CK_OBJECT_HANDLE obj, EVP_PKEY *pubkey);
|
||||
|
||||
EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj)
|
||||
{
|
||||
static RSA_METHOD *rsa_meth = NULL;
|
||||
static DSA_METHOD *dsa_meth = NULL;
|
||||
#ifndef OPENSSL_NO_EC
|
||||
static EC_KEY_METHOD *ec_key_meth = NULL;
|
||||
EC_KEY *ec;
|
||||
#if defined(EVP_PKEY_ED25519) && OPENSSL_VERSION_NUMBER < 0x40000000L
|
||||
static ENGINE *e = NULL;
|
||||
|
||||
if (!e) {
|
||||
e = ENGINE_new();
|
||||
Q_CHECK_PTR(e);
|
||||
|
||||
ENGINE_set_pkey_meths(e, eddsa_eng_meths);
|
||||
ENGINE_set_finish_function(e, eng_finish);
|
||||
if (eng_idx == -1)
|
||||
eng_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
|
||||
ENGINE_set_ex_data(e, eng_idx, NULL);
|
||||
// Why is engine attached to pubkey? I'm commenting it, as I do
|
||||
// not want it to be attached to RSA/DSA/EC
|
||||
//CRYPTO_add(&pub->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
||||
//pub->engine = e;
|
||||
|
||||
if (!p11_eddsa_method) {
|
||||
p11_eddsa_method = EVP_PKEY_meth_new(EVP_PKEY_ED25519,
|
||||
EVP_PKEY_FLAG_SIGCTX_CUSTOM);
|
||||
EVP_PKEY_meth_set_digestsign(p11_eddsa_method,
|
||||
eng_pmeth_sign_eddsa);
|
||||
EVP_PKEY_meth_set_ctrl(p11_eddsa_method,
|
||||
eng_pmeth_ctrl_eddsa, NULL);
|
||||
EVP_PKEY_meth_set_copy(p11_eddsa_method, eng_pmeth_copy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
EVP_PKEY *evp = NULL;
|
||||
int keytype;
|
||||
|
||||
p11slot.isValid();
|
||||
|
||||
keytype = EVP_PKEY_id(pub);
|
||||
|
||||
p11obj = obj;
|
||||
|
||||
int keytype = EVP_PKEY_id(pub);
|
||||
|
||||
// For now, we create a wrapper that will use the old ENGINE-style approach
|
||||
// A full provider-based implementation would require more extensive changes
|
||||
// to how OpenSSL 3.0 handles custom keys
|
||||
|
||||
switch (EVP_PKEY_type(keytype)) {
|
||||
case EVP_PKEY_RSA:
|
||||
rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pub));
|
||||
openssl_error();
|
||||
if (!rsa_meth) {
|
||||
rsa_meth = RSA_meth_dup(RSA_get_default_method());
|
||||
RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt);
|
||||
RSA_meth_set_priv_dec(rsa_meth, rsa_decrypt);
|
||||
RSA_meth_set_finish(rsa_meth, rsa_privdata_free);
|
||||
}
|
||||
p11obj = obj;
|
||||
RSA_set_method(rsa, rsa_meth);
|
||||
RSA_set_app_data(rsa, this);
|
||||
evp = EVP_PKEY_new();
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_RSA(evp, rsa);
|
||||
break;
|
||||
case EVP_PKEY_DSA:
|
||||
dsa = DSAparams_dup(EVP_PKEY_get0_DSA(pub));
|
||||
openssl_error();
|
||||
if (!dsa_meth) {
|
||||
dsa_meth = DSA_meth_dup(DSA_get_default_method());
|
||||
DSA_meth_set_sign(dsa_meth, dsa_sign);
|
||||
DSA_meth_set_finish(dsa_meth, dsa_privdata_free);
|
||||
}
|
||||
p11obj = obj;
|
||||
DSA_set_method(dsa, dsa_meth);
|
||||
DSA_set_ex_data(dsa, 0, this);
|
||||
evp = EVP_PKEY_new();
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_DSA(evp, dsa);
|
||||
break;
|
||||
#ifndef OPENSSL_NO_EC
|
||||
case EVP_PKEY_EC:
|
||||
ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pub));
|
||||
openssl_error();
|
||||
if (!ec_key_meth) {
|
||||
ec_key_meth = setup_ec_key_meth();
|
||||
}
|
||||
p11obj = obj;
|
||||
EC_KEY_set_method(ec, ec_key_meth);
|
||||
EC_KEY_set_ex_data(ec, 0, this);
|
||||
evp = EVP_PKEY_new();
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_EC_KEY(evp, ec);
|
||||
break;
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
case EVP_PKEY_ED25519:
|
||||
size_t len;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x40000000L
|
||||
if (ENGINE_get_ex_data(e, eng_idx))
|
||||
qWarning() << "We forgot to free the previous Card key.";
|
||||
ENGINE_set_ex_data(e, eng_idx, this);
|
||||
p11obj = obj;
|
||||
EVP_PKEY_get_raw_public_key(pub, NULL, &len);
|
||||
unsigned char *pubkey = (unsigned char *)OPENSSL_malloc(len);
|
||||
Q_CHECK_PTR(pubkey);
|
||||
EVP_PKEY_get_raw_public_key(pub, pubkey, &len);
|
||||
evp = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, e, pubkey, len);
|
||||
openssl_error();
|
||||
OPENSSL_free(pubkey);
|
||||
//EVP_PKEY_set1_engine(evp, e);
|
||||
#else
|
||||
p11obj = obj;
|
||||
EVP_PKEY_get_raw_public_key(pub, NULL, &len);
|
||||
unsigned char *pubkey = (unsigned char *)OPENSSL_malloc(len);
|
||||
Q_CHECK_PTR(pubkey);
|
||||
EVP_PKEY_get_raw_public_key(pub, pubkey, &len);
|
||||
evp = EVP_PKEY_new_raw_public_key_ex(OSSL_LIB_CTX_get0_global_default(),
|
||||
"ED25519", NULL, pubkey, len);
|
||||
openssl_error();
|
||||
OPENSSL_free(pubkey);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
// Return a reference to the public key
|
||||
// The actual signing will be handled by the sig_ctx in the provider
|
||||
// when operations are performed
|
||||
EVP_PKEY_up_ref(pub);
|
||||
return pub;
|
||||
}
|
||||
return evp;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
579
lib/pkcs11_provider.cpp
Normal file
579
lib/pkcs11_provider.cpp
Normal file
@ -0,0 +1,579 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "pkcs11.h"
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/params.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
// Signature context for RSA operations
|
||||
class sig_ctx
|
||||
{
|
||||
public:
|
||||
pkcs11 *p11;
|
||||
CK_OBJECT_HANDLE obj;
|
||||
EVP_PKEY *pubkey;
|
||||
|
||||
sig_ctx(pkcs11 *_p11, CK_OBJECT_HANDLE _obj, EVP_PKEY *_pubkey)
|
||||
: p11(_p11), obj(_obj), pubkey(_pubkey)
|
||||
{
|
||||
TRACE
|
||||
if (pubkey)
|
||||
EVP_PKEY_up_ref(pubkey);
|
||||
}
|
||||
|
||||
~sig_ctx()
|
||||
{
|
||||
TRACE
|
||||
if (pubkey)
|
||||
EVP_PKEY_free(pubkey);
|
||||
}
|
||||
};
|
||||
|
||||
static void *p11prov_rsasig_newctx(void *provctx, const char *properties)
|
||||
{
|
||||
TRACE
|
||||
(void)properties;
|
||||
(void)provctx;
|
||||
// Context will be created when key is loaded
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void p11prov_rsasig_freectx(void *ctx)
|
||||
{
|
||||
TRACE
|
||||
if (ctx)
|
||||
delete (sig_ctx *)ctx;
|
||||
}
|
||||
|
||||
static int p11prov_rsasig_sign(void *ctx, unsigned char *sig, size_t *siglen,
|
||||
size_t sigsize, const unsigned char *tbs, size_t tbslen)
|
||||
{
|
||||
TRACE
|
||||
sig_ctx *sctx = (sig_ctx *)ctx;
|
||||
if (!sctx || !sctx->p11)
|
||||
return 0;
|
||||
|
||||
size_t key_size = EVP_PKEY_bits(sctx->pubkey) / 8;
|
||||
if (!sig) {
|
||||
// Caller wants to know signature size
|
||||
*siglen = key_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sigsize < key_size)
|
||||
return 0;
|
||||
|
||||
// Use pkcs11::encrypt for signing
|
||||
int ret = sctx->p11->encrypt(tbslen, tbs, sig, sigsize, CKM_RSA_PKCS);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
*siglen = ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int p11prov_rsasig_digest_sign_init(void *ctx, const char *mdname,
|
||||
void *provkey, const OSSL_PARAM params[])
|
||||
{
|
||||
TRACE
|
||||
(void)ctx;
|
||||
(void)mdname;
|
||||
(void)provkey;
|
||||
(void)params;
|
||||
// Not implementing digest operations yet
|
||||
return 0;
|
||||
}
|
||||
|
||||
const OSSL_DISPATCH pkcs11_rsa_functions[] = {
|
||||
{ OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))p11prov_rsasig_newctx },
|
||||
{ OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))p11prov_rsasig_freectx },
|
||||
{ OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))p11prov_rsasig_sign },
|
||||
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))p11prov_rsasig_digest_sign_init },
|
||||
{ 0, nullptr}
|
||||
};
|
||||
|
||||
static const OSSL_ALGORITHM pkcs11_ciphers[] = {
|
||||
{ "RSA:rsaEncryption:1.2.840.113549.1.1.1", "",
|
||||
pkcs11_rsa_functions, "Description" },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
class provider_ctx
|
||||
{
|
||||
public:
|
||||
const OSSL_CORE_HANDLE *core;
|
||||
const OSSL_DISPATCH *dispatch;
|
||||
pkcs11 *p11;
|
||||
CK_OBJECT_HANDLE obj;
|
||||
const OSSL_ALGORITHM *op_signature;
|
||||
|
||||
provider_ctx(const OSSL_CORE_HANDLE *core, const OSSL_DISPATCH *in)
|
||||
: core(core), dispatch(in), p11(nullptr), obj(CK_INVALID_HANDLE)
|
||||
{
|
||||
TRACE
|
||||
op_signature = pkcs11_ciphers;
|
||||
}
|
||||
|
||||
~provider_ctx()
|
||||
{
|
||||
TRACE
|
||||
}
|
||||
|
||||
void setKey(pkcs11 *_p11, CK_OBJECT_HANDLE _obj)
|
||||
{
|
||||
p11 = _p11;
|
||||
obj = _obj;
|
||||
}
|
||||
};
|
||||
|
||||
/* The function that returns the appropriate algorithm table per operation */
|
||||
static const OSSL_ALGORITHM *pkcs11_prov_operation(void *ctx,
|
||||
int operation_id, int *no_cache)
|
||||
{
|
||||
TRACE
|
||||
|
||||
*no_cache = 0;
|
||||
switch (operation_id) {
|
||||
case OSSL_OP_SIGNATURE:
|
||||
return ((provider_ctx *)ctx)->op_signature;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The function that tears down this provider */
|
||||
static void pkcs11_prov_teardown(void *ctx)
|
||||
{
|
||||
TRACE
|
||||
delete (provider_ctx *)ctx;
|
||||
}
|
||||
|
||||
/* The base dispatch table */
|
||||
static const OSSL_DISPATCH provider_functions[] = {
|
||||
{ OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))pkcs11_prov_teardown },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))pkcs11_prov_operation },
|
||||
#if 0
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_OPERATION_NAME, (void (*)(void))pkcs11_prov_op_name },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_OPERATION_PROPERTIES,
|
||||
(void (*)(void))pkcs11_prov_op_properties },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY, (void (*)(void))pkcs11_prov_property },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_NAME, (void (*)(void))pkcs11_prov_prop_name },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_DESCRIPTION,
|
||||
(void (*)(void))pkcs11_prov_prop_description },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_TYPE,
|
||||
(void (*)(void))pkcs11_prov_prop_value_type },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_descriptions },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_descriptions },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_descriptions },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_descriptions },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_descriptions },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_descriptions },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_CONSTRAINTS,
|
||||
(void (*)(void))pkcs11_prov_prop_value_constraints },
|
||||
{ OSSL_FUNC_PROVIDER_QUERY_PROPERTY_VALUE_DESCRIPTIONS,
|
||||
{ OSSL_FUNC_PROVIDER_GET_REASON_STRINGS,
|
||||
(void (*)(void))vigenere_prov_get_reason_strings },
|
||||
{ OSSL_FUNC_PROVIDER_GET_PARAMS,
|
||||
(void (*)(void))vigenere_prov_get_params },
|
||||
{ 0, NULL }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
int OSSL_provider_init(const OSSL_CORE_HANDLE *core,
|
||||
const OSSL_DISPATCH *in,
|
||||
const OSSL_DISPATCH **out,
|
||||
void **p11ctx)
|
||||
{
|
||||
TRACE
|
||||
*p11ctx = new provider_ctx(core, in);
|
||||
*out = provider_functions;
|
||||
TRACE
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Helper function to create a signature context with pkcs11
|
||||
extern "C" void *pkcs11_create_sig_ctx(void *provctx, pkcs11 *p11,
|
||||
CK_OBJECT_HANDLE obj, EVP_PKEY *pubkey)
|
||||
{
|
||||
TRACE
|
||||
(void)provctx;
|
||||
return new sig_ctx(p11, obj, pubkey);
|
||||
}
|
||||
|
||||
# if 0
|
||||
#if not defined OPENSSL_NO_EC and defined EVP_PKEY_ED25519
|
||||
// Shared between libressl and openssl
|
||||
static int eng_idx = -1;
|
||||
static int eng_finish(ENGINE *e)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11 *)ENGINE_get_ex_data(e, eng_idx);
|
||||
delete p11;
|
||||
ENGINE_set_ex_data(e, eng_idx, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int eng_pmeth_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
|
||||
{
|
||||
void *p = EVP_PKEY_CTX_get_app_data((EVP_PKEY_CTX *)src);
|
||||
EVP_PKEY_CTX_set_app_data(dst, p);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rsa_privdata_free(RSA *rsa)
|
||||
{
|
||||
pkcs11 *priv = (pkcs11*)RSA_get_app_data(rsa);
|
||||
delete priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsa_encrypt(int flen, const unsigned char *from,
|
||||
unsigned char *to, RSA * rsa, int padding)
|
||||
{
|
||||
pkcs11 *priv = (pkcs11*)RSA_get_app_data(rsa);
|
||||
const BIGNUM *n = NULL;
|
||||
|
||||
if (padding != RSA_PKCS1_PADDING) {
|
||||
return -1;
|
||||
}
|
||||
RSA_get0_key(rsa, &n, NULL, NULL);
|
||||
return priv->encrypt(flen, from, to, BN_num_bytes(n), CKM_RSA_PKCS);
|
||||
}
|
||||
|
||||
static int rsa_decrypt(int flen, const unsigned char *from,
|
||||
unsigned char *to, RSA * rsa, int padding)
|
||||
{
|
||||
pkcs11 *priv = (pkcs11*)RSA_get_app_data(rsa);
|
||||
|
||||
if (padding != RSA_PKCS1_PADDING) {
|
||||
return -1;
|
||||
}
|
||||
return priv->decrypt(flen, from, to, flen, CKM_RSA_PKCS);
|
||||
}
|
||||
|
||||
static int dsa_privdata_free(DSA *dsa)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11*)DSA_get_ex_data(dsa, 0);
|
||||
delete p11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DSA_SIG *dsa_sign(const unsigned char *dgst, int dlen, DSA *dsa)
|
||||
{
|
||||
int len, rs_len;
|
||||
unsigned char rs_buf[128];
|
||||
pkcs11 *p11 = (pkcs11*)DSA_get_ex_data(dsa, 0);
|
||||
DSA_SIG *dsa_sig = DSA_SIG_new();
|
||||
BIGNUM *r, *s;
|
||||
|
||||
// siglen is unsigned and can't cope with -1 as return value
|
||||
len = p11->encrypt(dlen, dgst, rs_buf, sizeof rs_buf, CKM_DSA);
|
||||
if (len & 0x01) // Must be even
|
||||
goto out;
|
||||
|
||||
rs_len = len / 2;
|
||||
r = BN_bin2bn(rs_buf, rs_len, NULL);
|
||||
s = BN_bin2bn(rs_buf + rs_len, rs_len, NULL);
|
||||
DSA_SIG_set0(dsa_sig, r, s);
|
||||
if (r && s)
|
||||
return dsa_sig;
|
||||
out:
|
||||
DSA_SIG_free(dsa_sig);
|
||||
ign_openssl_error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
|
||||
static void ec_privdata_free(EC_KEY *ec)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11*)EC_KEY_get_ex_data(ec, 0);
|
||||
delete p11;
|
||||
}
|
||||
|
||||
static int ec_sign_setup(EC_KEY *ec, BN_CTX *ctx, BIGNUM **kinvp, BIGNUM **rp)
|
||||
{
|
||||
(void) ec;
|
||||
(void) ctx;
|
||||
(void) kinvp;
|
||||
(void) rp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ECDSA_SIG *ec_do_sign(const unsigned char *dgst, int dgst_len,
|
||||
const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *ec)
|
||||
{
|
||||
int len, rs_len;
|
||||
unsigned char rs_buf[512];
|
||||
ECDSA_SIG *ec_sig = ECDSA_SIG_new();
|
||||
pkcs11 *p11 = (pkcs11 *) EC_KEY_get_ex_data(ec, 0);
|
||||
BIGNUM *r, *s;
|
||||
|
||||
(void) in_kinv;
|
||||
(void) in_r;
|
||||
|
||||
// siglen is unsigned and can' cope with -1 as return value
|
||||
len = p11->encrypt(dgst_len, dgst, rs_buf, sizeof rs_buf, CKM_ECDSA);
|
||||
if (len & 0x01) // Must be even
|
||||
goto out;
|
||||
/* The buffer contains r and s concatenated
|
||||
* Both of equal size
|
||||
* pkcs-11v2-20.pdf chapter 12.13.1, page 232
|
||||
*/
|
||||
rs_len = len / 2;
|
||||
r = BN_bin2bn(rs_buf, rs_len, NULL);
|
||||
s = BN_bin2bn(rs_buf + rs_len, rs_len, NULL);
|
||||
ECDSA_SIG_set0(ec_sig, r, s);
|
||||
if (r && s)
|
||||
return ec_sig;
|
||||
|
||||
out:
|
||||
ECDSA_SIG_free(ec_sig);
|
||||
ign_openssl_error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ec_sign(int type, const unsigned char *dgst, int dlen,
|
||||
unsigned char *sig, unsigned int *siglen,
|
||||
const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec)
|
||||
{
|
||||
ECDSA_SIG *ec_sig;
|
||||
int ret = 0;
|
||||
int len;
|
||||
|
||||
(void) type;
|
||||
ec_sig = ec_do_sign(dgst, dlen, kinv, r, ec);
|
||||
if (!ec_sig)
|
||||
return 0;
|
||||
|
||||
len = i2d_ECDSA_SIG(ec_sig, &sig);
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
*siglen = len;
|
||||
ret = 1;
|
||||
out:
|
||||
ECDSA_SIG_free(ec_sig);
|
||||
ign_openssl_error();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static EC_KEY_METHOD *setup_ec_key_meth()
|
||||
{
|
||||
EC_KEY_METHOD *ec_key_meth;
|
||||
int (*ec_init_proc)(EC_KEY *key);
|
||||
void (*ec_finish_proc)(EC_KEY *key);
|
||||
int (*ec_copy_proc)(EC_KEY *dest, const EC_KEY *src);
|
||||
int (*ec_set_group_proc)(EC_KEY *key, const EC_GROUP *grp);
|
||||
int (*ec_set_private_proc)(EC_KEY *key, const BIGNUM *priv_key);
|
||||
int (*ec_set_public_proc)(EC_KEY *key, const EC_POINT *pub_key);
|
||||
|
||||
ec_key_meth = EC_KEY_METHOD_new(EC_KEY_get_default_method());
|
||||
EC_KEY_METHOD_set_sign(ec_key_meth, ec_sign, ec_sign_setup, ec_do_sign);
|
||||
EC_KEY_METHOD_get_init(ec_key_meth, &ec_init_proc, &ec_finish_proc,
|
||||
&ec_copy_proc, &ec_set_group_proc,
|
||||
&ec_set_private_proc, &ec_set_public_proc);
|
||||
EC_KEY_METHOD_set_init(ec_key_meth, ec_init_proc, ec_privdata_free,
|
||||
ec_copy_proc, ec_set_group_proc,
|
||||
ec_set_private_proc, ec_set_public_proc);
|
||||
return ec_key_meth;
|
||||
}
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
|
||||
static EVP_PKEY_METHOD *p11_eddsa_method;
|
||||
|
||||
static int eddsa_eng_meths(ENGINE *e, EVP_PKEY_METHOD **m, const int **nids, int nid)
|
||||
{
|
||||
static const int my_nids[] = {EVP_PKEY_ED25519 };
|
||||
(void)e;
|
||||
if (m) {
|
||||
switch (nid) {
|
||||
case EVP_PKEY_ED25519:
|
||||
*m = p11_eddsa_method;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (nids) {
|
||||
*nids = my_nids;
|
||||
return ARRAY_SIZE(my_nids);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int eng_pmeth_sign_eddsa(EVP_MD_CTX *ctx,
|
||||
unsigned char *sig, size_t *siglen,
|
||||
const unsigned char *tbs, size_t tbslen)
|
||||
{
|
||||
int len, ret = -1;
|
||||
unsigned char rs_buf[64];
|
||||
EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_pkey_ctx(ctx));
|
||||
pkcs11 *p11 = (pkcs11 *)ENGINE_get_ex_data(EVP_PKEY_get0_engine(pkey), eng_idx);
|
||||
*siglen = EVP_PKEY_size(pkey);
|
||||
if (sig == NULL) {
|
||||
// caller needs only size
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// siglen is unsigned and can' cope with -1 as return value
|
||||
len = p11->encrypt(tbslen, tbs, rs_buf, sizeof rs_buf, CKM_EDDSA);
|
||||
if ((len & 0x01) || (*siglen != (size_t)len)) // Must be even
|
||||
goto out;
|
||||
memcpy(sig, rs_buf, len);
|
||||
*siglen = len;
|
||||
ret = 1;
|
||||
out:
|
||||
ign_openssl_error();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eng_pmeth_ctrl_eddsa(EVP_PKEY_CTX *, int type, int p1, void *p2)
|
||||
{
|
||||
(void)p1;
|
||||
switch (type) {
|
||||
case EVP_PKEY_CTRL_MD:
|
||||
if (p2 == NULL || (const EVP_MD *)p2 == EVP_md_null())
|
||||
return 1;
|
||||
ECerr(EC_F_PKEY_ECD_CTRL, EC_R_INVALID_DIGEST_TYPE);
|
||||
return 0;
|
||||
}
|
||||
qWarning() << "EC Don't call me" << type;
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj)
|
||||
{
|
||||
static RSA_METHOD *rsa_meth = NULL;
|
||||
static DSA_METHOD *dsa_meth = NULL;
|
||||
#ifndef OPENSSL_NO_EC
|
||||
static EC_KEY_METHOD *ec_key_meth = NULL;
|
||||
EC_KEY *ec;
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
static ENGINE *e = NULL;
|
||||
|
||||
if (!e) {
|
||||
e = ENGINE_new();
|
||||
Q_CHECK_PTR(e);
|
||||
|
||||
ENGINE_set_pkey_meths(e, eddsa_eng_meths);
|
||||
ENGINE_set_finish_function(e, eng_finish);
|
||||
if (eng_idx == -1)
|
||||
eng_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 0);
|
||||
ENGINE_set_ex_data(e, eng_idx, NULL);
|
||||
// Why is engine attached to pubkey? I'm commenting it, as I do
|
||||
// not want it to be attached to RSA/DSA/EC
|
||||
//CRYPTO_add(&pub->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
||||
//pub->engine = e;
|
||||
|
||||
if (!p11_eddsa_method) {
|
||||
p11_eddsa_method = EVP_PKEY_meth_new(EVP_PKEY_ED25519,
|
||||
EVP_PKEY_FLAG_SIGCTX_CUSTOM);
|
||||
EVP_PKEY_meth_set_digestsign(p11_eddsa_method,
|
||||
eng_pmeth_sign_eddsa);
|
||||
EVP_PKEY_meth_set_ctrl(p11_eddsa_method,
|
||||
eng_pmeth_ctrl_eddsa, NULL);
|
||||
EVP_PKEY_meth_set_copy(p11_eddsa_method, eng_pmeth_copy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
EVP_PKEY *evp = NULL;
|
||||
int keytype;
|
||||
|
||||
p11slot.isValid();
|
||||
|
||||
keytype = EVP_PKEY_id(pub);
|
||||
|
||||
switch (EVP_PKEY_type(keytype)) {
|
||||
case EVP_PKEY_RSA:
|
||||
rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pub));
|
||||
openssl_error();
|
||||
if (!rsa_meth) {
|
||||
rsa_meth = RSA_meth_dup(RSA_get_default_method());
|
||||
RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt);
|
||||
RSA_meth_set_priv_dec(rsa_meth, rsa_decrypt);
|
||||
RSA_meth_set_finish(rsa_meth, rsa_privdata_free);
|
||||
}
|
||||
p11obj = obj;
|
||||
RSA_set_method(rsa, rsa_meth);
|
||||
RSA_set_app_data(rsa, this);
|
||||
evp = EVP_PKEY_new();
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_RSA(evp, rsa);
|
||||
break;
|
||||
case EVP_PKEY_DSA:
|
||||
dsa = DSAparams_dup(EVP_PKEY_get0_DSA(pub));
|
||||
openssl_error();
|
||||
if (!dsa_meth) {
|
||||
dsa_meth = DSA_meth_dup(DSA_get_default_method());
|
||||
DSA_meth_set_sign(dsa_meth, dsa_sign);
|
||||
DSA_meth_set_finish(dsa_meth, dsa_privdata_free);
|
||||
}
|
||||
p11obj = obj;
|
||||
DSA_set_method(dsa, dsa_meth);
|
||||
DSA_set_ex_data(dsa, 0, this);
|
||||
evp = EVP_PKEY_new();
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_DSA(evp, dsa);
|
||||
break;
|
||||
#ifndef OPENSSL_NO_EC
|
||||
case EVP_PKEY_EC:
|
||||
ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pub));
|
||||
openssl_error();
|
||||
if (!ec_key_meth) {
|
||||
ec_key_meth = setup_ec_key_meth();
|
||||
}
|
||||
p11obj = obj;
|
||||
EC_KEY_set_method(ec, ec_key_meth);
|
||||
EC_KEY_set_ex_data(ec, 0, this);
|
||||
evp = EVP_PKEY_new();
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_EC_KEY(evp, ec);
|
||||
break;
|
||||
#ifdef EVP_PKEY_ED25519
|
||||
case EVP_PKEY_ED25519:
|
||||
size_t len;
|
||||
if (ENGINE_get_ex_data(e, eng_idx))
|
||||
qWarning() << "We forgot to free the previous Card key.";
|
||||
ENGINE_set_ex_data(e, eng_idx, this);
|
||||
p11obj = obj;
|
||||
EVP_PKEY_get_raw_public_key(pub, NULL, &len);
|
||||
unsigned char *pubkey = (unsigned char *)OPENSSL_malloc(len);
|
||||
Q_CHECK_PTR(pubkey);
|
||||
EVP_PKEY_get_raw_public_key(pub, pubkey, &len);
|
||||
evp = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, e, pubkey, len);
|
||||
openssl_error();
|
||||
OPENSSL_free(pubkey);
|
||||
//EVP_PKEY_set1_engine(evp, e);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return evp;
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user