tlcl.c revision 1fe1607679a17a37ab6be390e2f04155e5c37e8e
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 3 * found in the LICENSE file. 4 */ 5 6/* A lightweight TPM command library. 7 * 8 * The general idea is that TPM commands are array of bytes whose 9 * fields are mostly compile-time constant. The goal is to build much 10 * of the commands at compile time (or build time) and change some of 11 * the fields at run time as needed. The code in 12 * utility/tlcl_generator.c builds structures containing the commands, 13 * as well as the offsets of the fields that need to be set at run 14 * time. 15 */ 16 17#include "sysincludes.h" 18#include "tlcl.h" 19#include "tlcl_internal.h" 20#include "tlcl_structures.h" 21#include "utility.h" 22 23/* Sets the size field of a TPM command. */ 24static INLINE void SetTpmCommandSize(uint8_t* buffer, uint32_t size) { 25 ToTpmUint32(buffer + sizeof(uint16_t), size); 26} 27 28/* Gets the size field of a TPM command. */ 29POSSIBLY_UNUSED static INLINE int TpmCommandSize(const uint8_t* buffer) { 30 uint32_t size; 31 FromTpmUint32(buffer + sizeof(uint16_t), &size); 32 return (int) size; 33} 34 35/* Gets the code field of a TPM command. */ 36static INLINE int TpmCommandCode(const uint8_t* buffer) { 37 uint32_t code; 38 FromTpmUint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code); 39 return code; 40} 41 42/* Gets the return code field of a TPM result. */ 43static INLINE int TpmReturnCode(const uint8_t* buffer) { 44 return TpmCommandCode(buffer); 45} 46 47/* Sends a TPM command and gets a response. Returns 0 if success or the TPM 48 * error code if error. */ 49static uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response, 50 int max_length) { 51 52 uint32_t result; 53 54#ifdef EXTRA_LOGGING 55 VBDEBUG(("TPM: command: %x%x %x%x%x%x %x%x%x%x\n", 56 request[0], request[1], 57 request[2], request[3], request[4], request[5], 58 request[6], request[7], request[8], request[9])); 59#endif 60 61 result = TlclStubSendReceive(request, TpmCommandSize(request), 62 response, max_length); 63 if (0 != result) { 64 /* Communication with TPM failed, so response is garbage */ 65 VBDEBUG(("TPM: command 0x%x send/receive failed: 0x%x\n", 66 TpmCommandCode(request), result)); 67 return TPM_E_COMMUNICATION_ERROR; 68 } 69 /* Otherwise, use the result code from the response */ 70 result = TpmReturnCode(response); 71 72#ifdef EXTRA_LOGGING 73 VBDEBUG(("TPM: response: %x%x %x%x%x%x %x%x%x%x\n", 74 response[0], response[1], 75 response[2], response[3], response[4], response[5], 76 response[6], response[7], response[8], response[9])); 77#endif 78 79 VBDEBUG(("TPM: command 0x%x returned 0x%x\n", 80 TpmCommandCode(request), result)); 81 82 return result; 83} 84 85 86/* Sends a command and returns the error code. */ 87static uint32_t Send(const uint8_t* command) { 88 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 89 return TlclSendReceive(command, response, sizeof(response)); 90} 91 92/* Exported functions. */ 93 94void TlclLibInit(void) { 95 TlclStubInit(); 96} 97 98uint32_t TlclStartup(void) { 99 VBDEBUG(("TPM: Startup\n")); 100 return Send(tpm_startup_cmd.buffer); 101} 102 103uint32_t TlclResume(void) { 104 VBDEBUG(("TPM: Resume\n")); 105 return Send(tpm_resume_cmd.buffer); 106} 107 108uint32_t TlclSelfTestFull(void) { 109 VBDEBUG(("TPM: Self test full\n")); 110 return Send(tpm_selftestfull_cmd.buffer); 111} 112 113uint32_t TlclContinueSelfTest(void) { 114 VBDEBUG(("TPM: Continue self test\n")); 115 return Send(tpm_continueselftest_cmd.buffer); 116} 117 118uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) { 119 struct s_tpm_nv_definespace_cmd cmd; 120 VBDEBUG(("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size)); 121 Memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd)); 122 ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.index, index); 123 ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm); 124 ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.size, size); 125 return Send(cmd.buffer); 126} 127 128uint32_t TlclWrite(uint32_t index, const void* data, uint32_t length) { 129 struct s_tpm_nv_write_cmd cmd; 130 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 131 const int total_length = 132 kTpmRequestHeaderLength + kWriteInfoLength + length; 133 134 VBDEBUG(("TPM: TlclWrite(0x%x, %d)\n", index, length)); 135 Memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd)); 136 assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE); 137 SetTpmCommandSize(cmd.buffer, total_length); 138 139 ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.index, index); 140 ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.length, length); 141 Memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length); 142 143 return TlclSendReceive(cmd.buffer, response, sizeof(response)); 144} 145 146uint32_t TlclRead(uint32_t index, void* data, uint32_t length) { 147 struct s_tpm_nv_read_cmd cmd; 148 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 149 uint32_t result_length; 150 uint32_t result; 151 152 VBDEBUG(("TPM: TlclRead(0x%x, %d)\n", index, length)); 153 Memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd)); 154 ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.index, index); 155 ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.length, length); 156 157 result = TlclSendReceive(cmd.buffer, response, sizeof(response)); 158 if (result == TPM_SUCCESS && length > 0) { 159 uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; 160 FromTpmUint32(nv_read_cursor, &result_length); 161 nv_read_cursor += sizeof(uint32_t); 162 Memcpy(data, nv_read_cursor, result_length); 163 } 164 165 return result; 166} 167 168uint32_t TlclWriteLock(uint32_t index) { 169 VBDEBUG(("TPM: Write lock 0x%x\n", index)); 170 return TlclWrite(index, NULL, 0); 171} 172 173uint32_t TlclReadLock(uint32_t index) { 174 VBDEBUG(("TPM: Read lock 0x%x\n", index)); 175 return TlclRead(index, NULL, 0); 176} 177 178uint32_t TlclAssertPhysicalPresence(void) { 179 VBDEBUG(("TPM: Asserting physical presence\n")); 180 return Send(tpm_ppassert_cmd.buffer); 181} 182 183uint32_t TlclPhysicalPresenceCMDEnable(void) { 184 VBDEBUG(("TPM: Enable the physical presence command\n")); 185 return Send(tpm_ppenable_cmd.buffer); 186} 187 188uint32_t TlclFinalizePhysicalPresence(void) { 189 VBDEBUG(("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n")); 190 return Send(tpm_finalizepp_cmd.buffer); 191} 192 193uint32_t TlclAssertPhysicalPresenceResult(void) { 194 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 195 return TlclSendReceive(tpm_ppassert_cmd.buffer, response, sizeof(response)); 196} 197 198uint32_t TlclLockPhysicalPresence(void) { 199 VBDEBUG(("TPM: Lock physical presence\n")); 200 return Send(tpm_pplock_cmd.buffer); 201} 202 203uint32_t TlclSetNvLocked(void) { 204 VBDEBUG(("TPM: Set NV locked\n")); 205 return TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0); 206} 207 208int TlclIsOwned(void) { 209 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_PUBEK_SIZE]; 210 uint32_t result; 211 result = TlclSendReceive(tpm_readpubek_cmd.buffer, 212 response, sizeof(response)); 213 return (result != TPM_SUCCESS); 214} 215 216uint32_t TlclForceClear(void) { 217 VBDEBUG(("TPM: Force clear\n")); 218 return Send(tpm_forceclear_cmd.buffer); 219} 220 221uint32_t TlclSetEnable(void) { 222 VBDEBUG(("TPM: Enabling TPM\n")); 223 return Send(tpm_physicalenable_cmd.buffer); 224} 225 226uint32_t TlclClearEnable(void) { 227 VBDEBUG(("TPM: Disabling TPM\n")); 228 return Send(tpm_physicaldisable_cmd.buffer); 229} 230 231uint32_t TlclSetDeactivated(uint8_t flag) { 232 struct s_tpm_physicalsetdeactivated_cmd cmd; 233 VBDEBUG(("TPM: SetDeactivated(%d)\n", flag)); 234 Memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd)); 235 *(cmd.buffer + cmd.deactivated) = flag; 236 return Send(cmd.buffer); 237} 238 239uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS* pflags) { 240 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 241 uint32_t size; 242 uint32_t result = 243 TlclSendReceive(tpm_getflags_cmd.buffer, response, sizeof(response)); 244 if (result != TPM_SUCCESS) 245 return result; 246 FromTpmUint32(response + kTpmResponseHeaderLength, &size); 247 assert(size == sizeof(TPM_PERMANENT_FLAGS)); 248 Memcpy(pflags, 249 response + kTpmResponseHeaderLength + sizeof(size), 250 sizeof(TPM_PERMANENT_FLAGS)); 251 return result; 252} 253 254uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS* vflags) { 255 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 256 uint32_t size; 257 uint32_t result = 258 TlclSendReceive(tpm_getstclearflags_cmd.buffer, response, sizeof(response)); 259 if (result != TPM_SUCCESS) 260 return result; 261 FromTpmUint32(response + kTpmResponseHeaderLength, &size); 262 /* Ugly assertion, but the struct is padded up by one byte. */ 263 assert(size == 7 && sizeof(TPM_STCLEAR_FLAGS) - 1 == 7); 264 Memcpy(vflags, 265 response + kTpmResponseHeaderLength + sizeof(size), 266 sizeof(TPM_STCLEAR_FLAGS)); 267 return result; 268} 269 270uint32_t TlclGetFlags(uint8_t* disable, 271 uint8_t* deactivated, 272 uint8_t *nvlocked) { 273 TPM_PERMANENT_FLAGS pflags; 274 uint32_t result = TlclGetPermanentFlags(&pflags); 275 if (result == TPM_SUCCESS) { 276 if (disable) 277 *disable = pflags.disable; 278 if (deactivated) 279 *deactivated = pflags.deactivated; 280 if (nvlocked) 281 *nvlocked = pflags.nvLocked; 282 VBDEBUG(("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n", 283 pflags.disable, pflags.deactivated, pflags.nvLocked)); 284 } 285 return result; 286} 287 288uint32_t TlclSetGlobalLock(void) { 289 uint32_t x; 290 VBDEBUG(("TPM: Set global lock\n")); 291 return TlclWrite(TPM_NV_INDEX0, (uint8_t*) &x, 0); 292} 293 294uint32_t TlclExtend(int pcr_num, uint8_t* in_digest, uint8_t* out_digest) { 295 struct s_tpm_extend_cmd cmd; 296 uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; 297 uint32_t result; 298 299 Memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); 300 ToTpmUint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); 301 Memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); 302 303 result = TlclSendReceive(cmd.buffer, response, sizeof(response)); 304 if (result != TPM_SUCCESS) 305 return result; 306 307 Memcpy(out_digest, response + kTpmResponseHeaderLength, kPcrDigestLength); 308 return result; 309} 310 311uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) { 312 struct s_tpm_getpermissions_cmd cmd; 313 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; 314 uint8_t* nvdata; 315 uint32_t result; 316 uint32_t size; 317 318 Memcpy(&cmd, &tpm_getpermissions_cmd, sizeof(cmd)); 319 ToTpmUint32(cmd.buffer + tpm_getpermissions_cmd.index, index); 320 result = TlclSendReceive(cmd.buffer, response, sizeof(response)); 321 if (result != TPM_SUCCESS) 322 return result; 323 324 nvdata = response + kTpmResponseHeaderLength + sizeof(size); 325 FromTpmUint32(nvdata + kNvDataPublicPermissionsOffset, permissions); 326 return result; 327} 328