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:
Yaroslav Isakov 2022-07-28 22:48:20 +02:00
parent bab9477e69
commit 6d098460d6
3 changed files with 141 additions and 16 deletions

View File

@ -364,6 +364,8 @@ typedef unsigned long ck_key_type_t;
#define CKK_AES (0x1f) #define CKK_AES (0x1f)
#define CKK_BLOWFISH (0x20) #define CKK_BLOWFISH (0x20)
#define CKK_TWOFISH (0x21) #define CKK_TWOFISH (0x21)
#define CKK_EC_EDWARDS (0x40)
#define CKK_EC_MONTGOMERY (0x41)
#define CKK_VENDOR_DEFINED ((unsigned long) (1 << 31)) #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_DERIVE (0x1050)
#define CKM_ECDH1_COFACTOR_DERIVE (0x1051) #define CKM_ECDH1_COFACTOR_DERIVE (0x1051)
#define CKM_ECMQV_DERIVE (0x1052) #define CKM_ECMQV_DERIVE (0x1052)
#define CKM_EDDSA (0x1057)
#define CKM_JUNIPER_KEY_GEN (0x1060) #define CKM_JUNIPER_KEY_GEN (0x1060)
#define CKM_JUNIPER_ECB128 (0x1061) #define CKM_JUNIPER_ECB128 (0x1061)
#define CKM_JUNIPER_CBC128 (0x1062) #define CKM_JUNIPER_CBC128 (0x1062)

View File

@ -653,6 +653,23 @@ int pkcs11::encrypt(int flen, const unsigned char *from,
return size; 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 #ifndef LIBRESSL_VERSION_NUMBER
static int rsa_privdata_free(RSA *rsa) static int rsa_privdata_free(RSA *rsa)
{ {
@ -719,6 +736,8 @@ out:
#ifndef OPENSSL_NO_EC #ifndef OPENSSL_NO_EC
static EVP_PKEY_METHOD *p11_eddsa_method;
static void ec_privdata_free(EC_KEY *ec) static void ec_privdata_free(EC_KEY *ec)
{ {
pkcs11 *p11 = (pkcs11*)EC_KEY_get_ex_data(ec, 0); 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); ec_set_private_proc, ec_set_public_proc);
return ec_key_meth; 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 #endif
EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj) 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 #ifndef OPENSSL_NO_EC
static EC_KEY_METHOD *ec_key_meth = NULL; static EC_KEY_METHOD *ec_key_meth = NULL;
EC_KEY *ec; 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 #endif
RSA *rsa; RSA *rsa;
DSA *dsa; DSA *dsa;
@ -876,27 +976,33 @@ EVP_PKEY *pkcs11::getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj)
openssl_error(); openssl_error();
EVP_PKEY_assign_EC_KEY(evp, ec); EVP_PKEY_assign_EC_KEY(evp, ec);
break; 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 #endif
} }
return evp; return evp;
} }
#else #else
static int eng_idx = -1;
static EVP_PKEY_METHOD *p11_rsa_method; static EVP_PKEY_METHOD *p11_rsa_method;
static EVP_PKEY_METHOD *p11_dsa_method; static EVP_PKEY_METHOD *p11_dsa_method;
#ifndef OPENSSL_NO_EC #ifndef OPENSSL_NO_EC
static EVP_PKEY_METHOD *p11_ec_method; static EVP_PKEY_METHOD *p11_ec_method;
#endif #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) static int eng_pmeth_ctrl_rsa(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
{ {
switch (type) { switch (type) {
@ -1109,13 +1215,6 @@ out:
} }
#endif #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 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 }; static const int my_nids[] = { EVP_PKEY_EC, EVP_PKEY_RSA };

View File

@ -206,6 +206,25 @@ EVP_PKEY *pki_scard::load_pubkey(pkcs11 &p11, CK_OBJECT_HANDLE object) const
EVP_PKEY_assign_EC_KEY(pkey, ec); EVP_PKEY_assign_EC_KEY(pkey, ec);
break; 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 #endif
default: default:
throw errorEx(QString("Unsupported CKA_KEY_TYPE: %1\n").arg(keytype)); 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) << attrs << pk11_attr_ulong(CKA_KEY_TYPE, CKK_EC) <<
pk11_attr_data(CKA_EC_PARAMS, ba); pk11_attr_data(CKA_EC_PARAMS, ba);
break; break;
case EVP_PKEY_ED25519:
attrs << pk11_attr_ulong(CKA_KEY_TYPE, CKK_EC_EDWARDS);
// should it also return params, somehow?
break;
#endif #endif
default: default:
throw errorEx(QString("Unknown Keytype %d") throw errorEx(QString("Unknown Keytype %d")