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