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_init.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 
33 
34 BOOL  g_bYes      = FALSE;		// Yes/No prompt reply
35 char *g_pszToken  = NULL;		// Token label to be used
36 
37 /*
38  * parseCallback
39  *   Process the command specific options.
40  */
41 int
parseCallback(int a_iOpt,const char * a_pszOptArg)42 parseCallback( int         a_iOpt,
43                const char *a_pszOptArg ) {
44 
45 	switch ( a_iOpt ) {
46 		// Use the specified token label when finding the token
47 		case 'k':
48 			if ( !a_pszOptArg )
49 				return -1;
50 
51 			g_pszToken = strdup( a_pszOptArg );
52 			break;
53 
54 		case 'y':
55 			g_bYes = TRUE;
56 			break;
57 	}
58 
59 	return 0;
60 }
61 
62 /*
63  * usageCallback
64  *   Display command usage information.
65  */
66 void
usageCallback(const char * a_pszCmd)67 usageCallback( const char *a_pszCmd ) {
68 
69 	logCmdHelp( a_pszCmd );
70 	logCmdOption( "-k, --token STRING",
71 			_("Use STRING to identify the label of the PKCS#11 token to be used") );
72 	logCmdOption( "-y, --yes",
73 			_("Reply 'yes' to the clear TPM token prompt") );
74 }
75 
76 /*
77  * parseCmd
78  *   Parse the command line options.
79  */
80 int
parseCmd(int a_iArgc,char ** a_pszArgv)81 parseCmd( int    a_iArgc,
82           char **a_pszArgv ) {
83 
84 	char *pszShortOpts = "k:y";
85 	struct option  stLongOpts[] = {
86 					{ "token", required_argument, NULL, 'k' },
87 					{ "yes", no_argument, NULL, 'y' },
88 				};
89 	int  iNumLongOpts = sizeof( stLongOpts ) / sizeof( struct option );
90 
91 	return genericOptHandler( a_iArgc, a_pszArgv,
92 					pszShortOpts, stLongOpts, iNumLongOpts,
93 					parseCallback, usageCallback );
94 }
95 
96 int
main(int a_iArgc,char ** a_pszArgv)97 main( int    a_iArgc,
98       char **a_pszArgv ) {
99 
100 	int  rc = 1;
101 
102 	// Create buffers for PIN prompts for formatting using sprintf
103 	char  szSoNewPinPrompt[ strlen( TOKEN_SO_NEW_PIN_PROMPT ) + 16 ];
104 	char  szUserNewPinPrompt[ strlen( TOKEN_USER_NEW_PIN_PROMPT ) + 16 ];
105 
106 	char *pszReply      = NULL;
107 	char *pszSoPin      = NULL;
108 	char *pszNewSoPin   = NULL;
109 	char *pszNewUserPin = NULL;
110 
111 	CK_RV              rv       = CKR_OK;
112 	CK_SESSION_HANDLE  hSession = 0;
113 
114 	// Set up i18n
115 	initIntlSys( );
116 
117 	// Parse the command
118 	if ( parseCmd( a_iArgc, a_pszArgv ) == -1 )
119 		goto out;
120 
121 	// Open the PKCS#11 TPM Token
122 	rv = openToken( g_pszToken );
123 	if ( rv != CKR_OK )
124 		goto out;
125 
126 	// Check if the token is already initialized
127 	if ( isTokenInitialized( ) ) {
128 		// Warn and ask the user before clearing
129 		if ( !g_bYes ) {
130 			pszReply = getReply( TOKEN_CLEAR_PROMPT, 1 );
131 			if ( !pszReply ||
132 				( strlen( pszReply ) == 0 ) ||
133 				( strcasecmp( pszReply, TOKEN_CLEAR_NO ) == 0 ) ) {
134 				goto out;
135 			}
136 		}
137 
138 		// Prompt for the current SO password
139 		pszSoPin = getPlainPasswd( TOKEN_SO_PIN_PROMPT, FALSE );
140 		if ( !pszSoPin )
141 			goto out;
142 	}
143 	else
144 		pszSoPin = strdup( TOKEN_SO_INIT_PIN );
145 
146 	// Clear the TPM token
147 	rv = initToken( pszSoPin );
148 	if ( rv != CKR_OK )
149 		goto out;
150 
151 	// Open a session
152 	rv = openTokenSession( CKF_RW_SESSION, &hSession );
153 	if ( rv != CKR_OK )
154 		goto out;
155 
156 	// Login to the token
157 	rv = loginToken( hSession, CKU_SO, TOKEN_SO_INIT_PIN );
158 	if ( rv != CKR_OK )
159 		goto out;
160 
161 	sprintf( szSoNewPinPrompt, TOKEN_SO_NEW_PIN_PROMPT, getMinPinLen( ), getMaxPinLen( ) );
162 	while ( TRUE ) {
163 		// Prompt for a new SO password
164 		pszNewSoPin = getPlainPasswd( szSoNewPinPrompt, TRUE );
165 		if ( !pszNewSoPin )
166 			goto out;
167 
168 		// Set the new password
169 		rv = setPin( hSession, TOKEN_SO_INIT_PIN, pszNewSoPin );
170 		if ( rv == CKR_OK )
171 			break;
172 
173 		if ( ( rv == CKR_PIN_INVALID ) || ( rv == CKR_PIN_LEN_RANGE ) )
174 			logError( TOKEN_INVALID_PIN );
175 		else
176 			goto out;
177 
178 		shredPasswd( pszNewSoPin );
179 	}
180 
181 	// Open a new session
182 	closeTokenSession( hSession );
183 	hSession = 0;
184 	rv = openTokenSession( CKF_RW_SESSION, &hSession );
185 	if ( rv != CKR_OK )
186 		goto out;
187 
188 	// Login to the token
189 	rv = loginToken( hSession, CKU_USER, TOKEN_USER_INIT_PIN );
190 	if ( rv != CKR_OK )
191 		goto out;
192 
193 	sprintf( szUserNewPinPrompt, TOKEN_USER_NEW_PIN_PROMPT, getMinPinLen( ), getMaxPinLen( ) );
194 	while ( TRUE ) {
195 		// Prompt for a new User password
196 		pszNewUserPin = getPlainPasswd( szUserNewPinPrompt, TRUE );
197 		if ( !pszNewUserPin )
198 			goto out;
199 
200 		// Set the new password
201 		rv = setPin( hSession, TOKEN_USER_INIT_PIN, pszNewUserPin );
202 		if ( rv == CKR_OK )
203 			break;
204 
205 		if ( ( rv == CKR_PIN_INVALID ) || ( rv == CKR_PIN_LEN_RANGE ) )
206 			logError( TOKEN_INVALID_PIN );
207 		else
208 			goto out;
209 
210 		shredPasswd( pszNewUserPin );
211 	}
212 
213 	rc = 0;
214 
215 out:
216 	free( pszReply );
217 	shredPasswd( pszSoPin );
218 	shredPasswd( pszNewSoPin );
219 	shredPasswd( pszNewUserPin );
220 
221 	if ( hSession )
222 		closeTokenSession( hSession );
223 
224 	closeToken( );
225 
226 	if ( rc == 0 )
227 		logInfo( TOKEN_CMD_SUCCESS, a_pszArgv[ 0 ] );
228 	else
229 		logInfo( TOKEN_CMD_FAILED, a_pszArgv[ 0 ] );
230 
231 	return rc;
232 }
233