Skip to content

Commit c315280

Browse files
Rafael Junio da Cruzmtrojnar
authored andcommitted
Introduce generic keypair generation interface and engine ctrl command
As discussed in #379 and #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: #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. It also possible to configure CKA_SENSITIVE and CKA_EXTRACTABLE key attributes. 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: #379 and reworked to compile and work with some new additions to libp11 i.e. templates.
1 parent b025351 commit c315280

17 files changed

+887
-38
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ tests/fork-change-slot-prov
8181
tests/rsa-oaep-prov
8282
tests/rsa-pss-sign-prov
8383
tests/store-cert-prov
84+
tests/rsa-keygen
85+
tests/ec-keygen
8486

8587
tests/*.log
8688
tests/*.trs

src/eng_back.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,43 @@ static int ENGINE_CTX_ctrl_set_vlog(ENGINE_CTX *ctx, void *cb)
257257
return 1;
258258
}
259259

260-
int ENGINE_CTX_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)(void))
260+
static int ENGINE_CTX_keygen(ENGINE_CTX *ctx, void *p)
261+
{
262+
int rv;
263+
PKCS11_KGEN_ATTRS *kg_attrs = p;
264+
PKCS11_SLOT* found_slot = NULL;
265+
266+
if (kg_attrs == NULL)
267+
return 0;
268+
269+
/* Delayed libp11 initialization */
270+
if (UTIL_CTX_init_libp11(ctx->util_ctx)) {
271+
ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_PARAMETER);
272+
return 0;
273+
}
274+
275+
found_slot = UTIL_CTX_find_token(ctx->util_ctx, kg_attrs->token_label);
276+
if (!found_slot)
277+
return 0;
278+
279+
/* Try logging in */
280+
ERR_clear_error();
281+
if (!(found_slot->token->loginRequired && UTIL_CTX_login(ctx->util_ctx,
282+
found_slot, ctx->ui_method, ctx->ui_data)))
283+
return 0;
284+
285+
rv = PKCS11_keygen(found_slot->token, kg_attrs);
286+
if (rv < 0) {
287+
ENGINE_CTX_log(ctx, LOG_ERR,
288+
"Failed to generate a key pair on the token. Error code: %d\n",
289+
rv);
290+
return 0;
291+
}
292+
293+
return 1;
294+
}
295+
296+
int ENGINE_CTX_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)())
261297
{
262298
(void)i; /* We don't currently take integer parameters */
263299
(void)f; /* We don't currently take callback parameters */
@@ -293,6 +329,8 @@ int ENGINE_CTX_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)(void))
293329
return ENGINE_CTX_ctrl_set_vlog(ctx, p);
294330
case CMD_DEBUG_LEVEL:
295331
return ENGINE_CTX_ctrl_set_debug_level(ctx, (int)i);
332+
case CMD_KEYGEN:
333+
return ENGINE_CTX_keygen(ctx, p);
296334
default:
297335
ENGerr(ENG_F_CTX_ENGINE_CTRL, ENG_R_UNKNOWN_COMMAND);
298336
break;

src/eng_front.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ static const ENGINE_CMD_DEFN engine_cmd_defns[] = {
8888
"DEBUG_LEVEL",
8989
"Set the debug level: 0=emerg, 1=alert, 2=crit, 3=err, 4=warning, 5=notice (default), 6=info, 7=debug",
9090
ENGINE_CMD_FLAG_NUMERIC},
91+
{CMD_KEYGEN,
92+
"KEYGEN",
93+
"Generate asymmetric key pair",
94+
ENGINE_CMD_FLAG_INTERNAL},
9195
{0, NULL, NULL, 0}
9296
};
9397

src/engine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#define CMD_RE_ENUMERATE (ENGINE_CMD_BASE + 10)
6969
#define CMD_VLOG_A (ENGINE_CMD_BASE + 11)
7070
#define CMD_DEBUG_LEVEL (ENGINE_CMD_BASE + 12)
71+
#define CMD_KEYGEN (ENGINE_CMD_BASE + 13)
7172

7273
typedef struct engine_ctx_st ENGINE_CTX; /* opaque */
7374

src/libp11-int.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,13 @@ extern int pkcs11_generate_random(PKCS11_SLOT_private *, unsigned char *r, unsig
332332
/* Internal implementation of deprecated features */
333333

334334
/* Generate and store a private key on the token */
335-
extern int pkcs11_generate_key(PKCS11_SLOT_private *tpriv,
336-
int algorithm, unsigned int bits,
337-
char *label, unsigned char *id, size_t id_len);
335+
extern int pkcs11_rsa_keygen(PKCS11_SLOT_private *tpriv,
336+
unsigned int bits, const char *label, const unsigned char *id,
337+
size_t id_len, const PKCS11_params* params);
338+
339+
extern int pkcs11_ec_keygen(PKCS11_SLOT_private *tpriv,
340+
const char *curve , const char *label, const unsigned char *id,
341+
size_t id_len, const PKCS11_params* params);
338342

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

src/libp11.exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ ERR_load_PKCS11_strings
5252
PKCS11_set_ui_method
5353
ERR_get_CKR_code
5454
PKCS11_set_vlog_a_method
55+
PKCS11_keygen

src/libp11.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,35 @@ 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_params {
118+
unsigned char extractable;
119+
unsigned char sensitive;
120+
} PKCS11_params;
121+
122+
typedef struct PKCS11_kgen_attrs_st {
123+
/* Key generation type from OpenSSL. Given the union below this should
124+
* be either EVP_PKEY_EC or EVP_PKEY_RSA
125+
*/
126+
int type;
127+
union {
128+
PKCS11_EC_KGEN *ec;
129+
PKCS11_RSA_KGEN *rsa;
130+
} kgen;
131+
const char *token_label;
132+
const char *key_label;
133+
const unsigned char *key_id;
134+
size_t id_len;
135+
const PKCS11_params *key_params;
136+
} PKCS11_KGEN_ATTRS;
137+
109138
/** PKCS11 ASCII logging callback */
110139
typedef void (*PKCS11_VLOG_A_CB)(int, const char *, va_list);
111140

@@ -431,20 +460,31 @@ extern void ERR_load_PKCS11_strings(void);
431460
* duplicate the functionality OpenSSL provides for EVP_PKEY objects
432461
*/
433462

463+
/**
464+
* Generate key pair on the token
465+
*
466+
* @param token on which the key should be generated
467+
* @param kgen_attrs struct describing key generation (selection of algorithm,
468+
* algorithm parameters...)
469+
* @retval 0 on success
470+
* @retval -1 error
471+
*/
472+
extern int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kgen_attrs);
473+
434474
/**
435475
* Generate a private key on the token
436476
*
437477
* @param token token returned by PKCS11_find_token()
438-
* @param algorithm IGNORED (still here for backward compatibility)
439-
* @param bits size of the modulus in bits
478+
* @param algorithm EVP_PKEY_EC any other value select EVP_PKEY_RSA
479+
* @param bits_or_nid size of the modulus in bits or the nid of the curve
440480
* @param label label for this key
441481
* @param id bytes to use as the id value
442482
* @param id_len length of the id value
443483
* @retval 0 success
444484
* @retval -1 error
445485
*/
446486
extern int PKCS11_generate_key(PKCS11_TOKEN *token,
447-
int algorithm, unsigned int bits,
487+
int algorithm, unsigned int bits_or_nid,
448488
char *label, unsigned char *id, size_t id_len);
449489

450490
/* Get the RSA key modulus size (in bytes) */

src/p11_front.c

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
* License along with this library; if not, write to the Free Software
1616
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1717
*/
18+
#include <openssl/objects.h>
1819

1920
#include "libp11-int.h"
2021

22+
/* The maximum length of PIN */
23+
#define MAX_PIN_LENGTH 256
24+
2125
/* The following exported functions are *not* implemented here:
2226
* PKCS11_get_rsa_method
2327
* PKCS11_get_ecdsa_method
@@ -401,14 +405,63 @@ int PKCS11_set_ui_method(PKCS11_CTX *pctx, UI_METHOD *ui_method, void *ui_user_d
401405

402406
/* External interface to the deprecated features */
403407

404-
int PKCS11_generate_key(PKCS11_TOKEN *token,
405-
int algorithm, unsigned int bits,
406-
char *label, unsigned char *id, size_t id_len)
408+
int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg)
407409
{
410+
if (token == NULL || kg == NULL || kg->id_len > MAX_PIN_LENGTH)
411+
return -1;
408412
PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
409413
if (check_slot_fork(slot) < 0)
410414
return -1;
411-
return pkcs11_generate_key(slot, algorithm, bits, label, id, id_len);
415+
416+
switch(kg->type) {
417+
case EVP_PKEY_RSA:
418+
return pkcs11_rsa_keygen(slot, kg->kgen.rsa->bits,
419+
kg->key_label, kg->key_id, kg->id_len, kg->key_params);
420+
case EVP_PKEY_EC:
421+
return pkcs11_ec_keygen(slot, kg->kgen.ec->curve,
422+
kg->key_label, kg->key_id, kg->id_len, kg->key_params);
423+
default:
424+
return -1;
425+
}
426+
}
427+
428+
int PKCS11_generate_key(PKCS11_TOKEN *token,
429+
int algorithm, unsigned int bits_or_nid,
430+
char *label, unsigned char *id, size_t id_len)
431+
{
432+
PKCS11_params key_params = { .extractable = 0, .sensitive = 1 };
433+
PKCS11_EC_KGEN ec_kgen;
434+
PKCS11_RSA_KGEN rsa_kgen;
435+
PKCS11_KGEN_ATTRS kgen_attrs = { 0 };
436+
437+
switch (algorithm) {
438+
case EVP_PKEY_EC:
439+
ec_kgen.curve = OBJ_nid2sn(bits_or_nid);
440+
kgen_attrs = (PKCS11_KGEN_ATTRS){
441+
.type = EVP_PKEY_EC,
442+
.kgen.ec = &ec_kgen,
443+
.token_label = (const char *)token->label,
444+
.key_label = label,
445+
.key_id = (const unsigned char *)id,
446+
.id_len = id_len,
447+
.key_params = &key_params
448+
};
449+
break;
450+
451+
default:
452+
rsa_kgen.bits = bits_or_nid;
453+
kgen_attrs = (PKCS11_KGEN_ATTRS){
454+
.type = EVP_PKEY_RSA,
455+
.kgen.rsa = &rsa_kgen,
456+
.token_label = (const char *)token->label,
457+
.key_label = label,
458+
.key_id = (const unsigned char *)id,
459+
.id_len = id_len,
460+
.key_params = &key_params
461+
};
462+
}
463+
464+
return PKCS11_keygen(token, &kgen_attrs);
412465
}
413466

414467
int PKCS11_get_key_size(PKCS11_KEY *pkey)

0 commit comments

Comments
 (0)