Skip to content

Commit 418a89a

Browse files
Ivan StepicOpenEmbedded
authored andcommitted
Introduce generic keypair generation interface and engine ctrl command
As discussed in OpenSC#379 and OpenSC#378 we need a generic interface that supports multiple algorithms for key generation. Attempt was made to create a new keygen method and register it in PKCS11_pkey_meths() in p11_pkey.c (so that it's possible to generate keys using OpenSSL's EVP_PKEY_* API) but multiple design issues appeared. How and where do you pass the key ID, token label and alike was the first question. As suggested by the maintainer here: OpenSC#379 (comment), app_data from EVP_PKEY_CTX was (mis)used and that worked well. The reason why this approach was abandoned is because a good (or bad) way to get a handle of the PKCS11_CTX_private, that is necessary for the Cryptoki call, was not found. The way other operations work is that they rely on the key being loaded *_first_* through ENGINE_load_public(private)_key because this is when the PKCS11_CTX gets initialized and a handle to PKCS11_OBJECT_private gets set to the ex_data of the underlying key. Key generation obviously cannot rely on that mechanism since key doesn't yet exist. Instead, a generic PKCS11_generate_key interface was made that takes a structure describing the key generation algorithm. For now it only contains simple options like curve name for ECC or number of bits for RSA key generation. This interface can then be used as any other PKCS11 wrapper interface or using the ENGINE control commands. Using it with ENGINE control commands is demonstrated in the new tests/keygen.c file. Code for ECC keygen was taken from: OpenSC#379 and reworked to compile and work with some new additions to libp11 i.e. templates. Upstream-Status: Submitted [OpenSC#474] Signed-off-by: Jorge Ramirez-Ortiz <[email protected]>
1 parent 6d66918 commit 418a89a

File tree

12 files changed

+664
-30
lines changed

12 files changed

+664
-30
lines changed

src/eng_back.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,64 @@ EVP_PKEY *ctx_load_privkey(ENGINE_CTX *ctx, const char *s_key_id,
10311031
return PKCS11_get_private_key(key);
10321032
}
10331033

1034+
static int ctx_keygen(ENGINE_CTX *ctx, void *p)
1035+
{
1036+
int rv = 1;
1037+
int i;
1038+
PKCS11_KGEN_ATTRS *kg_attrs = p;
1039+
PKCS11_SLOT* slot = NULL;
1040+
1041+
pthread_mutex_lock(&ctx->lock);
1042+
/* Delayed libp11 initialization */
1043+
if (ctx_init_libp11_unlocked(ctx)) {
1044+
ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_PARAMETER);
1045+
goto done;
1046+
}
1047+
1048+
// Take the first token that has a matching label
1049+
// TODO: make this more intelligent
1050+
for (i = 0; i < ctx->slot_count; ++i) {
1051+
slot = ctx->slot_list + i;
1052+
if (slot && slot->token && slot->token->initialized &&
1053+
slot->token->label &&
1054+
!strncmp(slot->token->label, kg_attrs->token_label, 32)) {
1055+
break;
1056+
}
1057+
}
1058+
1059+
if (i == ctx->slot_count) {
1060+
ctx_log(ctx, 0, "Initialized token with matching label not found...\n");
1061+
goto done;
1062+
}
1063+
1064+
if (!ctx->force_login) {
1065+
ERR_clear_error();
1066+
rv = PKCS11_generate_key(slot->token, kg_attrs);
1067+
if (rv == 0) {
1068+
goto done;
1069+
}
1070+
}
1071+
1072+
// Try with logging in
1073+
ERR_clear_error();
1074+
if (slot->token->loginRequired) {
1075+
if (!ctx_login(ctx, slot, slot->token,
1076+
NULL, NULL)) {
1077+
ctx_log(ctx, 0, "Login to token failed, returning 0...\n");
1078+
rv = 1;
1079+
goto done;
1080+
}
1081+
rv = PKCS11_generate_key(slot->token, kg_attrs);
1082+
if (rv < 0) {
1083+
ctx_log(ctx, 0, "Failed to generate a key pair on the token."
1084+
" Error code: %d\n", rv);
1085+
}
1086+
}
1087+
1088+
done:
1089+
pthread_mutex_unlock(&ctx->lock);
1090+
return rv ? 0 : 1;
1091+
}
10341092
/******************************************************************************/
10351093
/* Engine ctrl request handling */
10361094
/******************************************************************************/
@@ -1149,6 +1207,8 @@ int ctx_engine_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)())
11491207
return ctx_ctrl_force_login(ctx);
11501208
case CMD_RE_ENUMERATE:
11511209
return ctx_enumerate_slots(ctx);
1210+
case CMD_KEYGEN:
1211+
return ctx_keygen(ctx, p);
11521212
default:
11531213
ENGerr(ENG_F_CTX_ENGINE_CTRL, ENG_R_UNKNOWN_COMMAND);
11541214
break;

src/eng_front.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ static const ENGINE_CMD_DEFN engine_cmd_defns[] = {
8080
"RE_ENUMERATE",
8181
"re enumerate slots",
8282
ENGINE_CMD_FLAG_NO_INPUT},
83+
{CMD_KEYGEN,
84+
"KEYGEN",
85+
"Generate asymmetric key pair",
86+
ENGINE_CMD_FLAG_INTERNAL},
8387
{0, NULL, NULL, 0}
8488
};
8589

src/engine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#define CMD_SET_CALLBACK_DATA (ENGINE_CMD_BASE + 8)
5757
#define CMD_FORCE_LOGIN (ENGINE_CMD_BASE+9)
5858
#define CMD_RE_ENUMERATE (ENGINE_CMD_BASE+10)
59+
#define CMD_KEYGEN (ENGINE_CMD_BASE+11)
5960

6061
typedef struct st_engine_ctx ENGINE_CTX; /* opaque */
6162

src/libp11-int.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ extern int ERR_load_CKR_strings(void);
130130
pkcs11_strdup((char *) s, sizeof(s))
131131
extern char *pkcs11_strdup(char *, size_t);
132132

133+
/* Hex to bin */
134+
extern int pkcs11_hex_to_bin(const char *, unsigned char *, size_t *);
135+
133136
/* Emulate the OpenSSL 1.1 getters */
134137
#if OPENSSL_VERSION_NUMBER < 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3000000L )
135138
#define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa)
@@ -319,9 +322,13 @@ extern int pkcs11_generate_random(PKCS11_SLOT_private *, unsigned char *r, unsig
319322
/* Internal implementation of deprecated features */
320323

321324
/* Generate and store a private key on the token */
322-
extern int pkcs11_generate_key(PKCS11_SLOT_private *tpriv,
323-
int algorithm, unsigned int bits,
324-
char *label, unsigned char *id, size_t id_len);
325+
extern int pkcs11_rsa_keygen(PKCS11_SLOT_private *tpriv,
326+
unsigned int bits, char *label, unsigned char* id, size_t id_len);
327+
328+
extern int pkcs11_ec_keygen(PKCS11_SLOT_private *tpriv,
329+
const char *curve , char *label, unsigned char* id, size_t id_len);
330+
331+
/* Internal implementation of deprecated features */
325332

326333
/* Get the RSA key modulus size (in bytes) */
327334
extern int pkcs11_get_key_size(PKCS11_OBJECT_private *);

src/libp11.h

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ typedef struct PKCS11_ctx_st {
106106
void *_private;
107107
} PKCS11_CTX;
108108

109+
typedef struct PKCS11_ec_kgen_st {
110+
const char *curve;
111+
} PKCS11_EC_KGEN;
112+
113+
typedef struct PKCS11_rsa_kgen_st {
114+
unsigned int bits;
115+
} PKCS11_RSA_KGEN;
116+
117+
typedef struct PKCS11_kgen_attrs_st {
118+
int type;
119+
union {
120+
PKCS11_EC_KGEN *ec;
121+
PKCS11_RSA_KGEN *rsa;
122+
} kgen;
123+
char *token_label;
124+
char *key_label;
125+
char *key_id;
126+
} PKCS11_KGEN_ATTRS;
127+
109128
/**
110129
* Create a new libp11 context
111130
*
@@ -394,6 +413,17 @@ extern int PKCS11_store_certificate(PKCS11_TOKEN *token, X509 *x509,
394413
char *label, unsigned char *id, size_t id_len,
395414
PKCS11_CERT **ret_cert);
396415

416+
/**
417+
* Generate key pair on the token
418+
*
419+
* @param token on which the key should be generated
420+
* @param kgen_attrs struct describing key generation (selection of algorithm,
421+
* algorithm parameters...)
422+
* @retval 0 on success
423+
* @retval negative number on error
424+
*/
425+
extern int PKCS11_generate_key(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kgen_attrs);
426+
397427
/* Access the random number generator */
398428
extern int PKCS11_seed_random(PKCS11_SLOT *slot, const unsigned char *s, unsigned int s_len);
399429
extern int PKCS11_generate_random(PKCS11_SLOT *slot, unsigned char *r, unsigned int r_len);
@@ -428,22 +458,6 @@ extern void ERR_load_PKCS11_strings(void);
428458
* duplicate the functionality OpenSSL provides for EVP_PKEY objects
429459
*/
430460

431-
/**
432-
* Generate a private key on the token
433-
*
434-
* @param token token returned by PKCS11_find_token()
435-
* @param algorithm IGNORED (still here for backward compatibility)
436-
* @param bits size of the modulus in bits
437-
* @param label label for this key
438-
* @param id bytes to use as the id value
439-
* @param id_len length of the id value
440-
* @retval 0 success
441-
* @retval -1 error
442-
*/
443-
extern int PKCS11_generate_key(PKCS11_TOKEN *token,
444-
int algorithm, unsigned int bits,
445-
char *label, unsigned char *id, size_t id_len);
446-
447461
/* Get the RSA key modulus size (in bytes) */
448462
extern int PKCS11_get_key_size(PKCS11_KEY *);
449463

src/p11_front.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1717
*/
1818

19+
#include <string.h>
20+
1921
#include "libp11-int.h"
2022

2123
/* The following exported functions are *not* implemented here:
@@ -399,18 +401,34 @@ int PKCS11_set_ui_method(PKCS11_CTX *pctx, UI_METHOD *ui_method, void *ui_user_d
399401
return pkcs11_set_ui_method(ctx, ui_method, ui_user_data);
400402
}
401403

402-
/* External interface to the deprecated features */
403-
404-
int PKCS11_generate_key(PKCS11_TOKEN *token,
405-
int algorithm, unsigned int bits,
406-
char *label, unsigned char *id, size_t id_len)
404+
int PKCS11_generate_key(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg)
407405
{
408406
PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
409407
if (check_slot_fork(slot) < 0)
410408
return -1;
411-
return pkcs11_generate_key(slot, algorithm, bits, label, id, id_len);
409+
unsigned char out[128] = {0};
410+
size_t key_id_len = 0;
411+
if (kg && kg->key_id) {
412+
key_id_len = strlen(kg->key_id);
413+
if (key_id_len > 127) {
414+
return -2;
415+
}
416+
pkcs11_hex_to_bin(kg->key_id, out, &key_id_len);
417+
}
418+
switch(kg->type) {
419+
case EVP_PKEY_RSA:
420+
return pkcs11_rsa_keygen(slot, kg->kgen.rsa->bits,
421+
kg->key_label, out, key_id_len);
422+
case EVP_PKEY_EC:
423+
return pkcs11_ec_keygen(slot, kg->kgen.ec->curve,
424+
kg->key_label, out, key_id_len);
425+
default:
426+
return -3;
427+
}
412428
}
413429

430+
/* External interface to the deprecated features */
431+
414432
int PKCS11_get_key_size(PKCS11_KEY *pkey)
415433
{
416434
PKCS11_OBJECT_private *key = PRIVKEY(pkey);

src/p11_key.c

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ int pkcs11_reload_object(PKCS11_OBJECT_private *obj)
258258
/**
259259
* Generate a key pair directly on token
260260
*/
261-
int pkcs11_generate_key(PKCS11_SLOT_private *slot, int algorithm, unsigned int bits,
261+
int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits,
262262
char *label, unsigned char *id, size_t id_len) {
263263

264264
PKCS11_CTX_private *ctx = slot->ctx;
@@ -272,10 +272,8 @@ int pkcs11_generate_key(PKCS11_SLOT_private *slot, int algorithm, unsigned int b
272272
CK_OBJECT_HANDLE pub_key_obj, priv_key_obj;
273273
int rv;
274274

275-
(void)algorithm; /* squash the unused parameter warning */
276-
277275
if (pkcs11_get_session(slot, 1, &session))
278-
return -1;
276+
return -10;
279277

280278
/* pubkey attributes */
281279
pkcs11_addattr(&pubtmpl, CKA_ID, id, id_len);
@@ -316,6 +314,94 @@ int pkcs11_generate_key(PKCS11_SLOT_private *slot, int algorithm, unsigned int b
316314
return 0;
317315
}
318316

317+
int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve,
318+
char *label, unsigned char *id, size_t id_len)
319+
{
320+
PKCS11_CTX_private *ctx = slot->ctx;
321+
CK_SESSION_HANDLE session;
322+
PKCS11_TEMPLATE pubtmpl = {0}, privtmpl = {0};
323+
CK_MECHANISM mechanism = {
324+
CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
325+
};
326+
327+
CK_OBJECT_HANDLE pub_key_obj, priv_key_obj;
328+
int rv;
329+
330+
unsigned char *ecdsa_params = NULL;
331+
int ecdsa_params_len = 0;
332+
unsigned char *tmp = NULL;
333+
ASN1_OBJECT *curve_obj = NULL;
334+
int curve_nid = NID_undef;
335+
336+
if (pkcs11_get_session(slot, 1, &session)) {
337+
return -20;
338+
}
339+
340+
curve_nid = EC_curve_nist2nid(curve);
341+
if (curve_nid == NID_undef)
342+
curve_nid = OBJ_sn2nid(curve);
343+
if (curve_nid == NID_undef)
344+
curve_nid = OBJ_ln2nid(curve);
345+
if (curve_nid == NID_undef)
346+
return -21;
347+
348+
curve_obj = OBJ_nid2obj(curve_nid);
349+
if (!curve_obj)
350+
return -22;
351+
ecdsa_params_len = i2d_ASN1_OBJECT(curve_obj, NULL);
352+
ecdsa_params = (unsigned char *)OPENSSL_malloc(ecdsa_params_len);
353+
if (!ecdsa_params)
354+
return -23;
355+
tmp = ecdsa_params;
356+
i2d_ASN1_OBJECT(curve_obj, &tmp);
357+
358+
/* pubkey attributes */
359+
pkcs11_addattr(&pubtmpl, CKA_ID, id, id_len);
360+
if (label)
361+
pkcs11_addattr_s(&pubtmpl, CKA_LABEL, label);
362+
pkcs11_addattr_bool(&pubtmpl, CKA_TOKEN, TRUE);
363+
pkcs11_addattr_bool(&pubtmpl, CKA_DERIVE, TRUE);
364+
pkcs11_addattr_bool(&pubtmpl, CKA_WRAP, FALSE);
365+
pkcs11_addattr_bool(&pubtmpl, CKA_VERIFY, TRUE);
366+
pkcs11_addattr_bool(&pubtmpl, CKA_VERIFY_RECOVER, FALSE);
367+
pkcs11_addattr_bool(&pubtmpl, CKA_ENCRYPT, FALSE);
368+
pkcs11_addattr(&pubtmpl, CKA_ECDSA_PARAMS, ecdsa_params, ecdsa_params_len);
369+
370+
/* privkey attributes */
371+
pkcs11_addattr(&privtmpl, CKA_ID, id, id_len);
372+
if (label)
373+
pkcs11_addattr_s(&privtmpl, CKA_LABEL, label);
374+
pkcs11_addattr_bool(&privtmpl, CKA_TOKEN, TRUE);
375+
pkcs11_addattr_bool(&privtmpl, CKA_PRIVATE, TRUE);
376+
pkcs11_addattr_bool(&privtmpl, CKA_SENSITIVE, TRUE);
377+
pkcs11_addattr_bool(&privtmpl, CKA_DERIVE, TRUE);
378+
pkcs11_addattr_bool(&privtmpl, CKA_UNWRAP, FALSE);
379+
pkcs11_addattr_bool(&privtmpl, CKA_SIGN, TRUE);
380+
pkcs11_addattr_bool(&privtmpl, CKA_DECRYPT, FALSE);
381+
382+
/* call the pkcs11 module to create the key pair */
383+
rv = CRYPTOKI_call(ctx, C_GenerateKeyPair(
384+
session,
385+
&mechanism,
386+
pubtmpl.attrs,
387+
pubtmpl.nattr,
388+
privtmpl.attrs,
389+
privtmpl.nattr,
390+
&pub_key_obj,
391+
&priv_key_obj
392+
));
393+
394+
pkcs11_put_session(slot, session);
395+
396+
/* zap all memory allocated when building the template */
397+
pkcs11_zap_attrs(&privtmpl);
398+
pkcs11_zap_attrs(&pubtmpl);
399+
OPENSSL_free(ecdsa_params);
400+
401+
CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv);
402+
return 0;
403+
}
404+
319405
/*
320406
* Store a private key on the token
321407
*/

0 commit comments

Comments
 (0)