1 /* -*- mode: c; c-file-style:"stroustrup"; -*- */
2
3 /*
4 * Copyright (c) 2018 Mastercard
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #include <search.h>
26 #include <assert.h>
27 #include <openssl/objects.h>
28 #include "pkcs11lib.h"
29
30 /***********************************************************************/
31 /* keys can be created either as token keys (permanent), */
32 /* or as wrappable keys, in which case they are session keys and have */
33 /* CKA_EXTRACTABLE set to true */
34 /* this is reflected by the key_generation_t argument: */
35 /* - when kg_token, the key is a token key */
36 /* - when kg_session_for_wrapping, it is a session key, for wrapping */
37 /***********************************************************************/
38
compare_CKA(const void * a,const void * b)39 static int compare_CKA( const void *a, const void *b)
40 {
41 return ((CK_ATTRIBUTE_PTR)a)->type == ((CK_ATTRIBUTE_PTR)b)->type ? 0 : -1;
42 }
43
has_extractable(CK_ATTRIBUTE_PTR template,CK_ULONG template_len)44 static CK_BBOOL has_extractable(CK_ATTRIBUTE_PTR template, CK_ULONG template_len)
45 {
46 CK_ATTRIBUTE extractable[] = {
47 { CKA_EXTRACTABLE, NULL, 0L }
48 };
49
50 size_t len = (size_t) template_len;
51
52 CK_ATTRIBUTE_PTR match = lfind( &extractable[0],
53 template,
54 &len,
55 sizeof(CK_ATTRIBUTE),
56 compare_CKA );
57 return match ? *(CK_BBOOL *)match->pValue : CK_FALSE;
58 }
59
60
pkcs11_genAES(pkcs11Context * p11ctx,char * label,CK_ULONG bits,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR seckhandleptr,key_generation_t gentype)61 func_rc pkcs11_genAES( pkcs11Context * p11ctx,
62 char *label,
63 CK_ULONG bits,
64 CK_ATTRIBUTE attrs[],
65 CK_ULONG numattrs,
66 CK_OBJECT_HANDLE_PTR seckhandleptr,
67 key_generation_t gentype)
68 {
69 func_rc rc = rc_ok;
70 CK_RV retcode;
71 CK_BBOOL ck_false = CK_FALSE;
72 CK_BBOOL ck_true = CK_TRUE;
73 CK_BYTE id[16];
74 CK_ULONG bytes;
75 CK_MECHANISM mechanism = {
76 CKM_AES_KEY_GEN, NULL_PTR, 0
77 };
78
79 if(bits != 128 && bits !=256 && bits!=192) {
80 fprintf(stderr,"***Error: invalid key length: %d\n", (int)bits);
81 rc = rc_error_invalid_parameter_for_method;
82 goto error;
83 }
84
85 bytes = bits>>3;
86
87 snprintf((char *)id, sizeof id, "aes%d-%ld", (int)bits, time(NULL));
88
89 {
90 int i;
91
92 CK_ATTRIBUTE secktemplate[] = {
93 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof(CK_BBOOL)},
94 {CKA_PRIVATE, &ck_true, sizeof ck_true},
95 {CKA_VALUE_LEN, &bytes, sizeof(bytes)},
96 {CKA_LABEL, label, strlen(label) },
97 {CKA_ID, id, strlen((const char *)id) },
98 /* what can we do with this key */
99 {CKA_ENCRYPT, &ck_false, sizeof ck_false},
100 {CKA_DECRYPT, &ck_false, sizeof ck_false},
101 {CKA_SIGN, &ck_false, sizeof ck_false},
102 {CKA_VERIFY, &ck_false, sizeof ck_false},
103 {CKA_WRAP, &ck_false, sizeof ck_false},
104 {CKA_UNWRAP, &ck_false, sizeof ck_false},
105 {CKA_DERIVE, &ck_false, sizeof ck_false},
106 {CKA_SENSITIVE, &ck_true, sizeof ck_true},
107 {CKA_EXTRACTABLE, gentype != kg_token ? &ck_true : &ck_false, sizeof ck_false},
108 /* leave room for up to 5 additional attributes */
109 {0L, NULL, 0L},
110 {0L, NULL, 0L},
111 {0L, NULL, 0L},
112 {0L, NULL, 0L},
113 {0L, NULL, 0L},
114 };
115
116 size_t template_len_max = (sizeof(secktemplate)/sizeof(CK_ATTRIBUTE));
117 size_t template_len_min = template_len_max - 5;
118 size_t num_elems = template_len_min;
119
120 for(i=0; i<numattrs && num_elems<template_len_max; i++)
121 {
122 /* lsearch will add the keys if not found in the template */
123
124 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
125 secktemplate,
126 &num_elems,
127 sizeof(CK_ATTRIBUTE),
128 compare_CKA );
129
130 /* if we have a match, take the value from the command line */
131 /* we are basically stealing the pointer from attrs array */
132 if(match && match->ulValueLen == attrs[i].ulValueLen) {
133 match->pValue = attrs[i].pValue;
134 }
135 }
136
137 retcode = p11ctx->FunctionList.C_GenerateKey(p11ctx->Session,
138 &mechanism,
139 secktemplate, num_elems,
140 seckhandleptr );
141
142 if (retcode != CKR_OK ) {
143 pkcs11_error( retcode, "C_GenerateKey" );
144 rc = rc_error_pkcs11_api;
145 goto error;
146 }
147
148 /* special case: we want to keep a local copy of the wrapped key */
149 if(gentype==kg_token_for_wrapping) {
150 CK_OBJECT_HANDLE copyhandle=0;
151 /* we don't want an extractable key, unless specified as an attribute */
152 /* when invoking the command */
153 CK_BBOOL ck_extractable = has_extractable(attrs, numattrs);
154
155 CK_ATTRIBUTE tokentemplate[] = {
156 { CKA_TOKEN, &ck_true, sizeof ck_true },
157 { CKA_EXTRACTABLE, &ck_extractable, sizeof ck_extractable }
158 };
159
160 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
161 *seckhandleptr,
162 tokentemplate,
163 sizeof tokentemplate / sizeof(CK_ATTRIBUTE),
164 ©handle );
165 if (retcode != CKR_OK ) {
166 pkcs11_warning( retcode, "C_CopyObject" );
167 fprintf(stderr, "***Warning: could not create a local copy for secret key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
168 }
169 }
170 }
171 error:
172 return rc;
173 }
174
pkcs11_genDESX(pkcs11Context * p11ctx,char * label,CK_ULONG bits,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR seckhandleptr,key_generation_t gentype)175 func_rc pkcs11_genDESX( pkcs11Context * p11ctx,
176 char *label,
177 CK_ULONG bits,
178 CK_ATTRIBUTE attrs[],
179 CK_ULONG numattrs,
180 CK_OBJECT_HANDLE_PTR seckhandleptr,
181 key_generation_t gentype)
182 {
183 func_rc rc = rc_ok;
184 CK_RV retcode;
185 CK_BBOOL ck_false = CK_FALSE;
186 CK_BBOOL ck_true = CK_TRUE;
187 CK_BYTE id[16];
188 CK_MECHANISM mechanism = {
189 CKM_DES_KEY_GEN, NULL_PTR, 0
190 };
191
192 switch(bits) {
193
194 case 64:
195 mechanism.mechanism = CKM_DES_KEY_GEN;
196 break;
197
198 case 128:
199 mechanism.mechanism = CKM_DES2_KEY_GEN;
200 break;
201
202 case 192:
203 mechanism.mechanism = CKM_DES3_KEY_GEN;
204 break;
205
206 default:
207 fprintf(stderr,"***Error: invalid key length: %d\n", (int)bits);
208 rc = rc_error_invalid_parameter_for_method;
209 goto error;
210 }
211
212 snprintf((char *)id, sizeof id, "des%d-%ld", (int)bits, time(NULL));
213
214 {
215 int i;
216
217 CK_ATTRIBUTE secktemplate[] = {
218 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof(CK_BBOOL)},
219 /* CKA_VALUE_LEN is never specified for DES keys, implicit with key type */
220 {CKA_LABEL, label, strlen(label) },
221 {CKA_ID, id, strlen((const char *)id) },
222 /* what can we do with this key */
223 {CKA_ENCRYPT, &ck_false, sizeof ck_false},
224 {CKA_DECRYPT, &ck_false, sizeof ck_false},
225 {CKA_SIGN, &ck_false, sizeof ck_false},
226 {CKA_VERIFY, &ck_false, sizeof ck_false},
227 {CKA_WRAP, &ck_false, sizeof ck_false},
228 {CKA_UNWRAP, &ck_false, sizeof ck_false},
229 {CKA_DERIVE, &ck_false, sizeof ck_false},
230 {CKA_SENSITIVE, &ck_true, sizeof ck_true},
231 {CKA_EXTRACTABLE, gentype != kg_token ? &ck_true : &ck_false, sizeof ck_false},
232 /* leave room for up to 5 additional attributes */
233 {0L, NULL, 0L},
234 {0L, NULL, 0L},
235 {0L, NULL, 0L},
236 {0L, NULL, 0L},
237 {0L, NULL, 0L},
238 };
239
240 size_t template_len_max = (sizeof(secktemplate)/sizeof(CK_ATTRIBUTE));
241 size_t template_len_min = template_len_max - 5;
242 size_t num_elems = template_len_min;
243
244 for(i=0; i<numattrs && num_elems<template_len_max; i++)
245 {
246 /* lsearch will add the keys if not found in the template */
247
248 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
249 secktemplate,
250 &num_elems,
251 sizeof(CK_ATTRIBUTE),
252 compare_CKA );
253
254 /* if we have a match, take the value from the command line */
255 /* we are basically stealing the pointer from attrs array */
256 if(match && match->ulValueLen == attrs[i].ulValueLen) {
257 match->pValue = attrs[i].pValue;
258 }
259 }
260
261 retcode = p11ctx->FunctionList.C_GenerateKey(p11ctx->Session,
262 &mechanism,
263 secktemplate, num_elems,
264 seckhandleptr );
265
266 if (retcode != CKR_OK ) {
267 pkcs11_error( retcode, "C_GenerateKey" );
268 rc = rc_error_pkcs11_api;
269 goto error;
270 }
271
272 /* special case: we want to keep a local copy of the wrapped key */
273 if(gentype==kg_token_for_wrapping) {
274 CK_OBJECT_HANDLE copyhandle=0;
275 /* we don't want an extractable key, unless specified as an attribute */
276 /* when invoking the command */
277 CK_BBOOL ck_extractable = has_extractable(attrs, numattrs);
278
279 CK_ATTRIBUTE tokentemplate[] = {
280 { CKA_TOKEN, &ck_true, sizeof ck_true },
281 { CKA_EXTRACTABLE, &ck_extractable, sizeof ck_extractable }
282 };
283
284 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
285 *seckhandleptr,
286 tokentemplate,
287 sizeof tokentemplate / sizeof(CK_ATTRIBUTE),
288 ©handle );
289 if (retcode != CKR_OK ) {
290 pkcs11_warning( retcode, "C_CopyObject" );
291 fprintf(stderr, "***Warning: could not create a local copy for secret key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
292 }
293 }
294 }
295 error:
296 return rc;
297 }
298
299 /* Generate Generic/HMAC keys */
300 /* PKCS#11 standard is somewhat flawed, as it specifies that keys used for HMAC */
301 /* should be generic keys, which normally support only key derivation mechanism */
302 /* however, HMAC requires signature/verification */
303 /* to accomodate this contradiction, each vendor has its specific way: */
304 /* NSS allows generic keys to perform signature/verification */
305 /* nCipher has vendor-defined HMAC key generation methods */
306 /* this routine attempts to accomodate for these two implementations */
307
pkcs11_genGeneric(pkcs11Context * p11ctx,char * label,key_type_t kt,CK_ULONG bits,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR seckhandleptr,key_generation_t gentype)308 func_rc pkcs11_genGeneric( pkcs11Context * p11ctx,
309 char *label,
310 key_type_t kt,
311 CK_ULONG bits,
312 CK_ATTRIBUTE attrs[],
313 CK_ULONG numattrs,
314 CK_OBJECT_HANDLE_PTR seckhandleptr,
315 key_generation_t gentype)
316 {
317 func_rc rc = rc_ok;
318 CK_RV retcode;
319 CK_BBOOL ck_false = CK_FALSE;
320 CK_BBOOL ck_true = CK_TRUE;
321 CK_BYTE id[16];
322 CK_ULONG bytes;
323 CK_MECHANISM mechanism = {
324 0, NULL_PTR, 0
325 };
326
327 if(bits <= 56 ) {
328 fprintf(stderr,"***Error: insecure generic key length (%d)\n", (int)bits);
329 rc = rc_error_insecure;
330 goto error;
331 }
332
333 if( bits %8 ) {
334 fprintf(stderr, "***Warning: requested length (%d) is rounded up to (%d)\n", (int)bits, (int) (((bits>>3)+1)<<3) ) ;
335 }
336
337 /* we round up to the next byte boundary. */
338 bytes = (bits>>3) + ( (bits%8) ? 1 : 0 );
339
340 snprintf((char *)id, sizeof id, "gen%d-%ld", (int)bits, time(NULL));
341
342 /* choose key generation algorithm */
343 switch(kt) {
344 case generic:
345 mechanism.mechanism = CKM_GENERIC_SECRET_KEY_GEN;
346 break;
347
348 #if defined(HAVE_NCIPHER)
349 case hmacsha1: /* nCipher-specific */
350 mechanism.mechanism = CKM_NC_SHA_1_HMAC_KEY_GEN;
351 break;
352
353 case hmacsha224:
354 mechanism.mechanism = CKM_NC_SHA224_HMAC_KEY_GEN;
355 break;
356
357 case hmacsha256:
358 mechanism.mechanism = CKM_NC_SHA256_HMAC_KEY_GEN;
359 break;
360
361 case hmacsha384:
362 mechanism.mechanism = CKM_NC_SHA384_HMAC_KEY_GEN;
363 break;
364
365 case hmacsha512:
366 mechanism.mechanism = CKM_NC_SHA512_HMAC_KEY_GEN;
367 break;
368 #endif
369
370 default:
371 fprintf(stderr,"***Error: illegal key generation mechanism specified\n");
372 rc = rc_error_invalid_parameter_for_method;
373 goto error;
374 }
375
376 {
377 int i;
378
379 CK_ATTRIBUTE secktemplate[] = {
380 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof(CK_BBOOL)},
381 {CKA_VALUE_LEN, &bytes, sizeof(bytes)},
382
383 {CKA_LABEL, label, strlen(label) },
384 {CKA_ID, id, strlen((const char *)id) },
385 /* what can we do with this key */
386 {CKA_ENCRYPT, &ck_false, sizeof ck_false},
387 {CKA_DECRYPT, &ck_false, sizeof ck_false},
388 {CKA_SIGN, &ck_false, sizeof ck_false},
389 {CKA_VERIFY, &ck_false, sizeof ck_false},
390 {CKA_WRAP, &ck_false, sizeof ck_false},
391 {CKA_UNWRAP, &ck_false, sizeof ck_false},
392 {CKA_DERIVE, &ck_false, sizeof ck_false},
393 {CKA_SENSITIVE, &ck_true, sizeof ck_true},
394 {CKA_EXTRACTABLE, gentype != kg_token ? &ck_true : &ck_false, sizeof ck_false},
395 /* leave room for up to 5 additional attributes */
396 {0L, NULL, 0L},
397 {0L, NULL, 0L},
398 {0L, NULL, 0L},
399 {0L, NULL, 0L},
400 {0L, NULL, 0L},
401 };
402
403 size_t template_len_max = (sizeof(secktemplate)/sizeof(CK_ATTRIBUTE));
404 size_t template_len_min = template_len_max - 5;
405 size_t num_elems = template_len_min;
406
407 for(i=0; i<numattrs && num_elems<template_len_max; i++)
408 {
409 /* lsearch will add the keys if not found in the template */
410
411 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
412 secktemplate,
413 &num_elems,
414 sizeof(CK_ATTRIBUTE),
415 compare_CKA );
416
417 /* if we have a match, take the value from the command line */
418 /* we are basically stealing the pointer from attrs array */
419 if(match && match->ulValueLen == attrs[i].ulValueLen) {
420 match->pValue = attrs[i].pValue;
421 }
422 }
423
424 retcode = p11ctx->FunctionList.C_GenerateKey(p11ctx->Session,
425 &mechanism,
426 secktemplate, num_elems,
427 seckhandleptr );
428
429 if (retcode != CKR_OK ) {
430 pkcs11_error( retcode, "C_GenerateKey" );
431 rc = rc_error_pkcs11_api;
432 }
433
434 /* special case: we want to keep a local copy of the wrapped key */
435 if(gentype==kg_token_for_wrapping) {
436 CK_OBJECT_HANDLE copyhandle=0;
437 /* we don't want an extractable key, unless specified as an attribute */
438 /* when invoking the command */
439 CK_BBOOL ck_extractable = has_extractable(attrs, numattrs);
440
441 CK_ATTRIBUTE tokentemplate[] = {
442 { CKA_TOKEN, &ck_true, sizeof ck_true },
443 { CKA_EXTRACTABLE, &ck_extractable, sizeof ck_extractable }
444 };
445
446 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
447 *seckhandleptr,
448 tokentemplate,
449 sizeof tokentemplate / sizeof(CK_ATTRIBUTE),
450 ©handle );
451 if (retcode != CKR_OK ) {
452 pkcs11_warning( retcode, "C_CopyObject" );
453 fprintf(stderr, "***Warning: could not create a local copy for secret key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
454 }
455 }
456 }
457 error:
458 return rc;
459 }
460
461
pkcs11_genRSA(pkcs11Context * p11ctx,char * label,CK_ULONG bits,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR pubkhandleptr,CK_OBJECT_HANDLE_PTR prvkhandleptr,key_generation_t gentype)462 func_rc pkcs11_genRSA( pkcs11Context * p11ctx,
463 char *label,
464 CK_ULONG bits,
465 CK_ATTRIBUTE attrs[],
466 CK_ULONG numattrs,
467 CK_OBJECT_HANDLE_PTR pubkhandleptr,
468 CK_OBJECT_HANDLE_PTR prvkhandleptr,
469 key_generation_t gentype)
470 {
471 func_rc rc = rc_ok;
472 CK_RV retcode;
473 int i;
474 CK_BBOOL ck_false = CK_FALSE;
475 CK_BBOOL ck_true = CK_TRUE;
476 CK_ULONG modulusBits = bits;
477 CK_BYTE publicExponent[] = { 0x01, 0x00, 0x01 };
478
479 CK_MECHANISM mechanism = {
480 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
481 };
482
483 CK_BYTE id[32];
484 snprintf((char *)id, sizeof id, "rsa%d-%ld", (int)bits, time(NULL));
485
486 {
487 CK_ATTRIBUTE pubktemplate[] = {
488 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof(CK_BBOOL)},
489 {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
490 {CKA_PUBLIC_EXPONENT, publicExponent, sizeof (publicExponent)},
491
492 {CKA_LABEL, label, strlen(label) },
493 {CKA_ID, id, strlen((const char *)id) },
494 /* what can we do with this key */
495 {CKA_ENCRYPT, &ck_false, sizeof ck_false},
496 {CKA_WRAP, &ck_false, sizeof ck_false},
497 {CKA_VERIFY, &ck_false, sizeof ck_false},
498 {CKA_VERIFY_RECOVER, &ck_false, sizeof ck_false},
499 {CKA_DERIVE, &ck_false, sizeof ck_false},
500 /* leave room for up to 5 additional attributes */
501 {0L, NULL, 0L},
502 {0L, NULL, 0L},
503 {0L, NULL, 0L},
504 {0L, NULL, 0L},
505 {0L, NULL, 0L},
506 };
507
508 size_t pubk_template_len_max = (sizeof(pubktemplate)/sizeof(CK_ATTRIBUTE));
509 size_t pubk_template_len_min = pubk_template_len_max - 5;
510 size_t pubk_num_elems = pubk_template_len_min;
511
512
513 CK_ATTRIBUTE prvktemplate[] = {
514 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof(CK_BBOOL)},
515 {CKA_PRIVATE, &ck_true, sizeof ck_true},
516 {CKA_SENSITIVE, &ck_true, sizeof ck_true},
517 {CKA_EXTRACTABLE, gentype != kg_token ? &ck_true : &ck_false, sizeof ck_false},
518
519 {CKA_LABEL, label, strlen(label) },
520 {CKA_ID, id, strlen((const char *)id) },
521
522 {CKA_DECRYPT, &ck_false, sizeof ck_false},
523 {CKA_UNWRAP, &ck_false, sizeof ck_false},
524 {CKA_SIGN, &ck_false, sizeof ck_false},
525 {CKA_SIGN_RECOVER, &ck_false, sizeof ck_false},
526 {CKA_DERIVE, &ck_false, sizeof ck_false},
527 /* leave room for up to 5 additional attributes */
528 {0L, NULL, 0L},
529 {0L, NULL, 0L},
530 {0L, NULL, 0L},
531 {0L, NULL, 0L},
532 {0L, NULL, 0L},
533 };
534
535 size_t prvk_template_len_max = (sizeof(prvktemplate)/sizeof(CK_ATTRIBUTE));
536 size_t prvk_template_len_min = prvk_template_len_max - 5;
537 size_t prvk_num_elems = prvk_template_len_min;
538
539 /* adjust private key */
540 /* some attributes are not applicable to private key, so we filter out first */
541 for(i=0; i<numattrs && prvk_num_elems<prvk_template_len_max; i++)
542 {
543 switch(attrs[i].type) {
544 case CKA_SENSITIVE:
545 case CKA_EXTRACTABLE:
546 case CKA_LABEL:
547 case CKA_ID:
548 case CKA_DECRYPT:
549 case CKA_UNWRAP:
550 case CKA_SIGN:
551 case CKA_SIGN_RECOVER:
552 case CKA_DERIVE:
553 case CKA_TRUSTED:
554 case CKA_MODIFIABLE:
555 case CKA_DERIVE_TEMPLATE:
556 case CKA_UNWRAP_TEMPLATE:
557 case CKA_ALLOWED_MECHANISMS:
558 {
559 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
560 prvktemplate,
561 &prvk_num_elems,
562 sizeof(CK_ATTRIBUTE),
563 compare_CKA );
564
565 /* if we have a match, take the value from the command line */
566 /* we are basically stealing the pointer from attrs array */
567 if(match && match->ulValueLen == attrs[i].ulValueLen) {
568 match->pValue = attrs[i].pValue;
569 }
570 }
571 break;
572
573 default:
574 /* pass */
575 break;
576 }
577 }
578
579 /* adjust public key */
580 for(i=0; i<numattrs && pubk_num_elems<pubk_template_len_max; i++)
581 {
582
583 switch(attrs[i].type) {
584 case CKA_LABEL:
585 case CKA_ID:
586 case CKA_ENCRYPT:
587 case CKA_WRAP:
588 case CKA_VERIFY:
589 case CKA_VERIFY_RECOVER:
590 case CKA_DERIVE:
591 case CKA_TRUSTED:
592 case CKA_MODIFIABLE:
593 case CKA_WRAP_TEMPLATE:
594 case CKA_DERIVE_TEMPLATE:
595 case CKA_ALLOWED_MECHANISMS:
596 {
597 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
598 pubktemplate,
599 &pubk_num_elems,
600 sizeof(CK_ATTRIBUTE),
601 compare_CKA );
602
603 /* if we have a match, take the value from the command line */
604 /* we are basically stealing the pointer from attrs array */
605 if(match && match->ulValueLen == attrs[i].ulValueLen) {
606 match->pValue = attrs[i].pValue;
607 }
608 }
609 break;
610
611 default:
612 /* pass */
613 break;
614 }
615 }
616
617 retcode = p11ctx->FunctionList.C_GenerateKeyPair(p11ctx->Session,
618 &mechanism,
619 pubktemplate, pubk_num_elems,
620 prvktemplate, prvk_num_elems,
621 pubkhandleptr, prvkhandleptr);
622
623 if (retcode != CKR_OK ) {
624 pkcs11_error( retcode, "C_GenerateKeyPair" );
625 rc = rc_error_pkcs11_api;
626 goto error;
627 }
628
629 /* special case: we want to keep a local copy of the wrapped key */
630 if(gentype==kg_token_for_wrapping) {
631 CK_OBJECT_HANDLE copyhandle=0;
632 /* we don't want an extractable key, unless specified as an attribute */
633 /* when invoking the command */
634 CK_BBOOL ck_extractable = has_extractable(attrs, numattrs);
635
636 CK_ATTRIBUTE tokentemplate[] = {
637 { CKA_TOKEN, &ck_true, sizeof ck_true },
638 { CKA_EXTRACTABLE, &ck_extractable, sizeof ck_extractable }
639 };
640
641 /* copy the private key first */
642 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
643 *prvkhandleptr,
644 tokentemplate,
645 sizeof tokentemplate / sizeof(CK_ATTRIBUTE),
646 ©handle );
647 if (retcode != CKR_OK ) {
648 pkcs11_warning( retcode, "C_CopyObject" );
649 fprintf(stderr, "***Warning: could not create a local copy for private key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
650 }
651
652 /* then the public key */
653 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
654 *pubkhandleptr,
655 tokentemplate,
656 1, /* CKA_EXTRACTABLE is for private/secret keys only, so index is limited to CKA_TOKEN */
657 ©handle );
658 if (retcode != CKR_OK ) {
659 pkcs11_warning( retcode, "C_CopyObject" );
660 fprintf(stderr, "***Warning: could not create a local copy for public key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
661 }
662 }
663 }
664 error:
665 return rc;
666 }
667
668
pkcs11_genEX(pkcs11Context * p11ctx,key_type_t keytype,char * label,char * param,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR pubkhandleptr,CK_OBJECT_HANDLE_PTR prvkhandleptr,key_generation_t gentype)669 static func_rc pkcs11_genEX( pkcs11Context * p11ctx,
670 key_type_t keytype,
671 char *label,
672 char *param,
673 CK_ATTRIBUTE attrs[],
674 CK_ULONG numattrs,
675 CK_OBJECT_HANDLE_PTR pubkhandleptr,
676 CK_OBJECT_HANDLE_PTR prvkhandleptr,
677 key_generation_t gentype)
678 {
679 func_rc rc = rc_ok;
680 CK_RV retcode;
681 int i;
682 CK_BBOOL ck_false = CK_FALSE;
683 CK_BBOOL ck_true = CK_TRUE;
684
685 CK_BYTE *ex_param;
686 CK_ULONG ex_param_len;
687
688 CK_MECHANISM mechanism = {
689 0 , NULL_PTR, 0
690 };
691
692 CK_BYTE id[32];
693
694 switch(keytype) {
695 case ec:
696 mechanism.mechanism = CKM_EC_KEY_PAIR_GEN;
697 snprintf((char *)id, sizeof id, "ec-%s-%ld", param, time(NULL));
698 break;
699
700 case ed:
701 mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN;
702 snprintf((char *)id, sizeof id, "ed-%s-%ld", param, time(NULL));
703 break;
704
705 default:
706 fprintf(stderr, "***Error: unmanaged keytype\n");
707 assert(0);
708 }
709
710 /* adjust EC parameter */
711 if( pkcs11_ex_curvename2oid(param, &ex_param, &ex_param_len, keytype) == false) {
712 fprintf(stderr,"***Error: unknown/unsupported %s curve parameter name '%s'\n",
713 keytype == ed ? "Edwards" : "elliptic",
714 param);
715 rc = rc_error_invalid_parameter_for_method;
716 goto error;
717 }
718
719 {
720 CK_ATTRIBUTE pubktemplate[] = {
721 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof(CK_BBOOL)},
722 {CKA_EC_PARAMS, ex_param, ex_param_len },
723 {CKA_LABEL, label, strlen(label) },
724 {CKA_ID, id, strlen((const char *)id) },
725 /* what can we do with this key */
726 {CKA_ENCRYPT, &ck_false, sizeof ck_false},
727 {CKA_WRAP, &ck_false, sizeof ck_false},
728 {CKA_VERIFY, &ck_false, sizeof ck_false},
729 {CKA_VERIFY_RECOVER, &ck_false, sizeof ck_false},
730 {CKA_DERIVE, &ck_false, sizeof ck_false},
731 /* leave room for up to 5 additional attributes */
732 {0L, NULL, 0L},
733 {0L, NULL, 0L},
734 {0L, NULL, 0L},
735 {0L, NULL, 0L},
736 {0L, NULL, 0L},
737 };
738
739 size_t pubk_template_len_max = (sizeof(pubktemplate)/sizeof(CK_ATTRIBUTE));
740 size_t pubk_template_len_min = pubk_template_len_max - 5;
741 size_t pubk_num_elems = pubk_template_len_min;
742
743
744 CK_ATTRIBUTE prvktemplate[] = {
745 {CKA_TOKEN, gentype == kg_token ? &ck_true : &ck_false, sizeof ck_true},
746 {CKA_PRIVATE, &ck_true, sizeof ck_true},
747 {CKA_SENSITIVE, &ck_true, sizeof ck_true},
748 {CKA_EXTRACTABLE, gentype != kg_token ? &ck_true : &ck_false, sizeof ck_false},
749
750 {CKA_LABEL, label, strlen(label) },
751 {CKA_ID, id, strlen((const char *)id) },
752 /* what can we do with this key */
753 {CKA_DECRYPT, &ck_false, sizeof ck_false},
754 {CKA_UNWRAP, &ck_false, sizeof ck_false},
755 {CKA_SIGN, &ck_false, sizeof ck_false},
756 {CKA_SIGN_RECOVER, &ck_false, sizeof ck_false},
757 {CKA_DERIVE, &ck_false, sizeof ck_false},
758 /* leave room for up to 5 additional attributes */
759 {0L, NULL, 0L},
760 {0L, NULL, 0L},
761 {0L, NULL, 0L},
762 {0L, NULL, 0L},
763 {0L, NULL, 0L},
764 };
765
766 size_t prvk_template_len_max = (sizeof(prvktemplate)/sizeof(CK_ATTRIBUTE));
767 size_t prvk_template_len_min = prvk_template_len_max - 5;
768 size_t prvk_num_elems = prvk_template_len_min;
769
770 /* adjust private key */
771 /* some attributes are not applicable to private key, so we filter out first */
772 for(i=0; i<numattrs && prvk_num_elems<prvk_template_len_max; i++)
773 {
774 switch(attrs[i].type) {
775 case CKA_SENSITIVE:
776 case CKA_EXTRACTABLE:
777 case CKA_LABEL:
778 case CKA_ID:
779 case CKA_DECRYPT:
780 case CKA_UNWRAP:
781 case CKA_SIGN:
782 case CKA_SIGN_RECOVER:
783 case CKA_DERIVE:
784 case CKA_TRUSTED:
785 case CKA_MODIFIABLE:
786 case CKA_UNWRAP_TEMPLATE:
787 case CKA_DERIVE_TEMPLATE:
788 case CKA_ALLOWED_MECHANISMS:
789 {
790 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
791 prvktemplate,
792 &prvk_num_elems,
793 sizeof(CK_ATTRIBUTE),
794 compare_CKA );
795
796 /* if we have a match, take the value from the command line */
797 /* we are basically stealing the pointer from attrs array */
798 if(match && match->ulValueLen == attrs[i].ulValueLen) {
799 match->pValue = attrs[i].pValue;
800 }
801 }
802 break;
803
804 default:
805 /* pass */
806 break;
807 }
808 }
809
810 /* adjust public key */
811 for(i=0; i<numattrs && pubk_num_elems<pubk_template_len_max; i++)
812 {
813
814 switch(attrs[i].type) {
815 case CKA_LABEL:
816 case CKA_ID:
817 case CKA_ENCRYPT:
818 case CKA_WRAP:
819 case CKA_VERIFY:
820 case CKA_VERIFY_RECOVER:
821 case CKA_DERIVE:
822 case CKA_TRUSTED:
823 case CKA_MODIFIABLE:
824 case CKA_WRAP_TEMPLATE:
825 case CKA_DERIVE_TEMPLATE:
826 case CKA_ALLOWED_MECHANISMS:
827 {
828 CK_ATTRIBUTE_PTR match = lsearch( &attrs[i],
829 pubktemplate,
830 &pubk_num_elems,
831 sizeof(CK_ATTRIBUTE),
832 compare_CKA );
833
834 /* if we have a match, take the value from the command line */
835 /* we are basically stealing the pointer from attrs array */
836 if(match && match->ulValueLen == attrs[i].ulValueLen) {
837 match->pValue = attrs[i].pValue;
838 }
839 }
840 break;
841
842 default:
843 /* pass */
844 break;
845 }
846 }
847
848 retcode = p11ctx->FunctionList.C_GenerateKeyPair(p11ctx->Session,
849 &mechanism,
850 pubktemplate, pubk_num_elems,
851 prvktemplate, prvk_num_elems,
852 pubkhandleptr, prvkhandleptr);
853
854 if (retcode != CKR_OK ) {
855 pkcs11_error( retcode, "C_GenerateKeyPair" );
856 rc = rc_error_pkcs11_api;
857 goto error;
858 }
859
860 /* special case: we want to keep a local copy of the wrapped key */
861 if(gentype==kg_token_for_wrapping) {
862 CK_OBJECT_HANDLE copyhandle=0;
863 /* we don't want an extractable key, unless specified as an attribute */
864 /* when invoking the command */
865 CK_BBOOL ck_extractable = has_extractable(attrs, numattrs);
866
867 CK_ATTRIBUTE tokentemplate[] = {
868 { CKA_TOKEN, &ck_true, sizeof ck_true },
869 { CKA_EXTRACTABLE, &ck_extractable, sizeof ck_extractable }
870 };
871
872 /* copy the private key first */
873 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
874 *prvkhandleptr,
875 tokentemplate,
876 sizeof tokentemplate / sizeof(CK_ATTRIBUTE),
877 ©handle );
878 if (retcode != CKR_OK ) {
879 pkcs11_warning( retcode, "C_CopyObject" );
880 fprintf(stderr, "***Warning: could not create a local copy for private key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
881 }
882
883 /* then the public key */
884 retcode = p11ctx->FunctionList.C_CopyObject( p11ctx->Session,
885 *pubkhandleptr,
886 tokentemplate,
887 1, /* CKA_EXTRACTABLE is for private/secret keys only, so index is limited to CKA_TOKEN */
888 ©handle );
889 if (retcode != CKR_OK ) {
890 pkcs11_warning( retcode, "C_CopyObject" );
891 fprintf(stderr, "***Warning: could not create a local copy for public key '%s'. Retry key generation without wrapping, or with '-r' option.\n", label);
892 }
893 }
894 }
895
896 error:
897 if(ex_param) { pkcs11_ec_freeoid(ex_param); }
898
899 return rc;
900 }
901
pkcs11_genEC(pkcs11Context * p11ctx,char * label,char * param,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR pubkhandleptr,CK_OBJECT_HANDLE_PTR prvkhandleptr,key_generation_t gentype)902 inline func_rc pkcs11_genEC( pkcs11Context * p11ctx,
903 char *label,
904 char *param,
905 CK_ATTRIBUTE attrs[],
906 CK_ULONG numattrs,
907 CK_OBJECT_HANDLE_PTR pubkhandleptr,
908 CK_OBJECT_HANDLE_PTR prvkhandleptr,
909 key_generation_t gentype) {
910 return pkcs11_genEX(p11ctx, ec, label, param, attrs, numattrs, pubkhandleptr, prvkhandleptr, gentype);
911 }
912
913
pkcs11_genED(pkcs11Context * p11ctx,char * label,char * param,CK_ATTRIBUTE attrs[],CK_ULONG numattrs,CK_OBJECT_HANDLE_PTR pubkhandleptr,CK_OBJECT_HANDLE_PTR prvkhandleptr,key_generation_t gentype)914 inline func_rc pkcs11_genED( pkcs11Context * p11ctx,
915 char *label,
916 char *param,
917 CK_ATTRIBUTE attrs[],
918 CK_ULONG numattrs,
919 CK_OBJECT_HANDLE_PTR pubkhandleptr,
920 CK_OBJECT_HANDLE_PTR prvkhandleptr,
921 key_generation_t gentype) {
922 return pkcs11_genEX(p11ctx, ed, label, param, attrs, numattrs, pubkhandleptr, prvkhandleptr, gentype);
923 }
924
925
926
927
pkcs11_testgenEC_support(pkcs11Context * p11ctx,const char * param)928 int pkcs11_testgenEC_support( pkcs11Context * p11ctx, const char *param)
929 {
930
931 CK_RV retcode;
932 int rc=0;
933 CK_BBOOL ck_false = CK_FALSE;
934 CK_BBOOL ck_true = CK_TRUE;
935
936 CK_BYTE *ec_param;
937 CK_ULONG ec_param_len;
938
939 CK_MECHANISM mechanism = {
940 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
941 };
942
943 CK_OBJECT_HANDLE pubkhandle;
944 CK_OBJECT_HANDLE prvkhandle;
945
946
947 char id[32];
948 char * label = id;
949 snprintf((char *)id, sizeof id, "testecdsa-%ld", time(NULL));
950
951
952 /* adjust EC parameter */
953 if( pkcs11_ec_curvename2oid((char *)param, &ec_param, &ec_param_len) == false ) {
954 // fprintf(stderr,"***Error: unknown/unsupported elliptic curve parameter name '%s'\n", param);
955 goto cleanup;
956 }
957
958 {
959 CK_ATTRIBUTE pubktemplate[] = {
960 {CKA_TOKEN, &ck_false, sizeof ck_false},
961 {CKA_EC_PARAMS, ec_param, ec_param_len },
962 {CKA_LABEL, label, strlen(label) },
963 {CKA_ID, id, strlen((const char *)id) },
964 /* what can we do with this key */
965 {CKA_ENCRYPT, &ck_false, sizeof ck_false},
966 {CKA_WRAP, &ck_false, sizeof ck_false},
967 {CKA_VERIFY, &ck_true, sizeof ck_false},
968 {CKA_VERIFY_RECOVER, &ck_false, sizeof ck_false},
969 {CKA_DERIVE, &ck_false, sizeof ck_false},
970 };
971
972 CK_ATTRIBUTE prvktemplate[] = {
973 {CKA_TOKEN, &ck_false, sizeof ck_false},
974 {CKA_PRIVATE, &ck_true, sizeof ck_true},
975 {CKA_SENSITIVE, &ck_true, sizeof ck_true},
976 {CKA_EXTRACTABLE, &ck_false, sizeof ck_false},
977
978 {CKA_LABEL, label, strlen(label) },
979 {CKA_ID, id, strlen((const char *)id) },
980 /* what can we do with this key */
981 {CKA_DECRYPT, &ck_false, sizeof ck_false},
982 {CKA_UNWRAP, &ck_false, sizeof ck_false},
983 {CKA_SIGN, &ck_true, sizeof ck_false},
984 {CKA_SIGN_RECOVER, &ck_false, sizeof ck_false},
985 {CKA_DERIVE, &ck_false, sizeof ck_false},
986 };
987
988 retcode = p11ctx->FunctionList.C_GenerateKeyPair(p11ctx->Session,
989 &mechanism,
990 pubktemplate, sizeof(pubktemplate)/sizeof(CK_ATTRIBUTE),
991 prvktemplate, sizeof(prvktemplate)/sizeof(CK_ATTRIBUTE),
992 &pubkhandle, &prvkhandle);
993
994 /* not nice, because we *guess* param is not supported only if CKR_DOMAIN_PARAMS_INVALID is returned */
995 /* may vary amongst lib implementations... */
996 if (retcode != CKR_DOMAIN_PARAMS_INVALID) {
997 rc = 1;
998 }
999 }
1000
1001 cleanup:
1002 if(ec_param) { pkcs11_ec_freeoid(ec_param); }
1003
1004 return rc;
1005 }
1006
1007