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 */ 46char *g_pszFile = NULL; // Object import file name 47char *g_pszIdFile = NULL; // Object identification file name 48char *g_pszType = NULL; // Object import type 49int g_bPublic = FALSE; // Public object specifier 50int g_bYes = FALSE; // Yes/No prompt reply 51char *g_pszToken = NULL; // Token label to be used 52 53int g_bAttrsValid = FALSE; 54CK_BYTE *g_pchSubject = NULL; // SUBJECT attribute value 55CK_LONG g_subjectLen = 0; 56CK_BYTE *g_pchId = NULL; // ID attribute value 57CK_ULONG g_ulIdLen = 0; 58CK_BYTE *g_pchName = NULL; // LABEL attribute value 59CK_ULONG g_ulNameLen = 0; 60 61/* 62 * parseCallback 63 * Process the command specific options. 64 */ 65int 66parseCallback( 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 */ 125void 126usageCallback( 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 */ 155int 156parseCmd( 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 */ 195int 196findExistingObjects( 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 */ 235int 236checkExistingObjects( 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 271out: 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 */ 283int 284destroyExistingObjects( 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 309out: 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 */ 319int 320readX509Cert( 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 385out: 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 */ 399int 400checkX509Cert( 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 */ 416int 417destroyX509CertObject( 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 */ 432int 433createX509CertObject( 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 526out: 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 */ 538int 539doX509Cert( 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 552out: 553 return rc; 554} 555 556/* 557 * readRsaKey 558 * Use the OpenSSL library to read a PEM formatted RSA key. 559 */ 560int 561readRsaKey( 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 601out: 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 */ 616int 617checkRsaPubKey( 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 */ 635int 636checkRsaKey( 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 */ 652int 653destroyRsaPubKeyObject( 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 */ 671int 672destroyRsaKeyObject( 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 */ 687int 688createRsaPubKeyObject( 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 745out: 746 free( n ); 747 free( e ); 748 749 return rc; 750} 751 752/* 753 * createRsaPrivKeyObject 754 * Create an RSA private key object. 755 */ 756int 757createRsaPrivKeyObject( 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 840out: 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 */ 857int 858createRsaKeyObject( 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 880out: 881 return rc; 882} 883 884/* 885 * doRsaPubKey 886 * Process an RSA public key for import. 887 */ 888int 889doRsaPubKey( 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 904out: 905 return rc; 906} 907 908/* 909 * doRsaKey 910 * Process an RSA key for import. 911 */ 912int 913doRsaKey( 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 926out: 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 */ 935int 936getSubjectId( 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 1004out: 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 1015int 1016main( 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 1149out: 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