OLD | NEW |
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 */ | 4 */ |
5 | 5 |
6 /* A lightweight TPM command library. | 6 /* A lightweight TPM command library. |
7 * | 7 * |
8 * The general idea is that TPM commands are array of bytes whose fields are | 8 * The general idea is that TPM commands are array of bytes whose fields are |
9 * mostly compile-time constant. The goal is to build much of the commands at | 9 * mostly compile-time constant. The goal is to build much of the commands at |
10 * compile time (or build time) and change some of the fields at run time as | 10 * compile time (or build time) and change some of the fields at run time as |
11 * needed. The code in generator.c builds structures containing the commands, | 11 * needed. The code in generator.c builds structures containing the commands, |
12 * as well as the offsets of the fields that need to be set at run time. | 12 * as well as the offsets of the fields that need to be set at run time. |
13 */ | 13 */ |
14 | 14 |
15 #include "tlcl.h" | 15 #include "tlcl.h" |
16 | 16 |
| 17 #include <errno.h> |
| 18 #include <fcntl.h> |
17 #include <string.h> | 19 #include <string.h> |
| 20 #include <sys/types.h> |
| 21 #include <sys/stat.h> |
18 #include <tss/tcs.h> | 22 #include <tss/tcs.h> |
| 23 #include <unistd.h> |
19 | 24 |
20 #include "structures.h" | 25 #include "structures.h" |
21 #include "tlcl_internal.h" | 26 #include "tlcl_internal.h" |
| 27 #if USE_TPM_EMULATOR |
22 #include "tpmemu.h" | 28 #include "tpmemu.h" |
| 29 #endif |
23 #include "tpmextras.h" | 30 #include "tpmextras.h" |
24 | 31 |
| 32 /* The file descriptor for the TPM device. |
| 33 */ |
| 34 int tpm_fd = -1; |
| 35 |
| 36 /* Print |n| bytes from array |a|, with newlines. |
| 37 */ |
| 38 static void PrintBytes(uint8_t* a, int n) { |
| 39 int i; |
| 40 for (i = 0; i < n; i++) { |
| 41 printf("%02x ", a[i]); |
| 42 if ((i + 1) % 16 == 0) { |
| 43 printf("\n"); |
| 44 } |
| 45 } |
| 46 if (i % 16 != 0) { |
| 47 printf("\n"); |
| 48 } |
| 49 } |
| 50 |
25 /* Gets the tag field of a TPM command. | 51 /* Gets the tag field of a TPM command. |
26 */ | 52 */ |
27 static INLINE int TpmTag(uint8_t* buffer) { | 53 static INLINE int TpmTag(uint8_t* buffer) { |
28 uint16_t tag; | 54 uint16_t tag; |
29 FromTpmUint16(buffer, &tag); | 55 FromTpmUint16(buffer, &tag); |
30 return (int) tag; | 56 return (int) tag; |
31 } | 57 } |
32 | 58 |
33 /* Sets the size field of a TPM command. | 59 /* Sets the size field of a TPM command. |
34 */ | 60 */ |
35 static INLINE void SetTpmCommandSize(uint8_t* buffer, uint32_t size) { | 61 static INLINE void SetTpmCommandSize(uint8_t* buffer, uint32_t size) { |
36 ToTpmUint32(buffer + 2, size); | 62 ToTpmUint32(buffer + sizeof(uint16_t), size); |
37 } | 63 } |
38 | 64 |
39 /* Gets the size field of a TPM command. | 65 /* Gets the size field of a TPM command. |
40 */ | 66 */ |
41 static INLINE int TpmCommandSize(const uint8_t* buffer) { | 67 static INLINE int TpmCommandSize(const uint8_t* buffer) { |
42 uint32_t size; | 68 uint32_t size; |
43 FromTpmUint32(buffer + 2, &size); | 69 FromTpmUint32(buffer + sizeof(uint16_t), &size); |
44 return (int) size; | 70 return (int) size; |
45 } | 71 } |
46 | 72 |
47 /* Gets the code field of a TPM command. | 73 /* Gets the code field of a TPM command. |
48 */ | 74 */ |
49 static INLINE int TpmCommandCode(const uint8_t* buffer) { | 75 static INLINE int TpmCommandCode(const uint8_t* buffer) { |
50 uint32_t code; | 76 uint32_t code; |
51 FromTpmUint32(buffer + 6, &code); | 77 FromTpmUint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code); |
52 return code; | 78 return code; |
53 } | 79 } |
54 | 80 |
55 /* Gets the code field of a TPM result. | 81 /* Gets the return code field of a TPM result. |
56 */ | 82 */ |
57 static INLINE int TpmReturnCode(const uint8_t* buffer) { | 83 static INLINE int TpmReturnCode(const uint8_t* buffer) { |
58 return TpmCommandCode(buffer); | 84 return TpmCommandCode(buffer); |
59 } | 85 } |
60 | 86 |
61 /* Checks for errors in a TPM response. | 87 /* Checks for errors in a TPM response. |
62 */ | 88 */ |
63 static void CheckResult(uint8_t* request, uint8_t* response, bool warn_only) { | 89 static void CheckResult(uint8_t* request, uint8_t* response, bool warn_only) { |
64 int command = TpmCommandCode(request); | 90 int command = TpmCommandCode(request); |
65 int result = TpmReturnCode(response); | 91 int result = TpmReturnCode(response); |
66 if (result != TPM_SUCCESS) { | 92 if (result != TPM_SUCCESS) { |
67 (warn_only? warning : error)("command 0x%x failed: 0x%x\n", | 93 (warn_only? warning : error)("command %d 0x%x failed: %d 0x%x\n", |
68 command, result); | 94 command, command, result, result); |
69 } | 95 } |
70 } | 96 } |
71 | 97 |
| 98 /* Executes a command on the TPM. |
| 99 */ |
| 100 void TpmExecute(const uint8_t *in, const uint32_t in_len, |
| 101 uint8_t *out, uint32_t *pout_len) { |
| 102 uint8_t response[TPM_MAX_COMMAND_SIZE]; |
| 103 if (in_len <= 0) { |
| 104 error("invalid command length %d\n", in_len); |
| 105 } else if (tpm_fd < 0) { |
| 106 error("the TPM device was not opened. Forgot to call TlclLibinit?\n"); |
| 107 } else { |
| 108 int n = write(tpm_fd, in, in_len); |
| 109 if (n != in_len) { |
| 110 error("write failure to TPM device: %s\n", strerror(errno)); |
| 111 } |
| 112 n = read(tpm_fd, response, sizeof(response)); |
| 113 if (n == 0) { |
| 114 error("null read from TPM device\n"); |
| 115 } else if (n < 0) { |
| 116 error("read failure from TPM device: %s\n", strerror(errno)); |
| 117 } else { |
| 118 if (n > *pout_len) { |
| 119 error("TPM response too long for output buffer\n"); |
| 120 } else { |
| 121 *pout_len = n; |
| 122 memcpy(out, response, n); |
| 123 } |
| 124 } |
| 125 } |
| 126 } |
| 127 |
72 /* Sends a request and receive a response. | 128 /* Sends a request and receive a response. |
73 */ | 129 */ |
74 static void SendReceive(uint8_t* request, uint8_t* response, int max_length) { | 130 static void SendReceive(uint8_t* request, uint8_t* response, int max_length) { |
75 uint32_t response_length = max_length; | 131 uint32_t response_length = max_length; |
76 int tag, response_tag; | 132 int tag, response_tag; |
77 | 133 |
| 134 #if USE_TPM_EMULATOR |
78 tpmemu_execute(request, TpmCommandSize(request), response, &response_length); | 135 tpmemu_execute(request, TpmCommandSize(request), response, &response_length); |
| 136 #else |
| 137 TpmExecute(request, TpmCommandSize(request), response, &response_length); |
| 138 #endif |
| 139 |
| 140 { |
| 141 int x = TpmCommandSize(request); |
| 142 int y = response_length; |
| 143 printf("request (%d bytes): ", x); |
| 144 PrintBytes(request, 10); |
| 145 PrintBytes(request + 10, x - 10); |
| 146 printf("response (%d bytes): ", y); |
| 147 PrintBytes(response, 10); |
| 148 PrintBytes(response + 10, y - 10); |
| 149 } |
79 | 150 |
80 /* sanity checks */ | 151 /* sanity checks */ |
81 tag = TpmTag(request); | 152 tag = TpmTag(request); |
82 response_tag = TpmTag(response); | 153 response_tag = TpmTag(response); |
83 assert( | 154 assert( |
84 (tag == TPM_TAG_RQU_COMMAND && | 155 (tag == TPM_TAG_RQU_COMMAND && |
85 response_tag == TPM_TAG_RSP_COMMAND) || | 156 response_tag == TPM_TAG_RSP_COMMAND) || |
86 (tag == TPM_TAG_RQU_AUTH1_COMMAND && | 157 (tag == TPM_TAG_RQU_AUTH1_COMMAND && |
87 response_tag == TPM_TAG_RSP_AUTH1_COMMAND) || | 158 response_tag == TPM_TAG_RSP_AUTH1_COMMAND) || |
88 (tag == TPM_TAG_RQU_AUTH2_COMMAND && | 159 (tag == TPM_TAG_RQU_AUTH2_COMMAND && |
89 response_tag == TPM_TAG_RSP_AUTH2_COMMAND)); | 160 response_tag == TPM_TAG_RSP_AUTH2_COMMAND)); |
90 assert(response_length == TpmCommandSize(response)); | 161 assert(response_length == TpmCommandSize(response)); |
91 } | 162 } |
92 | 163 |
93 /* Sends a command and checks the result for errors. Note that this error | 164 /* Sends a command and checks the result for errors. Note that this error |
94 * checking is only meaningful when running in user mode. TODO: The entire | 165 * checking is only meaningful when running in user mode. TODO: The entire |
95 * error recovery strategy in the firmware needs more work. | 166 * error recovery strategy in the firmware needs more work. |
96 */ | 167 */ |
97 static void Send(uint8_t* command) { | 168 static void Send(uint8_t* command) { |
98 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; | 169 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; |
99 SendReceive(command, response, sizeof(response)); | 170 SendReceive(command, response, sizeof(response)); |
100 CheckResult(command, response, false); | 171 CheckResult(command, response, false); |
101 } | 172 } |
102 | 173 |
103 | 174 |
104 /* Exported functions. | 175 /* Exported functions. |
105 */ | 176 */ |
106 | 177 |
107 void TlclLibinit(void) { | 178 void TlclLibinit(void) { |
| 179 #if USE_TPM_EMULATOR |
108 tpmemu_init(); | 180 tpmemu_init(); |
| 181 #else |
| 182 tpm_fd = open("/dev/tpm0", O_RDWR); |
| 183 if (tpm_fd < 0) { |
| 184 error("cannot open TPM device: %s\n", strerror(errno)); |
| 185 } |
| 186 #endif |
109 } | 187 } |
110 | 188 |
111 void TlclStartup(void) { | 189 void TlclStartup(void) { |
112 Send(tpm_startup_cmd.buffer); | 190 Send(tpm_startup_cmd.buffer); |
113 } | 191 } |
114 | 192 |
115 void TlclSelftestfull(void) { | 193 void TlclSelftestfull(void) { |
116 Send(tpm_selftestfull_cmd.buffer); | 194 Send(tpm_selftestfull_cmd.buffer); |
117 } | 195 } |
118 | 196 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; | 233 uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; |
156 FromTpmUint32(nv_read_cursor, &result_length); | 234 FromTpmUint32(nv_read_cursor, &result_length); |
157 nv_read_cursor += sizeof(uint32_t); | 235 nv_read_cursor += sizeof(uint32_t); |
158 memcpy(data, nv_read_cursor, result_length); | 236 memcpy(data, nv_read_cursor, result_length); |
159 } | 237 } |
160 | 238 |
161 return result; | 239 return result; |
162 } | 240 } |
163 | 241 |
164 void TlclWriteLock(uint32_t index) { | 242 void TlclWriteLock(uint32_t index) { |
165 (void) TlclWrite(index, NULL, 0); | 243 if (TlclWrite(index, NULL, 0) != TPM_SUCCESS) { |
| 244 error("failed to write lock space 0x%x\n", index); |
| 245 } |
166 } | 246 } |
167 | 247 |
168 void TlclReadLock(uint32_t index) { | 248 void TlclReadLock(uint32_t index) { |
169 (void) TlclRead(index, NULL, 0); | 249 if (TlclRead(index, NULL, 0) != TPM_SUCCESS) { |
| 250 error("failed to read lock space 0x%x\n", index); |
| 251 } |
170 } | 252 } |
171 | 253 |
172 void TlclAssertPhysicalPresence(void) { | 254 void TlclAssertPhysicalPresence(void) { |
173 Send(tpm_physicalpresence_cmd.buffer); | 255 Send(tpm_physicalpresence_cmd.buffer); |
174 } | 256 } |
175 | 257 |
176 void TlclSetNvLocked(void) { | 258 void TlclSetNvLocked(void) { |
177 TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0); | 259 TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0); |
178 } | 260 } |
| 261 |
| 262 int TlclIsOwned(void) { |
| 263 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_PUBEK_SIZE]; |
| 264 uint32_t result; |
| 265 SendReceive(tpm_readpubek_cmd.buffer, response, sizeof(response)); |
| 266 result = TpmReturnCode(response); |
| 267 return (result != TPM_SUCCESS); |
| 268 } |
OLD | NEW |