]>
Commit | Line | Data |
---|---|---|
a0098eda CB |
1 | /********************************************************************************/ |
2 | /* */ | |
3 | /* NVRAM File Abstraction Layer */ | |
4 | /* Written by Ken Goldman */ | |
5 | /* IBM Thomas J. Watson Research Center */ | |
6 | /* $Id: tpm_nvfile.c 4664 2012-01-03 22:15:08Z kgoldman $ */ | |
7 | /* */ | |
8 | /* (c) Copyright IBM Corporation 2006, 2010. */ | |
9 | /* */ | |
10 | /* All rights reserved. */ | |
11 | /* */ | |
12 | /* Redistribution and use in source and binary forms, with or without */ | |
13 | /* modification, are permitted provided that the following conditions are */ | |
14 | /* met: */ | |
15 | /* */ | |
16 | /* Redistributions of source code must retain the above copyright notice, */ | |
17 | /* this list of conditions and the following disclaimer. */ | |
18 | /* */ | |
19 | /* Redistributions in binary form must reproduce the above copyright */ | |
20 | /* notice, this list of conditions and the following disclaimer in the */ | |
21 | /* documentation and/or other materials provided with the distribution. */ | |
22 | /* */ | |
23 | /* Neither the names of the IBM Corporation nor the names of its */ | |
24 | /* contributors may be used to endorse or promote products derived from */ | |
25 | /* this software without specific prior written permission. */ | |
26 | /* */ | |
27 | /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ | |
28 | /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ | |
29 | /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ | |
30 | /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ | |
31 | /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ | |
32 | /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ | |
33 | /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ | |
34 | /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ | |
35 | /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ | |
36 | /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ | |
37 | /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |
38 | /********************************************************************************/ | |
39 | ||
40 | /* This module abstracts out all NVRAM read and write operations. | |
41 | ||
42 | This implementation uses standard, portable C files. | |
43 | ||
44 | The basic high level abstractions are: | |
45 | ||
46 | TPM_NVRAM_LoadData(); | |
47 | TPM_NVRAM_StoreData(); | |
48 | TPM_NVRAM_DeleteName(); | |
49 | ||
50 | They take a 'name' that is mapped to a rooted file name. | |
51 | */ | |
52 | ||
53 | #include <stdio.h> | |
54 | #include <string.h> | |
55 | #include <stdlib.h> | |
56 | #include <errno.h> | |
57 | ||
58 | #include "tpm_debug.h" | |
59 | #include "tpm_error.h" | |
60 | #include "tpm_memory.h" | |
61 | #include "tpm_nvram.h" | |
62 | ||
63 | #include "tpm_nvfile.h" | |
64 | ||
65 | #ifdef TPM_LIBTPMS_CALLBACKS | |
66 | #include "tpm_library_intern.h" | |
7bbb41a1 | 67 | #include "tpm_library.h" |
a0098eda CB |
68 | #endif |
69 | ||
70 | ||
71 | /* local prototypes */ | |
72 | ||
7bd2fb0d SB |
73 | static TPM_RESULT TPM_NVRAM_GetFilenameForName(char *filename, |
74 | size_t filename_len, | |
a0098eda CB |
75 | uint32_t tpm_number, |
76 | const char *name); | |
77 | ||
78 | ||
79 | /* A file name in NVRAM is composed of 3 parts: | |
80 | ||
81 | 1 - 'state_directory' is the rooted path to the TPM state home directory | |
82 | 2 = 'tpm_number' is the TPM instance, 00 for a single TPM | |
83 | 2 - the file name | |
84 | ||
85 | For the IBM cryptographic coprocessor version, the root path is hard coded. | |
86 | ||
87 | For the Linux and Windows versions, the path comes from an environment variable. This variable is | |
88 | used once in TPM_NVRAM_Init(). | |
89 | ||
90 | One root path is used for all virtual TPM's, so it can be a static variable. | |
91 | */ | |
92 | ||
93 | char state_directory[FILENAME_MAX]; | |
94 | ||
95 | /* TPM_NVRAM_Init() is called once at startup. It does any NVRAM required initialization. | |
96 | ||
97 | This function sets some static variables that are used by all TPM's. | |
98 | */ | |
99 | ||
100 | TPM_RESULT TPM_NVRAM_Init(void) | |
101 | { | |
102 | TPM_RESULT rc = 0; | |
103 | char *tpm_state_path; | |
104 | size_t length; | |
105 | ||
106 | #ifdef TPM_LIBTPMS_CALLBACKS | |
107 | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); | |
108 | ||
109 | /* call user-provided function if available, otherwise execute | |
110 | default behavior */ | |
111 | if (cbs->tpm_nvram_init) { | |
112 | rc = cbs->tpm_nvram_init(); | |
113 | return rc; | |
114 | } | |
115 | #endif | |
116 | ||
117 | printf(" TPM_NVRAM_Init:\n"); | |
118 | #ifdef TPM_NV_DISK | |
119 | /* TPM_NV_DISK TPM emulation stores in local directory determined by environment variable. */ | |
120 | if (rc == 0) { | |
121 | tpm_state_path = getenv("TPM_PATH"); | |
122 | if (tpm_state_path == NULL) { | |
123 | printf("TPM_NVRAM_Init: Error (fatal), TPM_PATH environment variable not set\n"); | |
124 | rc = TPM_FAIL; | |
125 | } | |
126 | } | |
127 | #endif | |
128 | /* check that the directory name plus a file name will not overflow FILENAME_MAX */ | |
129 | if (rc == 0) { | |
130 | length = strlen(tpm_state_path); | |
131 | if ((length + TPM_FILENAME_MAX) > FILENAME_MAX) { | |
132 | printf("TPM_NVRAM_Init: Error (fatal), TPM state path name %s too large\n", | |
133 | tpm_state_path); | |
134 | rc = TPM_FAIL; | |
135 | } | |
136 | } | |
137 | if (rc == 0) { | |
048e207b | 138 | strcpy(state_directory, tpm_state_path); |
a0098eda CB |
139 | printf("TPM_NVRAM_Init: Rooted state path %s\n", state_directory); |
140 | } | |
141 | return rc; | |
142 | } | |
143 | ||
144 | /* Load 'data' of 'length' from the 'name'. | |
145 | ||
146 | 'data' must be freed after use. | |
147 | ||
148 | Returns | |
149 | 0 on success. | |
150 | TPM_RETRY and NULL,0 on non-existent file (non-fatal, first time start up) | |
151 | TPM_FAIL on failure to load (fatal), since it should never occur | |
152 | */ | |
153 | ||
154 | TPM_RESULT TPM_NVRAM_LoadData(unsigned char **data, /* freed by caller */ | |
155 | uint32_t *length, | |
156 | uint32_t tpm_number, | |
157 | const char *name) | |
158 | { | |
159 | TPM_RESULT rc = 0; | |
160 | long lrc; | |
161 | size_t src; | |
162 | int irc; | |
163 | FILE *file = NULL; | |
164 | char filename[FILENAME_MAX]; /* rooted file name from name */ | |
165 | ||
166 | #ifdef TPM_LIBTPMS_CALLBACKS | |
7bbb41a1 SB |
167 | struct libtpms_callbacks *cbs; |
168 | bool is_empty_buffer; | |
169 | ||
170 | /* try to get state blob set with TPMLIB_SetState() */ | |
171 | GetCachedState(TPMLIB_NameToStateType(name), data, length, &is_empty_buffer); | |
172 | if (is_empty_buffer) | |
173 | return TPM_RETRY; | |
174 | if (*data) | |
175 | return TPM_SUCCESS; | |
176 | ||
177 | cbs = TPMLIB_GetCallbacks(); | |
a0098eda CB |
178 | |
179 | /* call user-provided function if available, otherwise execute | |
180 | default behavior */ | |
181 | if (cbs->tpm_nvram_loaddata) { | |
182 | rc = cbs->tpm_nvram_loaddata(data, length, tpm_number, name); | |
183 | return rc; | |
184 | } | |
185 | #endif | |
186 | ||
187 | printf(" TPM_NVRAM_LoadData: From file %s\n", name); | |
188 | *data = NULL; | |
189 | *length = 0; | |
190 | /* open the file */ | |
191 | if (rc == 0) { | |
192 | /* map name to the rooted filename */ | |
7bd2fb0d SB |
193 | rc = TPM_NVRAM_GetFilenameForName(filename, sizeof(filename), |
194 | tpm_number, name); | |
195 | } | |
196 | if (rc == 0) { | |
a0098eda CB |
197 | printf(" TPM_NVRAM_LoadData: Opening file %s\n", filename); |
198 | file = fopen(filename, "rb"); /* closed @1 */ | |
199 | if (file == NULL) { /* if failure, determine cause */ | |
200 | if (errno == ENOENT) { | |
201 | printf("TPM_NVRAM_LoadData: No such file %s\n", filename); | |
202 | rc = TPM_RETRY; /* first time start up */ | |
203 | } | |
204 | else { | |
205 | printf("TPM_NVRAM_LoadData: Error (fatal) opening %s for read, %s\n", | |
206 | filename, strerror(errno)); | |
207 | rc = TPM_FAIL; | |
208 | } | |
209 | } | |
210 | } | |
211 | /* determine the file length */ | |
212 | if (rc == 0) { | |
213 | irc = fseek(file, 0L, SEEK_END); /* seek to end of file */ | |
214 | if (irc == -1L) { | |
215 | printf("TPM_NVRAM_LoadData: Error (fatal) fseek'ing %s, %s\n", | |
216 | filename, strerror(errno)); | |
217 | rc = TPM_FAIL; | |
218 | } | |
219 | } | |
220 | if (rc == 0) { | |
221 | lrc = ftell(file); /* get position in the stream */ | |
222 | if (lrc == -1L) { | |
223 | printf("TPM_NVRAM_LoadData: Error (fatal) ftell'ing %s, %s\n", | |
224 | filename, strerror(errno)); | |
225 | rc = TPM_FAIL; | |
226 | } | |
227 | else { | |
228 | *length = (uint32_t)lrc; /* save the length */ | |
229 | } | |
230 | } | |
231 | if (rc == 0) { | |
232 | irc = fseek(file, 0L, SEEK_SET); /* seek back to the beginning of the file */ | |
233 | if (irc == -1L) { | |
234 | printf("TPM_NVRAM_LoadData: Error (fatal) fseek'ing %s, %s\n", | |
235 | filename, strerror(errno)); | |
236 | rc = TPM_FAIL; | |
237 | } | |
238 | } | |
239 | /* allocate a buffer for the actual data */ | |
240 | if ((rc == 0) && *length != 0) { | |
241 | printf(" TPM_NVRAM_LoadData: Reading %u bytes of data\n", *length); | |
242 | rc = TPM_Malloc(data, *length); | |
243 | if (rc != 0) { | |
244 | printf("TPM_NVRAM_LoadData: Error (fatal) allocating %u bytes\n", *length); | |
245 | rc = TPM_FAIL; | |
246 | } | |
247 | } | |
248 | /* read the contents of the file into the data buffer */ | |
249 | if ((rc == 0) && *length != 0) { | |
250 | src = fread(*data, 1, *length, file); | |
251 | if (src != *length) { | |
252 | printf("TPM_NVRAM_LoadData: Error (fatal), data read of %u only read %lu\n", | |
253 | *length, (unsigned long)src); | |
254 | rc = TPM_FAIL; | |
255 | } | |
256 | } | |
257 | /* close the file */ | |
258 | if (file != NULL) { | |
259 | printf(" TPM_NVRAM_LoadData: Closing file %s\n", filename); | |
260 | irc = fclose(file); /* @1 */ | |
261 | if (irc != 0) { | |
262 | printf("TPM_NVRAM_LoadData: Error (fatal) closing file %s\n", filename); | |
263 | rc = TPM_FAIL; | |
264 | } | |
265 | else { | |
266 | printf(" TPM_NVRAM_LoadData: Closed file %s\n", filename); | |
267 | } | |
268 | } | |
269 | return rc; | |
270 | } | |
271 | ||
272 | /* TPM_NVRAM_StoreData stores 'data' of 'length' to the rooted 'filename' | |
273 | ||
274 | Returns | |
275 | 0 on success | |
276 | TPM_FAIL for other fatal errors | |
277 | */ | |
278 | ||
279 | TPM_RESULT TPM_NVRAM_StoreData(const unsigned char *data, | |
280 | uint32_t length, | |
281 | uint32_t tpm_number, | |
282 | const char *name) | |
283 | { | |
284 | TPM_RESULT rc = 0; | |
285 | uint32_t lrc; | |
286 | int irc; | |
287 | FILE *file = NULL; | |
288 | char filename[FILENAME_MAX]; /* rooted file name from name */ | |
289 | ||
290 | #ifdef TPM_LIBTPMS_CALLBACKS | |
291 | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); | |
292 | ||
293 | /* call user-provided function if available, otherwise execute | |
294 | default behavior */ | |
295 | if (cbs->tpm_nvram_storedata) { | |
296 | rc = cbs->tpm_nvram_storedata(data, length, tpm_number, name); | |
297 | return rc; | |
298 | } | |
299 | #endif | |
300 | ||
301 | printf(" TPM_NVRAM_StoreData: To name %s\n", name); | |
302 | if (rc == 0) { | |
303 | /* map name to the rooted filename */ | |
7bd2fb0d SB |
304 | rc = TPM_NVRAM_GetFilenameForName(filename, sizeof(filename), |
305 | tpm_number, name); | |
306 | } | |
307 | if (rc == 0) { | |
a0098eda CB |
308 | /* open the file */ |
309 | printf(" TPM_NVRAM_StoreData: Opening file %s\n", filename); | |
310 | file = fopen(filename, "wb"); /* closed @1 */ | |
311 | if (file == NULL) { | |
312 | printf("TPM_NVRAM_StoreData: Error (fatal) opening %s for write failed, %s\n", | |
313 | filename, strerror(errno)); | |
314 | rc = TPM_FAIL; | |
315 | } | |
316 | } | |
317 | /* write the data to the file */ | |
318 | if (rc == 0) { | |
319 | printf(" TPM_NVRAM_StoreData: Writing %u bytes of data\n", length); | |
320 | lrc = fwrite(data, 1, length, file); | |
321 | if (lrc != length) { | |
322 | printf("TPM_NVRAM_StoreData: Error (fatal), data write of %u only wrote %u\n", | |
323 | length, lrc); | |
324 | rc = TPM_FAIL; | |
325 | } | |
326 | } | |
327 | if (file != NULL) { | |
328 | printf(" TPM_NVRAM_StoreData: Closing file %s\n", filename); | |
329 | irc = fclose(file); /* @1 */ | |
330 | if (irc != 0) { | |
331 | printf("TPM_NVRAM_StoreData: Error (fatal) closing file\n"); | |
332 | rc = TPM_FAIL; | |
333 | } | |
334 | else { | |
335 | printf(" TPM_NVRAM_StoreData: Closed file %s\n", filename); | |
336 | } | |
337 | } | |
338 | return rc; | |
339 | } | |
340 | ||
341 | ||
342 | /* TPM_NVRAM_GetFilenameForName() constructs a rooted file name from the name. | |
343 | ||
344 | The filename is of the form: | |
345 | ||
346 | state_directory/tpm_number.name | |
347 | */ | |
348 | ||
7bd2fb0d SB |
349 | static TPM_RESULT TPM_NVRAM_GetFilenameForName(char *filename, /* output: rooted filename */ |
350 | size_t filename_len, | |
351 | uint32_t tpm_number, | |
352 | const char *name) /* input: abstract name */ | |
a0098eda | 353 | { |
7bd2fb0d SB |
354 | int n; |
355 | TPM_RESULT rc = TPM_FAIL; | |
356 | ||
a0098eda | 357 | printf(" TPM_NVRAM_GetFilenameForName: For name %s\n", name); |
7bd2fb0d SB |
358 | n = snprintf(filename, filename_len, |
359 | "%s/%02lx.%s", state_directory, (unsigned long)tpm_number, | |
360 | name); | |
361 | if (n < 0) { | |
362 | printf(" TPM_NVRAM_GetFilenameForName: Error (fatal), snprintf failed\n"); | |
363 | } else if ((size_t)n >= filename_len) { | |
364 | printf(" TPM_NVRAM_GetFilenameForName: Error (fatal), buffer too small\n"); | |
365 | } else { | |
366 | printf(" TPM_NVRAM_GetFilenameForName: File name %s\n", filename); | |
367 | rc = TPM_SUCCESS; | |
368 | } | |
369 | return rc; | |
a0098eda CB |
370 | } |
371 | ||
372 | /* TPM_NVRAM_DeleteName() deletes the 'name' from NVRAM | |
373 | ||
374 | Returns: | |
375 | 0 on success, or if the file does not exist and mustExist is FALSE | |
376 | TPM_FAIL if the file could not be removed, since this should never occur and there is | |
377 | no recovery | |
378 | ||
379 | NOTE: Not portable code, but supported by Linux and Windows | |
380 | */ | |
381 | ||
382 | TPM_RESULT TPM_NVRAM_DeleteName(uint32_t tpm_number, | |
383 | const char *name, | |
384 | TPM_BOOL mustExist) | |
385 | { | |
386 | TPM_RESULT rc = 0; | |
387 | int irc; | |
388 | char filename[FILENAME_MAX]; /* rooted file name from name */ | |
389 | ||
390 | #ifdef TPM_LIBTPMS_CALLBACKS | |
391 | struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); | |
392 | ||
393 | /* call user-provided function if available, otherwise execute | |
394 | default behavior */ | |
395 | if (cbs->tpm_nvram_deletename) { | |
396 | rc = cbs->tpm_nvram_deletename(tpm_number, name, mustExist); | |
397 | return rc; | |
398 | } | |
399 | #endif | |
400 | ||
401 | printf(" TPM_NVRAM_DeleteName: Name %s\n", name); | |
402 | /* map name to the rooted filename */ | |
7bd2fb0d SB |
403 | if (rc == 0) { |
404 | rc = TPM_NVRAM_GetFilenameForName(filename, sizeof(filename), | |
405 | tpm_number, name); | |
406 | } | |
a0098eda CB |
407 | if (rc == 0) { |
408 | irc = remove(filename); | |
409 | if ((irc != 0) && /* if the remove failed */ | |
410 | (mustExist || /* if any error is a failure, or */ | |
411 | (errno != ENOENT))) { /* if error other than no such file */ | |
412 | printf("TPM_NVRAM_DeleteName: Error, (fatal) file remove failed, errno %d\n", | |
413 | errno); | |
414 | rc = TPM_FAIL; | |
415 | } | |
416 | } | |
417 | return rc; | |
418 | } | |
419 |