Skip to content

Commit

Permalink
Add support co create ECDH public key from params
Browse files Browse the repository at this point in the history
OpenSSL expects to be able to create an EC PKEY and only "generate"
params, then fill in the key with a public key received from a peer.

So split the common gen_init into per key type ones as each type needs
slightly different setup and conditions now.

Also modify the code that sets public EC keys to allow setting a key on
a base object that does not already have key attributes at all.

Signed-off-by: Simo Sorce <[email protected]>
  • Loading branch information
simo5 committed Jun 11, 2024
1 parent 1ff2b3a commit 75cc2c3
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 72 deletions.
211 changes: 146 additions & 65 deletions src/keymgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,65 +131,6 @@ struct key_generator {
void *cb_arg;
};

static void *p11prov_common_gen_init(void *provctx, int selection,
CK_KEY_TYPE type,
const OSSL_PARAM params[])
{
struct key_generator *ctx = NULL;
/* big endian 65537 */
unsigned char def_e[] = { 0x01, 0x00, 0x01 };
int ret;

P11PROV_debug("common gen_init %p", provctx);

ret = p11prov_ctx_status(provctx);
if (ret != CKR_OK) {
return NULL;
}

if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) {
P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection");
return NULL;
}

ctx = OPENSSL_zalloc(sizeof(struct key_generator));
if (ctx == NULL) {
P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator");
return NULL;
}
ctx->provctx = (P11PROV_CTX *)provctx;
ctx->type = type;

/* set defaults */
switch (type) {
case CKK_RSA:
ctx->mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
ctx->data.rsa.modulus_bits = 2048;
ctx->data.rsa.exponent_size = sizeof(def_e);
memcpy(ctx->data.rsa.exponent, def_e, ctx->data.rsa.exponent_size);
break;
case CKK_EC:
ctx->mechanism.mechanism = CKM_EC_KEY_PAIR_GEN;
ctx->data.ec.ec_params = prime256v1_param;
ctx->data.ec.ec_params_size = sizeof(prime256v1_param);
break;
case CKK_EC_EDWARDS:
ctx->mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN;
break;
default:
P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Invalid type %lu", type);
OPENSSL_free(ctx);
return NULL;
}

ret = p11prov_common_gen_set_params(ctx, params);
if (ret != RET_OSSL_OK) {
p11prov_common_gen_cleanup(ctx);
ctx = NULL;
}
return ctx;
}

static int p11prov_common_gen_set_params(void *genctx,
const OSSL_PARAM params[])
{
Expand Down Expand Up @@ -618,9 +559,43 @@ static int p11prov_common_match(const void *keydata1, const void *keydata2,
static void *p11prov_rsa_gen_init(void *provctx, int selection,
const OSSL_PARAM params[])
{
struct key_generator *ctx = NULL;
/* big endian 65537 */
unsigned char def_e[] = { 0x01, 0x00, 0x01 };
int ret;

P11PROV_debug("rsa gen_init %p", provctx);

return p11prov_common_gen_init(provctx, selection, CKK_RSA, params);
ret = p11prov_ctx_status(provctx);
if (ret != CKR_OK) {
return NULL;
}

if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) {
P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection");
return NULL;
}

ctx = OPENSSL_zalloc(sizeof(struct key_generator));
if (ctx == NULL) {
P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator");
return NULL;
}
ctx->provctx = (P11PROV_CTX *)provctx;
ctx->type = CKK_RSA;

/* set defaults */
ctx->mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
ctx->data.rsa.modulus_bits = 2048;
ctx->data.rsa.exponent_size = sizeof(def_e);
memcpy(ctx->data.rsa.exponent, def_e, ctx->data.rsa.exponent_size);

ret = p11prov_common_gen_set_params(ctx, params);
if (ret != RET_OSSL_OK) {
p11prov_common_gen_cleanup(ctx);
ctx = NULL;
}
return ctx;
}

static int p11prov_rsa_gen_internal(void *genctx, OSSL_CALLBACK *cb_fn,
Expand Down Expand Up @@ -1265,9 +1240,48 @@ static void *p11prov_ec_new(void *provctx)
static void *p11prov_ec_gen_init(void *provctx, int selection,
const OSSL_PARAM params[])
{
struct key_generator *ctx = NULL;
int ret;

P11PROV_debug("ec gen_init %p", provctx);

return p11prov_common_gen_init(provctx, selection, CKK_EC, params);
ret = p11prov_ctx_status(provctx);
if (ret != CKR_OK) {
return NULL;
}

/* we need to allow to initialize a generation of just domain parameters,
* as this is used by OpenSSL for ECDH, to set the expected paramters first
* and then import the received public peer key */
if ((selection & OSSL_KEYMGMT_SELECT_ALL) == 0) {
P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection");
return NULL;
}

ctx = OPENSSL_zalloc(sizeof(struct key_generator));
if (ctx == NULL) {
P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator");
return NULL;
}
ctx->provctx = (P11PROV_CTX *)provctx;
ctx->type = CKK_EC;

if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
ctx->mechanism.mechanism = CKM_EC_KEY_PAIR_GEN;
} else {
ctx->mechanism.mechanism = CK_UNAVAILABLE_INFORMATION;
}

/* set defaults */
ctx->data.ec.ec_params = prime256v1_param;
ctx->data.ec.ec_params_size = sizeof(prime256v1_param);

ret = p11prov_common_gen_set_params(ctx, params);
if (ret != RET_OSSL_OK) {
p11prov_common_gen_cleanup(ctx);
ctx = NULL;
}
return ctx;
}

static void *p11prov_ec_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg)
Expand All @@ -1276,6 +1290,19 @@ static void *p11prov_ec_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg)
void *key;
CK_RV ret;

if (ctx->mechanism.mechanism == CK_UNAVAILABLE_INFORMATION) {
/* OpenSSL asked for a paramgen, basically it wants an
* empty key of a specific group that it will be filling
* up with public params later */
CK_ATTRIBUTE ec_params = {
.type = CKA_EC_PARAMS,
.pValue = (CK_VOID_PTR)ctx->data.ec.ec_params,
.ulValueLen = (CK_ULONG)ctx->data.ec.ec_params_size,
};

return mock_pub_ec_key(ctx->provctx, ctx->type, &ec_params);
}

/* always leave space for CKA_ID and CKA_LABEL */
#define EC_PUBKEY_TMPL_SIZE 5
CK_ATTRIBUTE pubkey_template[EC_PUBKEY_TMPL_SIZE + COMMON_TMPL_SIZE] = {
Expand Down Expand Up @@ -1701,8 +1728,35 @@ static void *p11prov_ed25519_gen_init(void *provctx, int selection,

P11PROV_debug("ed25519 gen_init %p", provctx);

ctx = p11prov_common_gen_init(provctx, selection, CKK_EC_EDWARDS, curve);
if (!ctx) {
ret = p11prov_ctx_status(provctx);
if (ret != CKR_OK) {
return NULL;
}

/* we need to allow to initialize a generation of just domain parameters,
* as this is used by OpenSSL for ECDH, to set the expected paramters first
* and then import the received public peer key */
if ((selection & OSSL_KEYMGMT_SELECT_ALL) == 0) {
P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection");
return NULL;
}

ctx = OPENSSL_zalloc(sizeof(struct key_generator));
if (ctx == NULL) {
P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator");
return NULL;
}
ctx->provctx = (P11PROV_CTX *)provctx;
ctx->type = CKK_EC_EDWARDS;

if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
ctx->mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN;
}

/* set defaults */
ret = p11prov_common_gen_set_params(ctx, curve);
if (ret != RET_OSSL_OK) {
p11prov_common_gen_cleanup(ctx);
return NULL;
}

Expand All @@ -1726,8 +1780,35 @@ static void *p11prov_ed448_gen_init(void *provctx, int selection,

P11PROV_debug("ed448 gen_init %p", provctx);

ctx = p11prov_common_gen_init(provctx, selection, CKK_EC_EDWARDS, curve);
if (!ctx) {
ret = p11prov_ctx_status(provctx);
if (ret != CKR_OK) {
return NULL;
}

/* we need to allow to initialize a generation of just domain parameters,
* as this is used by OpenSSL for ECDH, to set the expected paramters first
* and then import the received public peer key */
if ((selection & OSSL_KEYMGMT_SELECT_ALL) == 0) {
P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection");
return NULL;
}

ctx = OPENSSL_zalloc(sizeof(struct key_generator));
if (ctx == NULL) {
P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator");
return NULL;
}
ctx->provctx = (P11PROV_CTX *)provctx;
ctx->type = CKK_EC_EDWARDS;

if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
ctx->mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN;
}

/* set defaults */
ret = p11prov_common_gen_set_params(ctx, curve);
if (ret != RET_OSSL_OK) {
p11prov_common_gen_cleanup(ctx);
return NULL;
}

Expand Down
101 changes: 94 additions & 7 deletions src/objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -2890,6 +2890,7 @@ CK_RV p11prov_obj_set_ec_encoded_public_key(P11PROV_OBJ *key,
CK_ATTRIBUTE new_pub;
ASN1_OCTET_STRING oct;
unsigned char *der = NULL;
int add_attrs = 0;
int len;

if (key->handle != CK_INVALID_HANDLE) {
Expand All @@ -2902,20 +2903,59 @@ CK_RV p11prov_obj_set_ec_encoded_public_key(P11PROV_OBJ *key,
return CKR_KEY_INDIGESTIBLE;
}

switch (key->data.key.type) {
case CKK_EC:
case CKK_EC_EDWARDS:
/* check that this is a public key */
if (key->class != CKO_PUBLIC_KEY) {
P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE,
"Invalid Key type, not a public key");
return CKR_KEY_INDIGESTIBLE;
}
break;
default:
P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE,
"Invalid Key type, not an EC/ED key");
return CKR_KEY_INDIGESTIBLE;
}

pub = p11prov_obj_get_attr(key, CKA_P11PROV_PUB_KEY);
if (!pub) {
P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "No public key found");
return CKR_KEY_INDIGESTIBLE;
add_attrs += 1;
}

ecpoint = p11prov_obj_get_attr(key, CKA_EC_POINT);
if (!ecpoint) {
P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "No public key found");
return CKR_KEY_INDIGESTIBLE;
add_attrs += 1;
}

if (add_attrs > 0) {
void *ptr = OPENSSL_realloc(key->attrs, sizeof(CK_ATTRIBUTE) * (key->numattrs + add_attrs));
if (!ptr) {
P11PROV_raise(key->ctx, CKR_HOST_MEMORY,
"Failed to store key public key");
return CKR_HOST_MEMORY;
}
}

OPENSSL_free(pub->pValue);
if (!pub) {
pub = &key->attrs[key->numattrs];
key->numattrs += 1;
} else {
OPENSSL_free(pub->pValue);
}
/* always memset as realloc does not guarantee zeroed data */
memset(pub, 0, sizeof(CK_ATTRIBUTE));

if (!ecpoint) {
ecpoint = &key->attrs[key->numattrs];
key->numattrs += 1;
} else {
OPENSSL_free(ecpoint->pValue);
}
/* always memset as realloc does not guarantee zeroed data */
memset(ecpoint, 0, sizeof(CK_ATTRIBUTE));

new_pub.type = CKA_P11PROV_PUB_KEY;
new_pub.pValue = (CK_VOID_PTR)pubkey;
new_pub.ulValueLen = (CK_ULONG)pubkey_len;
Expand All @@ -2934,8 +2974,7 @@ CK_RV p11prov_obj_set_ec_encoded_public_key(P11PROV_OBJ *key,
"Failure to encode EC point to DER");
return CKR_KEY_INDIGESTIBLE;
}

OPENSSL_free(ecpoint->pValue);
ecpoint->type = CKA_EC_POINT;
ecpoint->pValue = der;
ecpoint->ulValueLen = len;

Expand Down Expand Up @@ -3049,3 +3088,51 @@ CK_RV p11prov_merge_pub_attrs_into_priv(P11PROV_OBJ *pub_key,
P11PROV_raise(priv_key->ctx, ret, "Failed attr copy");
return CKR_GENERAL_ERROR;
}

/* creates an empty (no public point Public EC Key, (OpenSSL paramgen function),
* that will later be filled in with a public EC key obtained by a peer */
P11PROV_OBJ *mock_pub_ec_key(P11PROV_CTX *ctx, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *ec_params)
{
P11PROV_OBJ *key;
CK_RV ret;

key = p11prov_obj_new(ctx, CK_UNAVAILABLE_INFORMATION,
CK_INVALID_HANDLE, CK_UNAVAILABLE_INFORMATION);
if (!key) {
return NULL;
}

key->class = CKO_PUBLIC_KEY;
key->data.key.type = type;

/* at this stage we have EC_PARAMS and the preprocessing
* function will add CKA_P11PROV_CURVE_NID and
* CKA_P11PROV_CURVE_NAME */
key->attrs = OPENSSL_zalloc(KEY_EC_PARAMS * sizeof(CK_ATTRIBUTE));
if (key->attrs == NULL) {
P11PROV_raise(key->ctx, CKR_HOST_MEMORY,
"Failed to generate mock ec key");
p11prov_obj_free(key);
return NULL;
}

ret = p11prov_copy_attr(&key->attrs[0], ec_params);
if (ret != CKR_OK) {
P11PROV_raise(key->ctx, CKR_HOST_MEMORY,
"Failed to generate mock key");
p11prov_obj_free(key);
return NULL;
}
key->numattrs++;

/* verify params are ok */
ret = pre_process_ec_key_data(key);
if (ret != CKR_OK) {
P11PROV_raise(key->ctx, CKR_HOST_MEMORY,
"Failed to generate mock key");
p11prov_obj_free(key);
return NULL;
}

return key;
}
1 change: 1 addition & 0 deletions src/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ int p11prov_obj_export_public_key(P11PROV_OBJ *obj, CK_KEY_TYPE key_type,
int p11prov_obj_get_ec_public_x_y(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub_x,
CK_ATTRIBUTE **pub_y);
int p11prov_obj_get_ed_pub_key(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub);
P11PROV_OBJ *mock_pub_ec_key(P11PROV_CTX *ctx, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *ec_params);

#define OBJ_CMP_KEY_TYPE 0x00
#define OBJ_CMP_KEY_PUBLIC 0x01
Expand Down

0 comments on commit 75cc2c3

Please sign in to comment.