mirror of
https://github.com/chris2511/xca.git
synced 2026-09-12 19:51:05 +05:00
Support importing ED25519 keys and signing with them, using PKCS#11 tokens
What works: - Importing ED25519 Signature key from Yubikey token (OpenSC with openpgp driver, key generated via gpg) - Creating self-signed certificate for CA, for Signature key from card - Signing Certificates using new CA I haven't tested other features, e.g. storing new certificate on card, so, they're probably broken
This commit is contained in:
parent
bab9477e69
commit
6d098460d6
@ -364,6 +364,8 @@ typedef unsigned long ck_key_type_t;
|
||||
#define CKK_AES (0x1f)
|
||||
#define CKK_BLOWFISH (0x20)
|
||||
#define CKK_TWOFISH (0x21)
|
||||
#define CKK_EC_EDWARDS (0x40)
|
||||
#define CKK_EC_MONTGOMERY (0x41)
|
||||
#define CKK_VENDOR_DEFINED ((unsigned long) (1 << 31))
|
||||
|
||||
|
||||
@ -664,6 +666,7 @@ typedef unsigned long ck_mechanism_type_t;
|
||||
#define CKM_ECDH1_DERIVE (0x1050)
|
||||
#define CKM_ECDH1_COFACTOR_DERIVE (0x1051)
|
||||
#define CKM_ECMQV_DERIVE (0x1052)
|
||||
#define CKM_EDDSA (0x1057)
|
||||
#define CKM_JUNIPER_KEY_GEN (0x1060)
|
||||
#define CKM_JUNIPER_ECB128 (0x1061)
|
||||
#define CKM_JUNIPER_CBC128 (0x1062)
|
||||
|
||||
131
lib/pkcs11.cpp
131
lib/pkcs11.cpp
@ -653,6 +653,23 @@ int pkcs11::encrypt(int flen, const unsigned char *from,
|
||||
return size;
|
||||
}
|
||||
|
||||
// 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, EVP_PKEY_CTX *src)
|
||||
{
|
||||
void *p = EVP_PKEY_CTX_get_app_data(src);
|
||||
EVP_PKEY_CTX_set_app_data(dst, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef LIBRESSL_VERSION_NUMBER
|
||||
static int rsa_privdata_free(RSA *rsa)
|
||||
{
|
||||
@ -719,6 +736,8 @@ out:
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
|
||||
static EVP_PKEY_METHOD *p11_eddsa_method;
|
||||
|
||||
static void ec_privdata_free(EC_KEY *ec)
|
||||
{
|
||||
pkcs11 *p11 = (pkcs11*)EC_KEY_get_ex_data(ec, 0);
|
||||
@ -811,6 +830,61 @@ static EC_KEY_METHOD *setup_ec_key_meth()
|
||||
ec_set_private_proc, ec_set_public_proc);
|
||||
return ec_key_meth;
|
||||
}
|
||||
|
||||
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, rs_len, ret = -1;
|
||||
unsigned char rs_buf[512];
|
||||
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 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) // 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 *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
|
||||
|
||||
EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj)
|
||||
@ -820,6 +894,32 @@ EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj)
|
||||
#ifndef OPENSSL_NO_EC
|
||||
static EC_KEY_METHOD *ec_key_meth = NULL;
|
||||
EC_KEY *ec;
|
||||
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
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
@ -876,27 +976,33 @@ EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj)
|
||||
openssl_error();
|
||||
EVP_PKEY_assign_EC_KEY(evp, ec);
|
||||
break;
|
||||
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
|
||||
}
|
||||
return evp;
|
||||
}
|
||||
#else
|
||||
|
||||
static int eng_idx = -1;
|
||||
static EVP_PKEY_METHOD *p11_rsa_method;
|
||||
static EVP_PKEY_METHOD *p11_dsa_method;
|
||||
#ifndef OPENSSL_NO_EC
|
||||
static EVP_PKEY_METHOD *p11_ec_method;
|
||||
#endif
|
||||
|
||||
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_ctrl_rsa(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
|
||||
{
|
||||
switch (type) {
|
||||
@ -1109,13 +1215,6 @@ out:
|
||||
}
|
||||
#endif
|
||||
|
||||
static int eng_pmeth_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
|
||||
{
|
||||
void *p = EVP_PKEY_CTX_get_app_data(src);
|
||||
EVP_PKEY_CTX_set_app_data(dst, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int eng_meths(ENGINE *e, EVP_PKEY_METHOD **m, const int **nids, int nid)
|
||||
{
|
||||
static const int my_nids[] = { EVP_PKEY_EC, EVP_PKEY_RSA };
|
||||
|
||||
@ -206,6 +206,25 @@ EVP_PKEY *pki_scard::load_pubkey(pkcs11 &p11, CK_OBJECT_HANDLE object) const
|
||||
EVP_PKEY_assign_EC_KEY(pkey, ec);
|
||||
break;
|
||||
}
|
||||
case CKK_EC_EDWARDS: {
|
||||
QByteArray ba;
|
||||
ASN1_OCTET_STRING *os;
|
||||
pk11_attr_data grp(CKA_EC_PARAMS);
|
||||
p11.loadAttribute(grp, object);
|
||||
pk11_attr_data pt(CKA_EC_POINT);
|
||||
p11.loadAttribute(pt, object);
|
||||
ba = pt.getData();
|
||||
os = (ASN1_OCTET_STRING *)
|
||||
d2i_bytearray(D2I_VOID(d2i_ASN1_OCTET_STRING), ba);
|
||||
pki_openssl_error();
|
||||
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
|
||||
(const uint8_t *)os->data,
|
||||
os->length);
|
||||
pki_openssl_error();
|
||||
ASN1_OCTET_STRING_free(os);
|
||||
pki_openssl_error();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
throw errorEx(QString("Unsupported CKA_KEY_TYPE: %1\n").arg(keytype));
|
||||
@ -328,6 +347,10 @@ pk11_attlist pki_scard::objectAttributesNoId(EVP_PKEY *pk, bool priv) const
|
||||
attrs << pk11_attr_ulong(CKA_KEY_TYPE, CKK_EC) <<
|
||||
pk11_attr_data(CKA_EC_PARAMS, ba);
|
||||
break;
|
||||
case EVP_PKEY_ED25519:
|
||||
attrs << pk11_attr_ulong(CKA_KEY_TYPE, CKK_EC_EDWARDS);
|
||||
// should it also return params, somehow?
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
throw errorEx(QString("Unknown Keytype %d")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user