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 							 &copyhandle );
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 							 &copyhandle );
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 							 &copyhandle );
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 							 &copyhandle );
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 							 &copyhandle );
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 							 &copyhandle );
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 							 &copyhandle );
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