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