1 /*
2 * The Initial Developer of the Original Code is International
3 * Business Machines Corporation. Portions created by IBM
4 * Corporation are Copyright (C) 2005 International Business
5 * Machines Corporation. All Rights Reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the Common Public License as published by
9 * IBM Corporation; either version 1 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * Common Public License for more details.
16 *
17 * You should have received a copy of the Common Public License
18 * along with this program; if not, a copy can be viewed at
19 * http://www.opensource.org/licenses/cpl1.0.php.
20 */
21
22 #include "data_import.h"
23 #include "data_common.h"
24
25 #include <tpm_pkcs11.h>
26 #include <tpm_utils.h>
27
28 #include <stdlib.h>
29 #include <unistd.h>
30 #define _GNU_SOURCE
31 #include <getopt.h>
32 #include <errno.h>
33
34 #include <openssl/rsa.h>
35 #include <openssl/x509.h>
36 #include <openssl/x509v3.h>
37 #include <openssl/pem.h>
38 #include <openssl/asn1.h>
39 #include <openssl/evp.h>
40 #include <openssl/err.h>
41
42 #if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER)
43 #define RSA_get0_n(x) ((x)->n)
44 #define RSA_get0_e(x) ((x)->e)
45 #define RSA_get0_d(x) ((x)->d)
46 #define RSA_get0_p(x) ((x)->p)
47 #define RSA_get0_q(x) ((x)->q)
48 #define RSA_get0_dmp1(x) ((x)->dmp1)
49 #define RSA_get0_dmq1(x) ((x)->dmq1)
50 #define RSA_get0_iqmp(x) ((x)->iqmp)
51 #endif
52
53 /*
54 * Global variables
55 */
56 char *g_pszFile = NULL; // Object import file name
57 char *g_pszIdFile = NULL; // Object identification file name
58 char *g_pszType = NULL; // Object import type
59 int g_bPublic = FALSE; // Public object specifier
60 int g_bYes = FALSE; // Yes/No prompt reply
61 char *g_pszToken = NULL; // Token label to be used
62
63 int g_bAttrsValid = FALSE;
64 CK_BYTE *g_pchSubject = NULL; // SUBJECT attribute value
65 CK_LONG g_subjectLen = 0;
66 CK_BYTE *g_pchId = NULL; // ID attribute value
67 CK_ULONG g_ulIdLen = 0;
68 CK_BYTE *g_pchName = NULL; // LABEL attribute value
69 CK_ULONG g_ulNameLen = 0;
70
71 /*
72 * parseCallback
73 * Process the command specific options.
74 */
75 int
parseCallback(int a_iOpt,const char * a_pszOptArg)76 parseCallback( int a_iOpt,
77 const char *a_pszOptArg ) {
78
79 switch ( a_iOpt ) {
80 // File with object to be used to obtain subject/id
81 case 'i':
82 if ( !a_pszOptArg )
83 return -1;
84
85 g_pszIdFile = strdup( a_pszOptArg );
86 break;
87
88 // Use the specified token label when finding the token
89 case 'k':
90 if ( !a_pszOptArg )
91 return -1;
92
93 g_pszToken = strdup( a_pszOptArg );
94 break;
95
96 // Name to use as the LABEL attribute value
97 case 'n':
98 if ( !a_pszOptArg )
99 return -1;
100
101 g_pchName = (CK_BYTE *)strdup( a_pszOptArg );
102 g_ulNameLen = strlen( a_pszOptArg );
103 break;
104
105 // Make the object public
106 case 'p':
107 g_bPublic = TRUE;
108 break;
109
110 // Only import the specified object type
111 case 't':
112 if ( !a_pszOptArg )
113 return -1;
114
115 if ( ( strcmp( a_pszOptArg, TOKEN_OBJECT_KEY ) != 0 ) &&
116 ( strcmp( a_pszOptArg, TOKEN_OBJECT_CERT ) != 0 ) )
117 return -1;
118
119 g_pszType = strdup( a_pszOptArg );
120 break;
121
122 // Reply "yes" to any yes/no prompts
123 case 'y':
124 g_bYes = TRUE;
125 break;
126 }
127
128 return 0;
129 }
130
131 /*
132 * usageCallback
133 * Display command usage information.
134 */
135 void
usageCallback(const char * a_pszCmd)136 usageCallback( const char *a_pszCmd ) {
137
138 char *pszArgs[2];
139 char *pszArgsDesc[2];
140
141 pszArgs[ 0 ] = "FILE";
142 pszArgsDesc[ 0 ] = _("Import the PEM formatted RSA key and/or X.509 certificate object contained in FILE");
143 pszArgs[ 1 ] = NULL;
144 pszArgsDesc[ 1 ] = NULL;
145
146 logCmdHelpEx( a_pszCmd, pszArgs, pszArgsDesc );
147 logCmdOption( "-i, --idfile FILE",
148 _("Use FILE as the PEM formatted X.509 certificate input used to obtain the subject and id attributes") );
149 logCmdOption( "-k, --token STRING",
150 _("Use STRING to identify the label of the PKCS#11 token to be used") );
151 logCmdOption( "-n, --name STRING",
152 _("Use STRING as the label for the imported object(s)") );
153 logCmdOption( "-p, --public",
154 _("Import the object(s) as a public object") );
155 logCmdOption( "-t, --type key|cert",
156 _("Import only the specified object type") );
157 logCmdOption( "-y, --yes",
158 _("Assume yes as the answer to any confirmation prompt") );
159 }
160
161 /*
162 * parseCmd
163 * Parse the command line options.
164 */
165 int
parseCmd(int a_iArgc,char ** a_pszArgv)166 parseCmd( int a_iArgc,
167 char **a_pszArgv ) {
168
169 int rc;
170
171 char *pszShortOpts = "i:k:n:pt:y";
172 struct option stLongOpts[] = {
173 { "idfile", required_argument, NULL, 'i' },
174 { "name", required_argument, NULL, 'n' },
175 { "public", no_argument, NULL, 'p' },
176 { "token", required_argument, NULL, 'k' },
177 { "type", required_argument, NULL, 't' },
178 { "yes", no_argument, NULL, 'y' },
179 };
180 int iNumLongOpts = sizeof( stLongOpts ) / sizeof( struct option );
181
182 rc = genericOptHandler( a_iArgc, a_pszArgv,
183 pszShortOpts, stLongOpts, iNumLongOpts,
184 parseCallback, usageCallback );
185 if ( rc == -1 )
186 return -1;
187
188 if ( optind >= a_iArgc ) {
189 logMsg( TOKEN_FILE_ERROR );
190 usageCallback( a_pszArgv[ 0 ] );
191 return -1;
192 }
193
194 g_pszFile = strdup( a_pszArgv[ optind ] );
195
196 return 0;
197 }
198
199 /*
200 * findExistingObjects
201 * Search for objects of the supplied type that have a SUBJECT
202 * and ID attribute equal to the values of the object to be
203 * imported.
204 */
205 int
findExistingObjects(CK_SESSION_HANDLE a_hSession,CK_ATTRIBUTE * a_tAttr,CK_ULONG a_ulAttrCount,CK_OBJECT_HANDLE ** a_phObject,CK_ULONG * a_pulObjectCount)206 findExistingObjects( CK_SESSION_HANDLE a_hSession,
207 CK_ATTRIBUTE *a_tAttr,
208 CK_ULONG a_ulAttrCount,
209 CK_OBJECT_HANDLE **a_phObject,
210 CK_ULONG *a_pulObjectCount ) {
211
212 CK_RV rv;
213 CK_BBOOL bTrue = TRUE;
214
215 // Set up default search attributes
216 CK_ATTRIBUTE tDefaultAttr[] = {
217 { CKA_TOKEN, &bTrue, sizeof( bTrue ) },
218 { CKA_SUBJECT, g_pchSubject, g_subjectLen },
219 { CKA_ID, g_pchId, g_ulIdLen },
220 };
221 CK_ULONG ulDefaultAttrCount = sizeof( tDefaultAttr ) / sizeof( CK_ATTRIBUTE );
222
223 CK_ATTRIBUTE tAttr[ ulDefaultAttrCount + a_ulAttrCount ];
224 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
225
226 *a_phObject = NULL;
227 *a_pulObjectCount = 0;
228
229 // Apply attributes and search
230 memcpy( tAttr, tDefaultAttr, ulDefaultAttrCount * sizeof( CK_ATTRIBUTE ) );
231 if ( a_ulAttrCount )
232 memcpy( tAttr + ulDefaultAttrCount, a_tAttr, a_ulAttrCount * sizeof( CK_ATTRIBUTE ) );
233
234 rv = findObjects( a_hSession, tAttr, ulAttrCount, a_phObject, a_pulObjectCount );
235
236 return ( rv == CKR_OK ) ? 0 : -1;
237 }
238
239 /*
240 * checkExistingObjects
241 * Use findExistingObjects to determine if objects of the
242 * supplied type currently exist. If so, prompt the user as
243 * to whether to replace the existing objects.
244 */
245 int
checkExistingObjects(CK_SESSION_HANDLE a_hSession,CK_ATTRIBUTE * a_tAttr,CK_ULONG a_ulAttrCount,const char * a_pszObject)246 checkExistingObjects( CK_SESSION_HANDLE a_hSession,
247 CK_ATTRIBUTE *a_tAttr,
248 CK_ULONG a_ulAttrCount,
249 const char *a_pszObject ) {
250
251 int rc = -1;
252
253 CK_OBJECT_HANDLE *phObject = NULL;
254 CK_ULONG ulObjectCount = 0;
255
256 char szPrompt[ strlen( TOKEN_ID_PROMPT ) + strlen( a_pszObject ) + 1 ];
257 char *pszReply = NULL;
258
259 if ( g_bAttrsValid ) {
260 // Search for existing objects
261 if ( findExistingObjects( a_hSession, a_tAttr, a_ulAttrCount, &phObject, &ulObjectCount ) == -1 )
262 goto out;
263
264 if ( ulObjectCount > 0 ) {
265 // One or more objects exists
266 if ( !g_bYes ) {
267 // Prompt for whether to replace the existing objects
268 sprintf( szPrompt, TOKEN_ID_PROMPT, a_pszObject );
269 pszReply = getReply( szPrompt, 1 );
270 if ( !pszReply ||
271 ( strlen( pszReply ) == 0 ) ||
272 ( strcasecmp( pszReply, TOKEN_ID_NO ) == 0 ) ) {
273 goto out;
274 }
275 }
276 }
277 }
278
279 rc = 0;
280
281 out:
282 free( phObject );
283 free( pszReply );
284
285 return rc;
286 }
287
288 /*
289 * destroyExistingObjects
290 * Use findExistingObjects to locate all objects of the
291 * supplied type that currently exists and destroy them.
292 */
293 int
destroyExistingObjects(CK_SESSION_HANDLE a_hSession,CK_ATTRIBUTE * a_tAttr,CK_ULONG a_ulAttrCount)294 destroyExistingObjects( CK_SESSION_HANDLE a_hSession,
295 CK_ATTRIBUTE *a_tAttr,
296 CK_ULONG a_ulAttrCount ) {
297
298 int rc = -1;
299
300 CK_RV rv;
301 CK_OBJECT_HANDLE *phObject = NULL;
302 CK_ULONG ulObjectCount = 0;
303
304 if ( g_bAttrsValid ) {
305 // Search for existing objects
306 if ( findExistingObjects( a_hSession, a_tAttr, a_ulAttrCount, &phObject, &ulObjectCount ) == -1 )
307 goto out;
308
309 // Destroy each object found
310 while ( ulObjectCount > 0 ) {
311 rv = destroyObject( a_hSession, phObject[ --ulObjectCount ] );
312 if ( rv != CKR_OK )
313 goto out;
314 }
315 }
316
317 rc = 0;
318
319 out:
320 free( phObject );
321
322 return rc;
323 }
324
325 /*
326 * readX509Cert
327 * Use the OpenSSL library to read a PEM formatted X509 certificate.
328 */
329 int
readX509Cert(const char * a_pszFile,int a_bCheckKey,X509 ** a_pX509)330 readX509Cert( const char *a_pszFile,
331 int a_bCheckKey,
332 X509 **a_pX509 ) {
333
334 int rc = -1;
335
336 FILE *pFile = stdin;
337 X509 *pX509 = NULL;
338 EVP_PKEY *pKey = NULL;
339
340 *a_pX509 = NULL;
341
342 // Open the file to be read
343 if ( a_pszFile ) {
344 errno = 0;
345 pFile = fopen( a_pszFile, "r" );
346 if ( !pFile ) {
347 logError( TOKEN_FILE_OPEN_ERROR, a_pszFile, strerror( errno ) );
348 goto out;
349 }
350 }
351
352 // Read the X509 certificate
353 pX509 = PEM_read_X509( pFile, NULL, NULL, NULL );
354 if ( !pX509 ) {
355 unsigned long ulError = ERR_get_error( );
356
357 // Not necessarily an error if the file doesn't contain the cert
358 if ( ( ERR_GET_LIB( ulError ) == ERR_R_PEM_LIB ) &&
359 ( ERR_GET_REASON( ulError ) == PEM_R_NO_START_LINE ) ) {
360 logInfo( TOKEN_OPENSSL_ERROR, ERR_error_string( ulError, NULL ) );
361 rc = 0;
362 }
363 else
364 logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ulError, NULL ) );
365
366 goto out;
367 }
368
369 // Make sure the certificate uses an RSA key
370 if ( !a_bCheckKey ) {
371 rc = 0;
372 goto out;
373 }
374
375 pKey = X509_get_pubkey( pX509 );
376 if ( !pKey ) {
377 logInfo( TOKEN_OPENSSL_ERROR,
378 ERR_error_string( ERR_get_error( ), NULL ) );
379
380 X509_free( pX509 );
381 pX509 = NULL;
382 goto out;
383 }
384
385 if ( EVP_PKEY_type( EVP_PKEY_id(pKey) ) != EVP_PKEY_RSA ) {
386 logError( TOKEN_RSA_KEY_ERROR );
387
388 X509_free( pX509 );
389 pX509 = NULL;
390 goto out;
391 }
392
393 rc = 0;
394
395 out:
396 *a_pX509 = pX509;
397
398 if ( a_pszFile && pFile )
399 fclose( pFile );
400
401 return rc;
402 }
403
404 /*
405 * checkX509Cert
406 * Use checkExistingObjects to search for X_509 objects
407 * that match the attributes of the X_509 object to be imported.
408 */
409 int
checkX509Cert(CK_SESSION_HANDLE a_hSession)410 checkX509Cert( CK_SESSION_HANDLE a_hSession ) {
411
412 CK_CERTIFICATE_TYPE tX509 = CKC_X_509;
413 CK_ATTRIBUTE tAttr[] = {
414 { CKA_CERTIFICATE_TYPE, &tX509, sizeof( tX509 ) },
415 };
416 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
417
418 return checkExistingObjects( a_hSession, tAttr, ulAttrCount, TOKEN_ID_X509_CERT );
419 }
420
421 /*
422 * destroyX509CertObject
423 * Use destroyExistingObjects to destroy X_509 objects
424 * that match the attributes of the X_509 object to be imported.
425 */
426 int
destroyX509CertObject(CK_SESSION_HANDLE a_hSession)427 destroyX509CertObject( CK_SESSION_HANDLE a_hSession ) {
428
429 CK_CERTIFICATE_TYPE tX509 = CKC_X_509;
430 CK_ATTRIBUTE tAttr[] = {
431 { CKA_CERTIFICATE_TYPE, &tX509, sizeof( tX509 ) },
432 };
433 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
434
435 return destroyExistingObjects( a_hSession, tAttr, ulAttrCount );
436 }
437
438 /*
439 * createX509CertObject
440 * Create an X_509 object.
441 */
442 int
createX509CertObject(X509 * a_pX509,CK_SESSION_HANDLE a_hSession)443 createX509CertObject( X509 *a_pX509,
444 CK_SESSION_HANDLE a_hSession ) {
445
446 int rc = -1;
447
448 CK_RV rv;
449
450 CK_BBOOL bTrue = TRUE;
451
452 X509_NAME *pIssuer = NULL;
453 ASN1_INTEGER *pSerialNum = NULL;
454
455 CK_BYTE *pchIssuer = NULL;
456 CK_LONG issuerLen = 0;
457 CK_BYTE *pchSerialNum = NULL;
458 CK_LONG serialNumLen = 0;
459 CK_BYTE *pchCert = NULL;
460 CK_LONG certLen = 0;
461
462 CK_OBJECT_CLASS clCertClass = CKO_CERTIFICATE;
463 CK_CERTIFICATE_TYPE tCertType = CKC_X_509;
464 CK_BBOOL bPrivate = ( !g_bPublic ) ? TRUE : FALSE;
465
466 // The issuer, serial number, and value attributes must be completed
467 // before the object is created
468 CK_ATTRIBUTE tCertAttr[] = {
469 { CKA_CLASS, &clCertClass, sizeof( clCertClass ) },
470 { CKA_TOKEN, &bTrue, sizeof( bTrue ) },
471 { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) },
472 { CKA_MODIFIABLE, &bTrue, sizeof( bTrue ) },
473 { CKA_LABEL, g_pchName, g_ulNameLen },
474 { CKA_CERTIFICATE_TYPE, &tCertType, sizeof( tCertType ) },
475 { CKA_SUBJECT, g_pchSubject, g_subjectLen },
476 { CKA_ID, g_pchId, g_ulIdLen },
477 { CKA_ISSUER, NULL, 0 },
478 { CKA_SERIAL_NUMBER, NULL, 0 },
479 { CKA_VALUE, NULL, 0 },
480 };
481 CK_ULONG ulCertAttrCount = sizeof( tCertAttr ) / sizeof( CK_ATTRIBUTE );
482
483 CK_OBJECT_HANDLE hObject;
484
485 // Get the issuer name from the X509 certificate
486 pIssuer = X509_get_issuer_name( a_pX509 );
487 if ( !pIssuer ) {
488 logError( TOKEN_OPENSSL_ERROR,
489 ERR_error_string( ERR_get_error( ), NULL ) );
490 goto out;
491 }
492 issuerLen = i2d_X509_NAME( pIssuer, &pchIssuer );
493 if ( issuerLen < 0 ) {
494 logError( TOKEN_OPENSSL_ERROR,
495 ERR_error_string( ERR_get_error( ), NULL ) );
496 goto out;
497 }
498
499 // Get the serial number from the X509 certificate
500 pSerialNum = X509_get_serialNumber( a_pX509 );
501 if ( !pSerialNum ) {
502 logError( TOKEN_OPENSSL_ERROR,
503 ERR_error_string( ERR_get_error( ), NULL ) );
504 goto out;
505 }
506 serialNumLen = i2d_ASN1_INTEGER( pSerialNum, &pchSerialNum );
507 if ( serialNumLen < 0 ) {
508 logError( TOKEN_OPENSSL_ERROR,
509 ERR_error_string( ERR_get_error( ), NULL ) );
510 goto out;
511 }
512
513 // Get a DER encoded format of the X509 certificate
514 certLen = i2d_X509( a_pX509, &pchCert );
515 if ( certLen < 0 ) {
516 logError( TOKEN_OPENSSL_ERROR,
517 ERR_error_string( ERR_get_error( ), NULL ) );
518 goto out;
519 }
520
521 // Set the attribute values
522 tCertAttr[ 8 ].pValue = pchIssuer;
523 tCertAttr[ 8 ].ulValueLen = issuerLen;
524 tCertAttr[ 9 ].pValue = pchSerialNum;
525 tCertAttr[ 9 ].ulValueLen = serialNumLen;
526 tCertAttr[ 10 ].pValue = pchCert;
527 tCertAttr[ 10 ].ulValueLen = certLen;
528
529 // Create the X509 certificate object
530 rv = createObject( a_hSession, tCertAttr, ulCertAttrCount, &hObject );
531 if ( rv != CKR_OK )
532 goto out;
533
534 rc = 0;
535
536 out:
537 OPENSSL_free( pchIssuer );
538 OPENSSL_free( pchCert );
539 OPENSSL_free( pchSerialNum );
540
541 return rc;
542 }
543
544 /*
545 * doX509Cert
546 * Process an X509 certificate for import.
547 */
548 int
doX509Cert(X509 * a_pX509,CK_SESSION_HANDLE a_hSession)549 doX509Cert( X509 *a_pX509,
550 CK_SESSION_HANDLE a_hSession ) {
551
552 int rc = -1;
553
554 if ( destroyX509CertObject( a_hSession ) == -1 )
555 goto out;
556
557 if ( createX509CertObject( a_pX509, a_hSession ) == -1 )
558 goto out;
559
560 rc = 0;
561
562 out:
563 return rc;
564 }
565
566 /*
567 * readRsaKey
568 * Use the OpenSSL library to read a PEM formatted RSA key.
569 */
570 int
readRsaKey(const char * a_pszFile,RSA ** a_pRsa)571 readRsaKey( const char *a_pszFile,
572 RSA **a_pRsa ) {
573
574 int rc = -1;
575
576 FILE *pFile = stdin;
577 RSA *pRsa = NULL;
578
579 *a_pRsa = NULL;
580
581 // Open the file to be read
582 if ( a_pszFile ) {
583 errno = 0;
584 pFile = fopen( a_pszFile, "r" );
585 if ( !pFile ) {
586 logError( TOKEN_FILE_OPEN_ERROR, a_pszFile, strerror( errno ) );
587 goto out;
588 }
589 }
590
591 // Read the RSA key
592 // This reads the public key also, not just the private key
593 pRsa = PEM_read_RSAPrivateKey( pFile, NULL, NULL, NULL );
594 if ( !pRsa ) {
595 unsigned long ulError = ERR_get_error( );
596
597 // Not necessarily an error if the file doesn't contain the key
598 if ( ( ERR_GET_LIB( ulError ) == ERR_R_PEM_LIB ) &&
599 ( ERR_GET_REASON( ulError ) == PEM_R_NO_START_LINE ) ) {
600 logInfo( TOKEN_OPENSSL_ERROR, ERR_error_string( ulError, NULL ) );
601 rc = 0;
602 }
603 else
604 logError( TOKEN_OPENSSL_ERROR, ERR_error_string( ulError, NULL ) );
605
606 goto out;
607 }
608
609 rc = 0;
610
611 out:
612 if ( a_pszFile && pFile )
613 fclose( pFile );
614
615 *a_pRsa = pRsa;
616
617 return rc;
618 }
619
620 /*
621 * checkRsaPubKey
622 * Use checkExistingObjects to search for RSA public key objects
623 * that match the attributes of the X509's RSA public key object
624 * to be imported.
625 */
626 int
checkRsaPubKey(CK_SESSION_HANDLE a_hSession)627 checkRsaPubKey( CK_SESSION_HANDLE a_hSession ) {
628
629 CK_OBJECT_CLASS tPubKey = CKO_PUBLIC_KEY;
630 CK_KEY_TYPE tRsa = CKK_RSA;
631 CK_ATTRIBUTE tAttr[] = {
632 { CKA_CLASS, &tPubKey, sizeof( tPubKey ) },
633 { CKA_KEY_TYPE, &tRsa, sizeof( tRsa ) },
634 };
635 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
636
637 return checkExistingObjects( a_hSession, tAttr, ulAttrCount, TOKEN_ID_RSA_PUBKEY );
638 }
639
640 /*
641 * checkRsaKey
642 * Use checkExistingObjects to search for RSA objects
643 * that match the attributes of the RSA object to be imported.
644 */
645 int
checkRsaKey(CK_SESSION_HANDLE a_hSession)646 checkRsaKey( CK_SESSION_HANDLE a_hSession ) {
647
648 CK_KEY_TYPE tRsa = CKK_RSA;
649 CK_ATTRIBUTE tAttr[] = {
650 { CKA_KEY_TYPE, &tRsa, sizeof( tRsa ) },
651 };
652 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
653
654 return checkExistingObjects( a_hSession, tAttr, ulAttrCount, TOKEN_ID_RSA_KEY );
655 }
656
657 /*
658 * destroyRsaKeyObject
659 * Use destroyExistingObjects to destroy RSA objects
660 * that match the attributes of the RSA object to be imported.
661 */
662 int
destroyRsaPubKeyObject(CK_SESSION_HANDLE a_hSession)663 destroyRsaPubKeyObject( CK_SESSION_HANDLE a_hSession ) {
664
665 CK_OBJECT_CLASS tPubKey = CKO_PUBLIC_KEY;
666 CK_KEY_TYPE tRsa = CKK_RSA;
667 CK_ATTRIBUTE tAttr[] = {
668 { CKA_CLASS, &tPubKey, sizeof( tPubKey ) },
669 { CKA_KEY_TYPE, &tRsa, sizeof( tRsa ) },
670 };
671 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
672
673 return destroyExistingObjects( a_hSession, tAttr, ulAttrCount );
674 }
675
676 /*
677 * destroyRsaKeyObject
678 * Use destroyExistingObjects to destroy RSA objects
679 * that match the attributes of the RSA object to be imported.
680 */
681 int
destroyRsaKeyObject(CK_SESSION_HANDLE a_hSession)682 destroyRsaKeyObject( CK_SESSION_HANDLE a_hSession ) {
683
684 CK_KEY_TYPE tRsa = CKK_RSA;
685 CK_ATTRIBUTE tAttr[] = {
686 { CKA_KEY_TYPE, &tRsa, sizeof( tRsa ) },
687 };
688 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
689
690 return destroyExistingObjects( a_hSession, tAttr, ulAttrCount );
691 }
692
693 /*
694 * createRsaPubKeyObject
695 * Create an RSA public key object.
696 */
697 int
createRsaPubKeyObject(RSA * a_pRsa,CK_SESSION_HANDLE a_hSession,CK_OBJECT_HANDLE * a_hObject)698 createRsaPubKeyObject( RSA *a_pRsa,
699 CK_SESSION_HANDLE a_hSession,
700 CK_OBJECT_HANDLE *a_hObject ) {
701
702 int rc = -1;
703
704 int nLen = BN_num_bytes( RSA_get0_n(a_pRsa) );
705 int eLen = BN_num_bytes( RSA_get0_e(a_pRsa) );
706
707 CK_RV rv;
708
709 CK_BBOOL bTrue = TRUE;
710 CK_BBOOL bFalse = FALSE;
711
712 CK_BYTE *n = malloc( nLen );
713 CK_BYTE *e = malloc( eLen );
714
715 CK_OBJECT_CLASS clPubClass = CKO_PUBLIC_KEY;
716 CK_KEY_TYPE tKeyType = CKK_RSA;
717 CK_BBOOL bPrivate = ( !g_bPublic ) ? TRUE : FALSE;
718
719 CK_ATTRIBUTE tAttr[] = {
720 { CKA_CLASS, &clPubClass, sizeof( clPubClass ) },
721 { CKA_TOKEN, &bTrue, sizeof( bTrue ) },
722 { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) },
723 { CKA_MODIFIABLE, &bTrue, sizeof( bTrue ) },
724 { CKA_LABEL, g_pchName, g_ulNameLen },
725 { CKA_KEY_TYPE, &tKeyType, sizeof( tKeyType ) },
726 { CKA_ID, g_pchId, g_ulIdLen },
727 { CKA_SUBJECT, g_pchSubject, g_subjectLen },
728 { CKA_ENCRYPT, &bTrue, sizeof( bTrue ) },
729 { CKA_VERIFY, &bTrue, sizeof( bTrue ) },
730 { CKA_VERIFY_RECOVER, &bFalse, sizeof( bFalse ) },
731 { CKA_WRAP, &bFalse, sizeof( bFalse ) },
732 { CKA_MODULUS, n, nLen },
733 { CKA_PUBLIC_EXPONENT, e, eLen },
734 };
735 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
736
737 *a_hObject = 0;
738
739 if ( !n || !e ) {
740 logError( TOKEN_MEMORY_ERROR );
741 goto out;
742 }
743
744 // Get binary representations of the RSA key information
745 BN_bn2bin( RSA_get0_n(a_pRsa), n );
746 BN_bn2bin( RSA_get0_e(a_pRsa), e );
747
748 // Create the RSA public key object
749 rv = createObject( a_hSession, tAttr, ulAttrCount, a_hObject );
750 if ( rv != CKR_OK )
751 goto out;
752
753 rc = 0;
754
755 out:
756 free( n );
757 free( e );
758
759 return rc;
760 }
761
762 /*
763 * createRsaPrivKeyObject
764 * Create an RSA private key object.
765 */
766 int
createRsaPrivKeyObject(RSA * a_pRsa,CK_SESSION_HANDLE a_hSession,CK_OBJECT_HANDLE * a_hObject)767 createRsaPrivKeyObject( RSA *a_pRsa,
768 CK_SESSION_HANDLE a_hSession,
769 CK_OBJECT_HANDLE *a_hObject ) {
770
771 int rc = -1;
772
773 int nLen = BN_num_bytes( RSA_get0_n(a_pRsa) );
774 int eLen = BN_num_bytes( RSA_get0_e(a_pRsa) );
775 int dLen = BN_num_bytes( RSA_get0_d(a_pRsa) );
776 int pLen = BN_num_bytes( RSA_get0_p(a_pRsa) );
777 int qLen = BN_num_bytes( RSA_get0_q(a_pRsa) );
778 int dmp1Len = BN_num_bytes( RSA_get0_dmp1(a_pRsa) );
779 int dmq1Len = BN_num_bytes( RSA_get0_dmq1(a_pRsa) );
780 int iqmpLen = BN_num_bytes( RSA_get0_iqmp(a_pRsa) );
781
782 CK_RV rv;
783
784 CK_BBOOL bTrue = TRUE;
785 CK_BBOOL bFalse = FALSE;
786
787 CK_BYTE *n = malloc( nLen );
788 CK_BYTE *e = malloc( eLen );
789 CK_BYTE *d = malloc( dLen );
790 CK_BYTE *p = malloc( pLen );
791 CK_BYTE *q = malloc( qLen );
792 CK_BYTE *dmp1 = malloc( dmp1Len );
793 CK_BYTE *dmq1 = malloc( dmq1Len );
794 CK_BYTE *iqmp = malloc( iqmpLen );
795
796 CK_OBJECT_CLASS clPrivClass = CKO_PRIVATE_KEY;
797 CK_KEY_TYPE tKeyType = CKK_RSA;
798 CK_BBOOL bPrivate = ( !g_bPublic ) ? TRUE : FALSE;
799
800 CK_ATTRIBUTE tAttr[] = {
801 { CKA_CLASS, &clPrivClass, sizeof( clPrivClass ) },
802 { CKA_TOKEN, &bTrue, sizeof( bTrue ) },
803 { CKA_PRIVATE, &bPrivate, sizeof( bPrivate ) },
804 { CKA_MODIFIABLE, &bTrue, sizeof( bTrue ) },
805 { CKA_LABEL, g_pchName, g_ulNameLen },
806 { CKA_KEY_TYPE, &tKeyType, sizeof( tKeyType ) },
807 { CKA_ID, g_pchId, g_ulIdLen },
808 { CKA_SUBJECT, g_pchSubject, g_subjectLen },
809 { CKA_SENSITIVE, &bTrue, sizeof( bTrue ) },
810 { CKA_DECRYPT, &bTrue, sizeof( bTrue ) },
811 { CKA_SIGN, &bTrue, sizeof( bTrue ) },
812 { CKA_SIGN_RECOVER, &bFalse, sizeof( bFalse ) },
813 { CKA_UNWRAP, &bFalse, sizeof( bFalse ) },
814 { CKA_EXTRACTABLE, &bFalse, sizeof( bFalse ) },
815 { CKA_MODULUS, n, nLen },
816 { CKA_PUBLIC_EXPONENT, e, eLen },
817 { CKA_PRIVATE_EXPONENT, d, dLen },
818 { CKA_PRIME_1, p, pLen },
819 { CKA_PRIME_2, q, qLen },
820 { CKA_EXPONENT_1, dmp1, dmp1Len },
821 { CKA_EXPONENT_2, dmq1, dmq1Len },
822 { CKA_COEFFICIENT, iqmp, iqmpLen },
823 };
824 CK_ULONG ulAttrCount = sizeof( tAttr ) / sizeof( CK_ATTRIBUTE );
825
826 *a_hObject = 0;
827
828 if ( !n || !e || !d || !p || !q || !dmp1 || !dmq1 || !iqmp ) {
829 logError( TOKEN_MEMORY_ERROR );
830 goto out;
831 }
832
833 // Get binary representations of the RSA key information
834 BN_bn2bin( RSA_get0_n(a_pRsa), n );
835 BN_bn2bin( RSA_get0_e(a_pRsa), e );
836 BN_bn2bin( RSA_get0_d(a_pRsa), d );
837 BN_bn2bin( RSA_get0_p(a_pRsa), p );
838 BN_bn2bin( RSA_get0_q(a_pRsa), q );
839 BN_bn2bin( RSA_get0_dmp1(a_pRsa), dmp1 );
840 BN_bn2bin( RSA_get0_dmq1(a_pRsa), dmq1 );
841 BN_bn2bin( RSA_get0_iqmp(a_pRsa), iqmp );
842
843 // Create the RSA private key object
844 rv = createObject( a_hSession, tAttr, ulAttrCount, a_hObject );
845 if ( rv != CKR_OK )
846 goto out;
847
848 rc = 0;
849
850 out:
851 free( n );
852 free( e );
853 free( d );
854 free( p );
855 free( q );
856 free( dmp1 );
857 free( dmq1 );
858 free( iqmp );
859
860 return rc;
861 }
862
863 /*
864 * createRsaKeyObject
865 * Create an RSA key object (both public and private).
866 */
867 int
createRsaKeyObject(RSA * a_pRsa,CK_SESSION_HANDLE a_hSession)868 createRsaKeyObject( RSA *a_pRsa,
869 CK_SESSION_HANDLE a_hSession ) {
870
871 int rc = -1;
872
873 CK_OBJECT_HANDLE hPubObject;
874 CK_OBJECT_HANDLE hPrivObject;
875
876 // Create the RSA public key object
877 if ( createRsaPubKeyObject( a_pRsa, a_hSession, &hPubObject ) == -1 )
878 goto out;
879
880 // Create the RSA private key object
881 if ( createRsaPrivKeyObject( a_pRsa, a_hSession, &hPrivObject ) == -1 ) {
882 // Private key object creation failed, destroy the public
883 // key object just created
884 destroyObject( a_hSession, hPubObject );
885 goto out;
886 }
887
888 rc = 0;
889
890 out:
891 return rc;
892 }
893
894 /*
895 * doRsaPubKey
896 * Process an RSA public key for import.
897 */
898 int
doRsaPubKey(RSA * a_pRsa,CK_SESSION_HANDLE a_hSession)899 doRsaPubKey( RSA *a_pRsa,
900 CK_SESSION_HANDLE a_hSession ) {
901
902 int rc = -1;
903
904 CK_OBJECT_HANDLE hObject;
905
906 if ( destroyRsaPubKeyObject( a_hSession ) == -1 )
907 goto out;
908
909 if ( createRsaPubKeyObject( a_pRsa, a_hSession, &hObject ) == -1 )
910 goto out;
911
912 rc = 0;
913
914 out:
915 return rc;
916 }
917
918 /*
919 * doRsaKey
920 * Process an RSA key for import.
921 */
922 int
doRsaKey(RSA * a_pRsa,CK_SESSION_HANDLE a_hSession)923 doRsaKey( RSA *a_pRsa,
924 CK_SESSION_HANDLE a_hSession ) {
925
926 int rc = -1;
927
928 if ( destroyRsaKeyObject( a_hSession ) == -1 )
929 goto out;
930
931 if ( createRsaKeyObject( a_pRsa, a_hSession ) == -1 )
932 goto out;
933
934 rc = 0;
935
936 out:
937 return rc;
938 }
939
940 /*
941 * getSubjectId
942 * Extract the subject name and key identifier from an
943 * X509 certificate for use as the SUBJECT and ID attributes.
944 */
945 int
getSubjectId(X509 * a_pX509)946 getSubjectId( X509 *a_pX509 ) {
947
948 int rc = -1;
949
950 char *pszReply = NULL;
951
952 X509 *pX509 = a_pX509;
953 X509_NAME *pSubject = NULL;
954 ASN1_OCTET_STRING *pSkid = NULL;
955
956 // Use the Id input file if specified
957 if ( g_pszIdFile )
958 if ( readX509Cert( g_pszIdFile, FALSE, &pX509 ) == -1 )
959 goto out;
960
961 if ( !pX509 ) {
962 // Prompt the user about creating without it.
963 if ( !g_bYes ) {
964 // Prompt for whether to import without the attributes
965 pszReply = getReply( TOKEN_ID_MISSING_PROMPT, 1 );
966 if ( !pszReply ||
967 ( strlen( pszReply ) == 0 ) ||
968 ( strcasecmp( pszReply, TOKEN_ID_NO ) == 0 ) ) {
969 goto out;
970 }
971 }
972
973 rc = 0;
974 goto out;
975 }
976
977 // Get the subject name from the X509 certificate
978 pSubject = X509_get_subject_name( pX509 );
979 if ( !pSubject ) {
980 logInfo( TOKEN_OPENSSL_ERROR,
981 ERR_error_string( ERR_get_error( ), NULL ) );
982 goto out;
983 }
984
985 // Get the DER encoded format of the subject name
986 g_subjectLen = i2d_X509_NAME( pSubject, &g_pchSubject );
987 if ( g_subjectLen < 0 ) {
988 logInfo( TOKEN_OPENSSL_ERROR,
989 ERR_error_string( ERR_get_error( ), NULL ) );
990 goto out;
991 }
992
993 // Get the subject key identifier from the X509 certficate
994 pSkid = X509_get_ext_d2i( pX509, NID_subject_key_identifier, NULL, NULL );
995 if ( !pSkid ) {
996 logInfo( TOKEN_OPENSSL_ERROR,
997 ERR_error_string( ERR_get_error( ), NULL ) );
998 goto out;
999 }
1000
1001 // Get the ASCII string format of the subject key identifier
1002 g_pchId = (CK_BYTE *)i2s_ASN1_OCTET_STRING( NULL, pSkid );
1003 if ( !g_pchId ) {
1004 logInfo( TOKEN_OPENSSL_ERROR,
1005 ERR_error_string( ERR_get_error( ), NULL ) );
1006 goto out;
1007 }
1008 g_ulIdLen = strlen( (char *)g_pchId );
1009
1010 g_bAttrsValid = TRUE;
1011
1012 rc = 0;
1013
1014 out:
1015 // Free the structure if it was created for this function
1016 if ( pX509 && ( pX509 != a_pX509 ) )
1017 X509_free( pX509 );
1018
1019 ASN1_OCTET_STRING_free( pSkid );
1020 free( pszReply );
1021
1022 return rc;
1023 }
1024
1025 int
main(int a_iArgc,char ** a_pszArgv)1026 main( int a_iArgc,
1027 char **a_pszArgv ) {
1028
1029 int rc = 1;
1030
1031 char *pszPin = NULL;
1032
1033 CK_RV rv = CKR_OK;
1034 CK_SESSION_HANDLE hSession = 0;
1035
1036 X509 *pX509 = NULL;
1037 RSA *pPubRsa = NULL;
1038 RSA *pRsa = NULL;
1039
1040 // Set up i18n
1041 initIntlSys( );
1042
1043 // Initialize OpenSSL
1044 OpenSSL_add_all_algorithms( );
1045 ERR_load_crypto_strings( );
1046
1047 // Parse the command
1048 if ( parseCmd( a_iArgc, a_pszArgv ) == -1 )
1049 goto out;
1050
1051 // Open the PKCS#11 TPM Token
1052 rv = openToken( g_pszToken );
1053 if ( rv != CKR_OK )
1054 goto out;
1055
1056 // Make sure the token is initialized
1057 if ( !isTokenInitialized( ) ) {
1058 logMsg( TOKEN_NOT_INIT_ERROR );
1059 goto out;
1060 }
1061
1062 // Create the structures based on the input
1063 if ( !g_pszType ) {
1064 if ( readX509Cert( g_pszFile, TRUE, &pX509 ) == -1 )
1065 goto out;
1066 if ( readRsaKey( g_pszFile, &pRsa ) == -1 )
1067 goto out;
1068 if ( !pX509 && !pRsa ) {
1069 logError( TOKEN_OBJECT_ERROR );
1070 goto out;
1071 }
1072 }
1073 else if ( strcmp( g_pszType, TOKEN_OBJECT_CERT ) == 0 ) {
1074 if ( readX509Cert( g_pszFile, TRUE, &pX509 ) == -1 )
1075 goto out;
1076 if ( !pX509 ) {
1077 logError( TOKEN_OBJECT_ERROR );
1078 goto out;
1079 }
1080 }
1081 else if ( strcmp( g_pszType, TOKEN_OBJECT_KEY ) == 0 ) {
1082 if ( readRsaKey( g_pszFile, &pRsa ) == -1 )
1083 goto out;
1084 if ( !pRsa ) {
1085 logError( TOKEN_OBJECT_ERROR );
1086 goto out;
1087 }
1088 }
1089
1090 // Open a session
1091 rv = openTokenSession( CKF_RW_SESSION, &hSession );
1092 if ( rv != CKR_OK )
1093 goto out;
1094
1095 // Check the scope of the request, which will determine the login
1096 // requirements:
1097 // Public = no password, no login
1098 // Private = user password, user login (default)
1099 if ( !g_bPublic ) {
1100 pszPin = getPlainPasswd( TOKEN_USER_PIN_PROMPT, FALSE );
1101 if ( !pszPin )
1102 goto out;
1103
1104 // Login to the token
1105 rv = loginToken( hSession, CKU_USER, pszPin );
1106 if ( rv != CKR_OK )
1107 goto out;
1108 }
1109
1110 // Obtain the subject name and id, these are used to
1111 // uniquely identify the certificate/key relation
1112 if ( getSubjectId( pX509 ) == -1 ) {
1113 logError( TOKEN_ID_ERROR );
1114 goto out;
1115 }
1116
1117 // Now check for existing objects that may get replaced
1118 // prior to processing the request(s)
1119 if ( pX509 ) {
1120 if ( checkX509Cert( hSession ) == -1 ) {
1121 goto out;
1122 }
1123
1124 // If we are not importing any RSA keys, use the
1125 // public key from the certificate
1126 if ( !pRsa ) {
1127 if ( checkRsaPubKey( hSession ) == -1 ) {
1128 goto out;
1129 }
1130 }
1131
1132 pPubRsa = EVP_PKEY_get1_RSA( X509_get_pubkey( pX509 ) );
1133 }
1134 if ( pRsa ) {
1135 if ( checkRsaKey( hSession ) == -1 ) {
1136 goto out;
1137 }
1138 }
1139
1140 // Process the request(s)
1141 if ( pX509 ) {
1142 if ( doX509Cert( pX509, hSession ) == -1 )
1143 goto out;
1144
1145 // If we are not importing any RSA keys, use the
1146 // public key from the certificate
1147 if ( !pRsa ) {
1148 if ( doRsaPubKey( pPubRsa, hSession ) == -1 )
1149 goto out;
1150 }
1151 }
1152 if ( pRsa ) {
1153 if ( doRsaKey( pRsa, hSession ) == -1 )
1154 goto out;
1155 }
1156
1157 rc = 0;
1158
1159 out:
1160 shredPasswd( pszPin );
1161
1162 if ( hSession )
1163 closeTokenSession( hSession );
1164
1165 closeToken( );
1166
1167 free( g_pszFile );
1168 free( g_pszIdFile );
1169 free( g_pszType );
1170 X509_free( pX509 );
1171 RSA_free( pRsa );
1172 OPENSSL_free( g_pchSubject );
1173 OPENSSL_free( g_pchId );
1174 free( g_pchName );
1175
1176 EVP_cleanup( );
1177
1178 if ( rc == 0 )
1179 logInfo( TOKEN_CMD_SUCCESS, a_pszArgv[ 0 ] );
1180 else
1181 logInfo( TOKEN_CMD_FAILED, a_pszArgv[ 0 ] );
1182
1183 return rc;
1184 }
1185