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