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 "tpm_tspi.h"
23 #include "tpm_utils.h"
24 
25 TSS_HCONTEXT hContext = 0;
26 
27 #ifdef TSS_LIB_IS_12
28 #include <limits.h>
29 
30 //Controled by input options
31 static char in_filename[PATH_MAX] = "", out_filename[PATH_MAX] = "";
32 static BOOL isRevocable = FALSE;
33 static BOOL needGenerateSecret = FALSE;
34 static BOOL inFileSet = FALSE;
35 static BOOL outFileSet = FALSE;
36 
help(const char * aCmd)37 static void help(const char *aCmd)
38 {
39 	logCmdHelp(aCmd);
40 	logCmdOption("-r, --revocable",
41 		     _("Creates a revocable EK instead of the default non-revocable one. Requires [-g -o] or [-i]"));
42 	logCmdOption("-i, --infile FILE",
43 		     _("Filename containing the secret data used to revoke the EK."));
44 	logCmdOption("-g, --generate-secret",
45 		     _("Generates a 20 Bytes secret that is used to revoke the EK. Requires [-o]"));
46 	logCmdOption("-o, --outfile FILE",
47 		     _("Filename to write the secret data generated to revoke the EK."));
48 
49 }
50 
parse(const int aOpt,const char * aArg)51 static int parse(const int aOpt, const char *aArg)
52 {
53 	switch (aOpt){
54 	case 'r':
55 		isRevocable = TRUE;
56 		break;
57 	case 'g':
58 		needGenerateSecret = TRUE;
59 		break;
60 	case 'i':
61 		inFileSet = TRUE;
62 		if (aArg){
63 			strncpy(in_filename, aArg, PATH_MAX);
64 		}
65 		break;
66 	case 'o':
67 		outFileSet = TRUE;
68 		if (aArg){
69 			strncpy(out_filename, aArg, PATH_MAX);
70 		}
71 		break;
72 	default:
73 		return -1;
74 	}
75 	return 0;
76 
77 }
78 
79 static TSS_RESULT
tpmCreateRevEk(TSS_HTPM a_hTpm,TSS_HKEY a_hKey,TSS_VALIDATION * a_pValData,UINT32 * revDataSz,BYTE ** revData)80 tpmCreateRevEk(TSS_HTPM a_hTpm, TSS_HKEY a_hKey,
81 	    TSS_VALIDATION * a_pValData, UINT32 *revDataSz, BYTE **revData)
82 {
83 	TSS_RESULT result = Tspi_TPM_CreateRevocableEndorsementKey(a_hTpm, a_hKey,
84 	a_pValData, revDataSz, revData);
85 	tspiResult("Tspi_TPM_CreateRevocableEndorsementKey", result);
86 	return result;
87 }
88 
readData(UINT32 bytesToRead,BYTE ** buffer)89 static int readData(UINT32 bytesToRead, BYTE **buffer)
90 {
91 	FILE *infile = NULL;
92 	size_t iBytes;
93 	int rc = 0;
94 	BYTE eofile;
95 
96 	__memset(*buffer, 0x00, bytesToRead);
97 	infile = fopen(in_filename, "r");
98 	if ( !infile ){
99 		logError(_("Unable to open input file: %s\n"),
100 				in_filename);
101 		return -1;
102 	}
103 
104 	//Read the data
105 	iBytes = fread( *buffer, 1, bytesToRead, infile );
106 	if ( iBytes < bytesToRead ) {
107 		logError(_("Error: the secret data file %s contains less than %d bytes. Aborting ...\n"),
108 				in_filename, bytesToRead);
109 		rc = -1;
110 	} else if ( (iBytes = fread( &eofile, 1, 1, infile )) ) {
111 		//Test if there's more than 20 bytes
112 		if ( !feof( infile))
113 			logMsg(_("WARNING: Using only the first %d bytes of file %s for secret data\n"),
114 					bytesToRead, in_filename);
115 	} else {
116 		logDebug(_("Read %d bytes of secret data from file %s.\n"),
117 			 bytesToRead, in_filename);
118 	}
119 
120 	fclose( infile);
121 	return rc;
122 }
123 
writeData(UINT32 bytesToWrite,BYTE * buffer)124 static int writeData(UINT32 bytesToWrite, BYTE *buffer)
125 {
126 	FILE *outfile = NULL;
127 	size_t iBytes;
128 	int rc = 0;
129 
130 	logDebug(_("bytesToWrite: %d\n"), bytesToWrite);
131 	outfile = fopen(out_filename, "w");
132 	if ( !outfile ) {
133 		logError(_("Unable to open output file: %s\n"), out_filename);
134 		return -1;
135 	}
136 
137 	//Write data in buffer
138 	iBytes = fwrite( buffer, 1, bytesToWrite, outfile);
139 	if ( iBytes != bytesToWrite ) {
140 		logError(_("Error: Unable to write %d bytes on the file %s.\n"),
141 				 bytesToWrite, out_filename);
142 		rc = -1;
143 	}
144 
145 	logDebug(_("%zd bytes written on file %s.\n"), iBytes, out_filename);
146 	fclose( outfile );
147 	return rc;
148 
149 }
150 #endif
151 
152 static TSS_RESULT
tpmCreateEk(TSS_HTPM a_hTpm,TSS_HKEY a_hKey,TSS_VALIDATION * a_pValData)153 tpmCreateEk(TSS_HTPM a_hTpm, TSS_HKEY a_hKey,
154 	    TSS_VALIDATION * a_pValData)
155 {
156 
157 	TSS_RESULT result = Tspi_TPM_CreateEndorsementKey(a_hTpm, a_hKey,
158 			 a_pValData);
159 	tspiResult("Tspi_TPM_CreateEndorsementKey", result);
160 	return result;
161 }
162 
main(int argc,char ** argv)163 int main(int argc, char **argv)
164 {
165 	TSS_RESULT tResult;
166 	TSS_HTPM hTpm;
167 	TSS_HKEY hEk;
168 	TSS_FLAG fEkAttrs;
169 	int iRc = -1;
170 
171 #ifdef TSS_LIB_IS_12
172 	struct option opts[] = {{"revocable", no_argument, NULL, 'r'},
173 	{"generate-secret", no_argument, NULL, 'g'},
174 	{"infile", required_argument, NULL, 'i'},
175 	{"outfile", required_argument, NULL, 'o'},
176 	};
177 	UINT32 revDataSz;
178 	BYTE revokeData[TPM_SHA1BASED_NONCE_LEN];
179 	BYTE *pRevData;
180 #endif
181 
182 	initIntlSys();
183 
184 #ifdef TSS_LIB_IS_12
185 	if (genericOptHandler(argc, argv, "rgi:o:", opts, sizeof(opts) / sizeof(struct option),
186 			      parse, help) != 0)
187 		goto out;
188 
189 	//Check commands for command hierarchy
190 	if (isRevocable) {
191 		if (needGenerateSecret) {
192 			if (!outFileSet) {
193 				logError(_("Please specify an output file\n"));
194 				goto out;
195 			}
196 			if (inFileSet) {
197 				logError(_("The option -i, --infile is not valid with -g\n"));
198 				goto out;
199 			}
200 		} else if (!inFileSet) {
201 			logError(_("Please specify -i, --infile or -g, --generate-secret\n"));
202 			goto out;
203 		} else if (outFileSet) {
204 			logError(_("The option -o, --outfile is not valid with -i, --infile"));
205 			goto out;
206 		}
207 	}
208 	logDebug("Input file name: %s\n", in_filename);
209 	logDebug("Output file name: %s\n", out_filename);
210 
211 	if (inFileSet) {
212 		pRevData = revokeData;
213 		revDataSz = sizeof(revokeData);
214 		if (readData(revDataSz, &pRevData))
215 			goto out;
216 	} else if (outFileSet) {
217 		FILE *outfile = fopen(out_filename, "w");
218 		if (!outfile) {
219 			iRc = -1;
220 			logError(_("Unable to open output file: %s\n"), out_filename);
221 			goto out;
222 		}
223 		fclose(outfile);
224 
225 		//TPM should generate the revoke data
226 		revDataSz = 0;
227 		pRevData = NULL;
228 	}
229 #else
230 	if (genericOptHandler(argc, argv, NULL, NULL, 0, NULL, NULL) != 0){
231 		logError(_("See man pages for details.\n"));
232 		goto out;
233 	}
234 #endif
235 
236 	if (contextCreate(&hContext) != TSS_SUCCESS)
237 		goto out;
238 
239 	if (contextConnect(hContext) != TSS_SUCCESS)
240 		goto out_close;
241 
242 	if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
243 		goto out_close;
244 
245 	//Initialize EK attributes here
246 	fEkAttrs = TSS_KEY_SIZE_2048 | TSS_KEY_TYPE_LEGACY;
247 	if (contextCreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, fEkAttrs, &hEk) != TSS_SUCCESS)
248 		goto out_close;
249 
250 #ifdef TSS_LIB_IS_12
251 	if (isRevocable){
252 		tResult = tpmCreateRevEk(hTpm, hEk, NULL, &revDataSz, &pRevData);
253 		if (tResult != TSS_SUCCESS)
254 			goto out_close;
255 		//Writes the generated secret into the output file
256 		if (outFileSet) {
257 			if (writeData(revDataSz, pRevData)) {
258 				logError(_("Creating revocable EK succeeded, but writing the EK "
259 					   "revoke authorization to disk failed.\nPrinting the "
260 					   "revoke authorization instead:\n"));
261 				logHex(revDataSz, pRevData);
262 				logError(_("You should record this data, as its the authorization "
263 					   "you'll need to revoke your EK!\n"));
264 				goto out_close;
265 			}
266 		}
267 	} else
268 #endif
269 		tResult = tpmCreateEk(hTpm, hEk, NULL);
270 	if (tResult != TSS_SUCCESS)
271 		goto out_close;
272 
273 	iRc = 0;
274 	logSuccess(argv[0]);
275 
276       out_close:
277 	contextClose(hContext);
278 
279       out:
280 	return iRc;
281 }
282