Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TLS operation with EdDSA keys #465

Merged
merged 3 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Files: .github/*
tools/openssl*.cnf
tests/*.pem
tests/cert.json.in
tests/cert.json.part.in
scripts/clean-dist.sh
Copyright: (C) 2022 - 2024 Simo Sorce <[email protected]>
License: Apache-2.0
Expand Down
22 changes: 17 additions & 5 deletions src/keymgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,8 +1396,8 @@ static int p11prov_ec_match(const void *keydata1, const void *keydata2,
return p11prov_common_match(keydata1, keydata2, CKK_EC, selection);
}

static int p11prov_ec_import(void *keydata, int selection,
const OSSL_PARAM params[])
static int p11prov_ec_import_genr(CK_KEY_TYPE key_type, void *keydata,
int selection, const OSSL_PARAM params[])
{
P11PROV_OBJ *key = (P11PROV_OBJ *)keydata;
CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
Expand Down Expand Up @@ -1426,13 +1426,19 @@ static int p11prov_ec_import(void *keydata, int selection,
}
}

rv = p11prov_obj_import_key(key, CKK_EC, class, params);
rv = p11prov_obj_import_key(key, key_type, class, params);
if (rv != CKR_OK) {
return RET_OSSL_ERR;
}
return RET_OSSL_OK;
}

static int p11prov_ec_import(void *keydata, int selection,
const OSSL_PARAM params[])
{
return p11prov_ec_import_genr(CKK_EC, keydata, selection, params);
}

static int p11prov_ec_export(void *keydata, int selection, OSSL_CALLBACK *cb_fn,
void *cb_arg)
{
Expand Down Expand Up @@ -1915,6 +1921,12 @@ static int p11prov_ed_export(void *keydata, int selection, OSSL_CALLBACK *cb_fn,
return RET_OSSL_ERR;
}

static int p11prov_ed_import(void *keydata, int selection,
const OSSL_PARAM params[])
{
return p11prov_ec_import_genr(CKK_EC_EDWARDS, keydata, selection, params);
}

static const OSSL_PARAM *p11prov_ed_import_types(int selection)
{
static const OSSL_PARAM p11prov_ed_imp_key_types[] = {
Expand Down Expand Up @@ -2082,7 +2094,7 @@ const OSSL_DISPATCH p11prov_ed25519_keymgmt_functions[] = {
DISPATCH_KEYMGMT_ELEM(ec, FREE, free),
DISPATCH_KEYMGMT_ELEM(ec, HAS, has),
DISPATCH_KEYMGMT_ELEM(ed, MATCH, match),
DISPATCH_KEYMGMT_ELEM(ec, IMPORT, import),
DISPATCH_KEYMGMT_ELEM(ed, IMPORT, import),
DISPATCH_KEYMGMT_ELEM(ed, IMPORT_TYPES, import_types),
DISPATCH_KEYMGMT_ELEM(ed, EXPORT, export),
DISPATCH_KEYMGMT_ELEM(ed, EXPORT_TYPES, export_types),
Expand All @@ -2106,7 +2118,7 @@ const OSSL_DISPATCH p11prov_ed448_keymgmt_functions[] = {
DISPATCH_KEYMGMT_ELEM(ec, FREE, free),
DISPATCH_KEYMGMT_ELEM(ec, HAS, has),
DISPATCH_KEYMGMT_ELEM(ed, MATCH, match),
DISPATCH_KEYMGMT_ELEM(ec, IMPORT, import),
DISPATCH_KEYMGMT_ELEM(ed, IMPORT, import),
DISPATCH_KEYMGMT_ELEM(ed, IMPORT_TYPES, import_types),
DISPATCH_KEYMGMT_ELEM(ed, EXPORT, export),
DISPATCH_KEYMGMT_ELEM(ed, EXPORT_TYPES, export_types),
Expand Down
145 changes: 143 additions & 2 deletions src/objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -2974,6 +2974,134 @@ static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[],
return rv;
}

static CK_RV prep_ed_find(P11PROV_CTX *ctx, const OSSL_PARAM params[],
struct pool_find_ctx *findctx)
{
OSSL_PARAM tmp;
const OSSL_PARAM *p;

data_buffer digest_data[4];
data_buffer digest = { 0 };

const unsigned char *ecparams = NULL;
int len, i;
CK_RV rv;

if (findctx->numattrs != MAX_ATTRS_SIZE) {
return CKR_ARGUMENTS_BAD;
}
findctx->numattrs = 0;

switch (findctx->class) {
case CKO_PUBLIC_KEY:
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
if (!p) {
P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s",
OSSL_PKEY_PARAM_PUB_KEY);
rv = CKR_KEY_INDIGESTIBLE;
goto done;
}

if (p->data_size == ED25519_BYTE_SIZE) {
ecparams = ed25519_ec_params;
len = ED25519_EC_PARAMS_LEN;
findctx->bit_size = ED25519_BIT_SIZE;
findctx->key_size = ED25519_BYTE_SIZE;
} else if (p->data_size == ED448_BYTE_SIZE) {
ecparams = ed448_ec_params;
len = ED448_EC_PARAMS_LEN;
findctx->bit_size = ED448_BIT_SIZE;
findctx->key_size = ED448_BYTE_SIZE;
} else {
P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE,
"Public key of unknown length %lu", p->data_size);
rv = CKR_KEY_INDIGESTIBLE;
goto done;
}

rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_PUB_KEY,
&findctx->attrs[0], CKA_P11PROV_PUB_KEY, false);
if (rv != CKR_OK) {
goto done;
}

findctx->numattrs++;

break;
case CKO_PRIVATE_KEY:
/* A Token would never allow us to search by private exponent,
* so we store a hash of the private key in CKA_ID */
p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
if (!p) {
P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s",
OSSL_PKEY_PARAM_PRIV_KEY);
return CKR_KEY_INDIGESTIBLE;
}

i = 0;

if (p->data_size == ED25519_BYTE_SIZE) {
ecparams = ed25519_ec_params;
len = ED25519_EC_PARAMS_LEN;
findctx->bit_size = ED25519_BIT_SIZE;
findctx->key_size = ED25519_BYTE_SIZE;
} else if (p->data_size == ED448_BYTE_SIZE) {
ecparams = ed448_ec_params;
len = ED448_EC_PARAMS_LEN;
findctx->bit_size = ED448_BIT_SIZE;
findctx->key_size = ED448_BYTE_SIZE;
} else {
P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE,
"Private key of unknown length %lu", p->data_size);
rv = CKR_KEY_INDIGESTIBLE;
goto done;
}

/* prefix */
digest_data[i].data = (uint8_t *)"PrivKey";
digest_data[i].length = 7;
i++;

digest_data[i].data = (CK_BYTE *)ecparams;
digest_data[i].length = len;
i++;

digest_data[i].data = p->data;
digest_data[i].length = p->data_size;
i++;

digest_data[i].data = NULL;

rv = p11prov_digest_util(ctx, "sha256", NULL, digest_data, &digest);
if (rv != CKR_OK) {
return rv;
}
findctx->attrs[0].type = CKA_ID;
findctx->attrs[0].pValue = digest.data;
findctx->attrs[0].ulValueLen = digest.length;
findctx->numattrs++;

break;
default:
return CKR_GENERAL_ERROR;
}

/* common params */
tmp.key = "EC Params";
tmp.data = (CK_BYTE *)ecparams;
tmp.data_size = len;
rv = param_to_attr(ctx, &tmp, tmp.key, &findctx->attrs[findctx->numattrs],
CKA_EC_PARAMS, false);
if (rv != CKR_OK) {
goto done;
}
findctx->numattrs++;
rv = CKR_OK;

done:
return rv;
}

static CK_RV return_dup_key(P11PROV_OBJ *dst, P11PROV_OBJ *src)
{
CK_RV rv;
Expand Down Expand Up @@ -3073,14 +3201,21 @@ static CK_RV p11prov_obj_import_public_key(P11PROV_OBJ *key, CK_KEY_TYPE type,
break;

case CKK_EC:
case CKK_EC_EDWARDS:
rv = prep_ec_find(ctx, params, &findctx);
if (rv != CKR_OK) {
goto done;
}
allocattrs = EC_ATTRS_NUM;
break;

case CKK_EC_EDWARDS:
rv = prep_ed_find(ctx, params, &findctx);
if (rv != CKR_OK) {
goto done;
}
allocattrs = EC_ATTRS_NUM;
break;

default:
P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE,
"Unsupported key type: %08lx", type);
Expand Down Expand Up @@ -3620,13 +3755,19 @@ static CK_RV p11prov_obj_import_private_key(P11PROV_OBJ *key, CK_KEY_TYPE type,
break;

case CKK_EC:
case CKK_EC_EDWARDS:
rv = prep_ec_find(ctx, params, &findctx);
if (rv != CKR_OK) {
goto done;
}
break;

case CKK_EC_EDWARDS:
rv = prep_ed_find(ctx, params, &findctx);
if (rv != CKR_OK) {
goto done;
}
break;

default:
P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE,
"Unsupported key type: %08lx", type);
Expand Down
17 changes: 1 addition & 16 deletions tests/cert.json.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[
{"server_command": [@CHECKER@"openssl", "s_server", "-www", "-port", "@PORT@",
{"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@",
"-key", "@PRIURI@", "-cert", "@CRTURI@",
"-verify", "1", "-CAfile", "tests/clientX509Cert.pem"],
"comment": "Use ANY certificate just to ensure that server tries to authorise a client",
Expand All @@ -18,19 +18,4 @@
"-s", "@SIGALGS@",
"-p", "@PORT@"]}
]
},
{"server_command": [@CHECKER@"openssl", "s_server", "-www", "-port", "@PORT@", "-key", "@ECPRIURI@", "-cert", "@ECCRTURI@"],
"comment": "Run test with ECDSA hostkey in pkcs11 provider",
"environment": {"PYTHONPATH" : "."},
"server_hostname": "localhost",
"server_port": @PORT@,
"tests" : [
{"name" : "test-tls13-conversation.py",
"arguments" : ["-p", "@PORT@"]},
{"name" : "test-conversation.py",
"arguments" : ["-p", "@PORT@",
"-d"]}
]
}
]

15 changes: 15 additions & 0 deletions tests/cert.json.part.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
,
{"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@"],
"comment": "Run test without certificate verify",
"environment": {"PYTHONPATH" : "."},
"server_hostname": "localhost",
"server_port": @PORT@,
"tests" : [
{"name" : "test-tls13-conversation.py",
"arguments" : ["-p", "@PORT@"]},
{"name" : "test-conversation.py",
"arguments" : ["-p", "@PORT@",
"-d"]}
]
}

32 changes: 24 additions & 8 deletions tests/ttls
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ run_test() {
CERT="$2"
SRV_ARGS=$3
CLNT_ARGS=$4
expect -c "spawn $CHECKER openssl s_server -accept \"${PORT}\" -naccept 1 -key \"${KEY}\" -cert \"${CERT}\" $SRV_ARGS;
set timeout 60;

export PKCS11_PROVIDER_DEBUG="file:${TMPPDIR}/p11prov-debug-tls-server.log"
expect -c "spawn $CHECKER openssl s_server $PROPQ -accept \"${PORT}\" -naccept 1 -key \"${KEY}\" -cert \"${CERT}\" $SRV_ARGS;
set timeout 10;
expect {
\"ACCEPT\" {};
eof { exit 2; }
timeout { exit 5; }
default {
send \" NO ACCEPT \n\";
exit 1;
Expand All @@ -54,6 +57,7 @@ run_test() {
expect {
\"END SSL SESSION PARAMETERS\" {};
eof { exit 2; }
timeout { exit 5; }
default {
send \" NO SESSION PARAMETERS \n\";
exit 1;
Expand All @@ -63,6 +67,7 @@ run_test() {
send \"Q\n\"
expect {
eof {exit 0;};
timeout { exit 5; }
default {
send \" NO EOF \n\";
exit 1;
Expand All @@ -72,18 +77,21 @@ run_test() {

read -r < "${TMPPDIR}/s_server_ready"

expect -c "spawn $CHECKER openssl s_client -connect \"localhost:${PORT}\" -CAfile \"${CACRT}\" $CLNT_ARGS;
set timeout 60;
export PKCS11_PROVIDER_DEBUG="file:${TMPPDIR}/p11prov-debug-tls-client.log"
expect -c "spawn $CHECKER openssl s_client $PROPQ -connect \"localhost:${PORT}\" -CAfile \"${CACRT}\" $CLNT_ARGS;
set timeout 10;
expect {
\" TLS SUCCESSFUL \" {};
eof { exit 2; }
timeout { exit 5; }
default {
send \" NO TLS SUCCESSFUL MESSAGE \n\";
exit 1;
};
}
expect {
eof {exit 0;};
timeout { exit 5; }
default {
send \" NO EOF \n\";
exit 1;
Expand All @@ -101,6 +109,11 @@ run_tests() {
title PARA "Run sanity test with default values (ECDSA)"
run_test "$ECPRIURI" "$ECCRTURI"

if [[ -n "$EDBASEURI" ]]; then
title PARA "Run sanity test with default values (EdDSA)"
run_test "$EDPRIURI" "$EDCRTURI"
fi

title PARA "Run test with TLS 1.2"
run_test "$PRIURI" "$CRTURI" "" "-tls1_2"

Expand All @@ -118,15 +131,18 @@ run_tests() {
}

title SECTION "TLS with key in provider"
PROPQ=""
run_tests
title ENDSECTION

title SECTION "Forcing the provider for all server operations"
#Try again forcing all operations on the token
#We need to disable digest operations as OpenSSL depends on context duplication working
# We can not put this into the openssl.cnf directly, as it would be picked up by softhsm
# causing infinite recursion when doing EdDSA key operations.
Jakuje marked this conversation as resolved.
Show resolved Hide resolved
PROPQ="-propquery \"?provider=pkcs11\""
# Try again forcing all operations on the token
# We need to disable digest operations as OpenSSL depends on context duplication working
ORIG_OPENSSL_CONF=${OPENSSL_CONF}
sed -e "s/^#MORECONF/alg_section = algorithm_sec\n\n[algorithm_sec]\ndefault_properties = ?provider=pkcs11/" \
-e "s/^#pkcs11-module-block-operations/pkcs11-module-block-operations = digest/" \
sed -e "s/^#pkcs11-module-block-operations/pkcs11-module-block-operations = digest/" \
"${OPENSSL_CONF}" > "${OPENSSL_CONF}.forcetoken"
OPENSSL_CONF=${OPENSSL_CONF}.forcetoken

Expand Down
Loading
Loading