Many upgrades to tpm_lite.
They include:
- support for local and cross-compilation with emerge;
- support for execution on TPM devices (formerly only linked with emulator);
- added ownership detection command;
- more complete test of space creation and write locking;
- added PPWRITE permission to space creation.
Review URL: http://codereview.chromium.org/870004
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..8f8b208
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,25 @@
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Simple Makefile for local compilation on the platform and cross compilation
+# using emerge.
+
+USE_TPM_EMULATOR ?= 1
+
+default:
+ @echo "Usage: make { local | cross } [ USE_TPM_EMULATOR=0 ]"
+ @exit 1
+
+local:
+ (cd tlcl; $(MAKE) USE_TPM_EMULATOR=$(USE_TPM_EMULATOR))
+ (cd testsuite; $(MAKE) USE_TPM_EMULATOR=$(USE_TPM_EMULATOR) \
+ LOCAL_COMPILATION=1)
+
+cross:
+ (cd tlcl; $(MAKE) USE_TPM_EMULATOR=$(USE_TPM_EMULATOR))
+ (cd testsuite; $(MAKE) USE_TPM_EMULATOR=$(USE_TPM_EMULATOR))
+
+clean:
+ (cd tlcl; $(MAKE) clean)
+ (cd testsuite; $(MAKE) clean)
diff --git a/src/include/tlcl.h b/src/include/tlcl.h
index e644ebe..30c7350 100644
--- a/src/include/tlcl.h
+++ b/src/include/tlcl.h
@@ -11,7 +11,44 @@
#ifndef TPM_LITE_TLCL_H_
#define TPM_LITE_TLCL_H_
+#include <stdarg.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define POSSIBLY_UNUSED __attribute__((unused))
+
+#ifdef __STRICT_ANSI__
+#define INLINE
+#else
+#define INLINE inline
+#endif
+
+/* Outputs an error message and quits the program.
+ */
+static void error(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+/* Outputs a warning and continues.
+ */
+POSSIBLY_UNUSED
+static void warning(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "WARNING: ");
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+#define assert(expr) do { if (!(expr)) { \
+ error("assert fail: %s at %s:%d\n", \
+ #expr, __FILE__, __LINE__); }} while(0)
/* Call this first.
*/
@@ -58,4 +95,8 @@
*/
void TlclSetNvLocked(void);
+/* Returns 1 if the TPM is owned, 0 otherwise.
+ */
+int TlclIsOwned(void);
+
#endif /* TPM_LITE_TLCL_H_ */
diff --git a/src/testsuite/Makefile b/src/testsuite/Makefile
index c646a6b..0211af5 100644
--- a/src/testsuite/Makefile
+++ b/src/testsuite/Makefile
@@ -3,18 +3,35 @@
# found in the LICENSE file.
LIBTLCL = ../tlcl/libtlcl.a
+
+ifeq ($(USE_TPM_EMULATOR),1)
+ifeq ($(LOCAL_COMPILATION),1)
LIBTPM = ../../../../third_party/tpm-emulator/build/tpm/libtpm.a
LIBCRYPTO = ../../../../third_party/tpm-emulator/build/crypto/libcrypto.a
LIBTPMEMU = ../../../../third_party/tpm-emulator/build/tpmd/unix/libtpmemu.a
-LIBS = $(LIBTLCL) $(LIBTPMEMU) $(LIBTPM) $(LIBCRYPTO)
+else
+LIBTPM = ${ROOT}/usr/lib/tpmemu/libtpm.a
+LIBCRYPTO = ${ROOT}/usr/lib/tpmemu/libcrypto.a
+LIBTPMEMU = ${ROOT}/usr/lib/tpmemu/libtpmemu.a
+endif
+LIBGMP = -lgmp
+endif
+
+LIBS = $(LIBTLCL) $(LIBTPMEMU) $(LIBTPM) $(LIBCRYPTO) $(LIBGMP)
CC ?= cc
+CFLAGS += -Werror -Wall
+#CFLAGS += -pedantic -ansi
-readonly: readonly.o $(LIBS)
- $(CC) -g readonly.o -o readonly $(LIBS) -lgmp
+TESTS = tpmtest_readonly
-readonly.o: readonly.c
- cc -g -c -Werror -Wall -pedantic -ansi readonly.c -I../include
+all: $(TESTS)
+
+$(TESTS): tpmtest_%: %.o $(LIBS)
+ $(CC) $(LDFLAGS) -g $< -o $@ $(LIBS)
+
+.c.o:
+ $(CC) $(CFLAGS) -g -c $< -I../include
clean:
- rm -f readonly *.o *~
+ rm -f $(TESTS) *.o *~
diff --git a/src/testsuite/readonly.c b/src/testsuite/readonly.c
index 1707d59..47ee0a4 100644
--- a/src/testsuite/readonly.c
+++ b/src/testsuite/readonly.c
@@ -35,20 +35,23 @@
*/
void InitializeSpaces(void) {
uint32_t zero = 0;
+ uint32_t perm = TPM_NV_PER_WRITE_STCLEAR;
+ printf("Initializing spaces\n");
TlclSetNvLocked(); /* useful only the first time */
- TlclDefineSpace(INDEX0, TPM_NV_PER_WRITE_STCLEAR, 4);
+ TlclDefineSpace(INDEX0, perm, 4);
TlclWrite(INDEX0, (uint8_t *) &zero, 4);
- TlclDefineSpace(INDEX1, TPM_NV_PER_WRITE_STCLEAR, 4);
+ TlclDefineSpace(INDEX1, perm, 4);
TlclWrite(INDEX1, (uint8_t *) &zero, 4);
- TlclDefineSpace(INDEX2, TPM_NV_PER_WRITE_STCLEAR, 4);
+ TlclDefineSpace(INDEX2, perm, 4);
TlclWrite(INDEX2, (uint8_t *) &zero, 4);
- TlclDefineSpace(INDEX3, TPM_NV_PER_WRITE_STCLEAR, 4);
+ TlclDefineSpace(INDEX3, perm, 4);
TlclWrite(INDEX3, (uint8_t *) &zero, 4);
- TlclDefineSpace(INDEX_INITIALIZED, TPM_NV_PER_READ_STCLEAR, 1);
- TlclReadLock(INDEX_INITIALIZED);
+ perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR |
+ TPM_NV_PER_PPWRITE;
+ TlclDefineSpace(INDEX_INITIALIZED, perm, 1);
}
@@ -71,9 +74,10 @@
TlclAssertPhysicalPresence();
- /* Checks if initialization has completed.
+ /* Checks if initialization has completed by trying to read-lock a space
+ * that's created at the end of initialization.
*/
- if (TlclRead(INDEX_INITIALIZED, &c, 1) != TPM_E_DISABLED_CMD) {
+ if (TlclRead(INDEX_INITIALIZED, &c, 0) == TPM_E_BADINDEX) {
/* The initialization did not complete.
*/
InitializeSpaces();
@@ -81,15 +85,27 @@
/* Checks if spaces are OK or messed up.
*/
- if (TlclRead(INDEX0, (uint8_t *) &index_0, sizeof(index_0)) != TPM_SUCCESS ||
- TlclRead(INDEX1, (uint8_t *) &index_1, sizeof(index_1)) != TPM_SUCCESS ||
- TlclRead(INDEX2, (uint8_t *) &index_2, sizeof(index_2)) != TPM_SUCCESS ||
- TlclRead(INDEX3, (uint8_t *) &index_3, sizeof(index_3)) != TPM_SUCCESS) {
+ if (TlclRead(INDEX0, (uint8_t*) &index_0, sizeof(index_0)) != TPM_SUCCESS ||
+ TlclRead(INDEX1, (uint8_t*) &index_1, sizeof(index_1)) != TPM_SUCCESS ||
+ TlclRead(INDEX2, (uint8_t*) &index_2, sizeof(index_2)) != TPM_SUCCESS ||
+ TlclRead(INDEX3, (uint8_t*) &index_3, sizeof(index_3)) != TPM_SUCCESS) {
EnterRecoveryMode();
}
+ /* Writes space, and locks it. Then attempts to write again. I really wish
+ * I could use the imperative.
+ */
+ index_0 += 1;
+ if (TlclWrite(INDEX0, (uint8_t*) &index_0, sizeof(index_0) != TPM_SUCCESS)) {
+ error("could not write index 0\n");
+ }
+ TlclWriteLock(INDEX0);
+ if (TlclWrite(INDEX0, (uint8_t*) &index_0, sizeof(index_0)) == TPM_SUCCESS) {
+ error("index 0 is not locked\n");
+ }
+
/* Done for now.
*/
+ printf("Test completed successfully\n");
exit(0);
}
-
diff --git a/src/tlcl/Makefile b/src/tlcl/Makefile
index bb729e0..a80dd8f 100644
--- a/src/tlcl/Makefile
+++ b/src/tlcl/Makefile
@@ -3,7 +3,14 @@
# found in the LICENSE file.
INCLUDEDIRS = -I../include -I../../../../third_party/tpm-emulator/tpmd/unix
-CFLAGS += -g -Wall -Werror -ansi -pedantic $(INCLUDEDIRS)
+CFLAGS += -g -Wall -Werror $(INCLUDEDIRS)
+# CFLAGS += -ansi -pedantic
+ifeq ($(USE_TPM_EMULATOR),1)
+CFLAGS += -DUSE_TPM_EMULATOR=1
+else
+CFLAGS += -DUSE_TPM_EMULATOR=0
+endif
+
CC ?= cc
libtlcl.a: tlcl.o
diff --git a/src/tlcl/generator.c b/src/tlcl/generator.c
index 1906d5f..f3762f4 100644
--- a/src/tlcl/generator.c
+++ b/src/tlcl/generator.c
@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <tss/tcs.h>
+#include "tlcl.h"
#include "tlcl_internal.h"
#include "tpmextras.h"
@@ -196,6 +197,13 @@
return cmd;
}
+Command* BuildReadPubekCommand(void) {
+ int size = kTpmRequestHeaderLength + sizeof(TPM_NONCE);
+ Command* cmd = newCommand(TPM_ORD_ReadPubek, size);
+ cmd->name = "tpm_readpubek_cmd";
+ return cmd;
+}
+
/* Output the fields of a structure.
*/
void OutputFields(Field* fld) {
@@ -298,6 +306,7 @@
BuildPhysicalPresenceCommand,
BuildStartupCommand,
BuildSelftestfullCommand,
+ BuildReadPubekCommand,
};
static void FreeFields(Field* fld) {
@@ -312,6 +321,7 @@
if (cmd != NULL) {
Command* next_command = cmd->next;
free(cmd);
+ FreeFields(cmd->fields);
FreeCommands(next_command);
}
}
@@ -327,7 +337,7 @@
printf("/* This file is automatically generated */\n\n");
OutputCommands(commands);
- printf("const int kWriteInfoLength = %ld;\n", sizeof(TPM_WRITE_INFO));
+ printf("const int kWriteInfoLength = %d;\n", (int) sizeof(TPM_WRITE_INFO));
FreeCommands(commands);
return 0;
diff --git a/src/tlcl/tlcl.c b/src/tlcl/tlcl.c
index 916fb9f..b505f72 100644
--- a/src/tlcl/tlcl.c
+++ b/src/tlcl/tlcl.c
@@ -14,14 +14,40 @@
#include "tlcl.h"
+#include <errno.h>
+#include <fcntl.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <tss/tcs.h>
+#include <unistd.h>
#include "structures.h"
#include "tlcl_internal.h"
+#if USE_TPM_EMULATOR
#include "tpmemu.h"
+#endif
#include "tpmextras.h"
+/* The file descriptor for the TPM device.
+ */
+int tpm_fd = -1;
+
+/* Print |n| bytes from array |a|, with newlines.
+ */
+static void PrintBytes(uint8_t* a, int n) {
+ int i;
+ for (i = 0; i < n; i++) {
+ printf("%02x ", a[i]);
+ if ((i + 1) % 16 == 0) {
+ printf("\n");
+ }
+ }
+ if (i % 16 != 0) {
+ printf("\n");
+ }
+}
+
/* Gets the tag field of a TPM command.
*/
static INLINE int TpmTag(uint8_t* buffer) {
@@ -33,14 +59,14 @@
/* Sets the size field of a TPM command.
*/
static INLINE void SetTpmCommandSize(uint8_t* buffer, uint32_t size) {
- ToTpmUint32(buffer + 2, size);
+ ToTpmUint32(buffer + sizeof(uint16_t), size);
}
/* Gets the size field of a TPM command.
*/
static INLINE int TpmCommandSize(const uint8_t* buffer) {
uint32_t size;
- FromTpmUint32(buffer + 2, &size);
+ FromTpmUint32(buffer + sizeof(uint16_t), &size);
return (int) size;
}
@@ -48,11 +74,11 @@
*/
static INLINE int TpmCommandCode(const uint8_t* buffer) {
uint32_t code;
- FromTpmUint32(buffer + 6, &code);
+ FromTpmUint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code);
return code;
}
-/* Gets the code field of a TPM result.
+/* Gets the return code field of a TPM result.
*/
static INLINE int TpmReturnCode(const uint8_t* buffer) {
return TpmCommandCode(buffer);
@@ -64,8 +90,38 @@
int command = TpmCommandCode(request);
int result = TpmReturnCode(response);
if (result != TPM_SUCCESS) {
- (warn_only? warning : error)("command 0x%x failed: 0x%x\n",
- command, result);
+ (warn_only? warning : error)("command %d 0x%x failed: %d 0x%x\n",
+ command, command, result, result);
+ }
+}
+
+/* Executes a command on the TPM.
+ */
+void TpmExecute(const uint8_t *in, const uint32_t in_len,
+ uint8_t *out, uint32_t *pout_len) {
+ uint8_t response[TPM_MAX_COMMAND_SIZE];
+ if (in_len <= 0) {
+ error("invalid command length %d\n", in_len);
+ } else if (tpm_fd < 0) {
+ error("the TPM device was not opened. Forgot to call TlclLibinit?\n");
+ } else {
+ int n = write(tpm_fd, in, in_len);
+ if (n != in_len) {
+ error("write failure to TPM device: %s\n", strerror(errno));
+ }
+ n = read(tpm_fd, response, sizeof(response));
+ if (n == 0) {
+ error("null read from TPM device\n");
+ } else if (n < 0) {
+ error("read failure from TPM device: %s\n", strerror(errno));
+ } else {
+ if (n > *pout_len) {
+ error("TPM response too long for output buffer\n");
+ } else {
+ *pout_len = n;
+ memcpy(out, response, n);
+ }
+ }
}
}
@@ -75,7 +131,22 @@
uint32_t response_length = max_length;
int tag, response_tag;
+#if USE_TPM_EMULATOR
tpmemu_execute(request, TpmCommandSize(request), response, &response_length);
+#else
+ TpmExecute(request, TpmCommandSize(request), response, &response_length);
+#endif
+
+ {
+ int x = TpmCommandSize(request);
+ int y = response_length;
+ printf("request (%d bytes): ", x);
+ PrintBytes(request, 10);
+ PrintBytes(request + 10, x - 10);
+ printf("response (%d bytes): ", y);
+ PrintBytes(response, 10);
+ PrintBytes(response + 10, y - 10);
+ }
/* sanity checks */
tag = TpmTag(request);
@@ -105,7 +176,14 @@
*/
void TlclLibinit(void) {
+#if USE_TPM_EMULATOR
tpmemu_init();
+#else
+ tpm_fd = open("/dev/tpm0", O_RDWR);
+ if (tpm_fd < 0) {
+ error("cannot open TPM device: %s\n", strerror(errno));
+ }
+#endif
}
void TlclStartup(void) {
@@ -162,11 +240,15 @@
}
void TlclWriteLock(uint32_t index) {
- (void) TlclWrite(index, NULL, 0);
+ if (TlclWrite(index, NULL, 0) != TPM_SUCCESS) {
+ error("failed to write lock space 0x%x\n", index);
+ }
}
void TlclReadLock(uint32_t index) {
- (void) TlclRead(index, NULL, 0);
+ if (TlclRead(index, NULL, 0) != TPM_SUCCESS) {
+ error("failed to read lock space 0x%x\n", index);
+ }
}
void TlclAssertPhysicalPresence(void) {
@@ -176,3 +258,11 @@
void TlclSetNvLocked(void) {
TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0);
}
+
+int TlclIsOwned(void) {
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_PUBEK_SIZE];
+ uint32_t result;
+ SendReceive(tpm_readpubek_cmd.buffer, response, sizeof(response));
+ result = TpmReturnCode(response);
+ return (result != TPM_SUCCESS);
+}
diff --git a/src/tlcl/tlcl_internal.h b/src/tlcl/tlcl_internal.h
index 1ca71c0..f9a1b7b 100644
--- a/src/tlcl/tlcl_internal.h
+++ b/src/tlcl/tlcl_internal.h
@@ -6,7 +6,6 @@
#ifndef TPM_LITE_TLCL_INTERNAL_H_
#define TPM_LITE_TLCL_INTERNAL_H_
-#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -15,43 +14,6 @@
const bool true = 1;
const bool false = 0;
-#define POSSIBLY_UNUSED __attribute__((unused))
-
-#ifdef __STRICT_ANSI__
-#define INLINE
-#else
-#define INLINE inline
-#endif
-
-/*
- * Output an error message and quit the program.
- */
-static void error(const char *format, ...) {
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, format, ap);
- va_end(ap);
- exit(1);
-}
-
-/*
- * Output a warning and continue.
- */
-POSSIBLY_UNUSED
-static void warning(const char *format, ...) {
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "WARNING: ");
- vfprintf(stderr, format, ap);
- va_end(ap);
- exit(1);
-}
-
-#define assert(expr) do { if (!(expr)) { \
- error("assert fail: %s at %s:%d\n", \
- #expr, __FILE__, __LINE__); }} while(0)
-
/*
* Conversion functions. ToTpmTYPE puts a value of type TYPE into a TPM
* command buffer. FromTpmTYPE gets a value of type TYPE from a TPM command
diff --git a/src/tlcl/tpmextras.h b/src/tlcl/tpmextras.h
index 7f01348..abd5837 100644
--- a/src/tlcl/tpmextras.h
+++ b/src/tlcl/tpmextras.h
@@ -25,5 +25,6 @@
| TPM_LOC_THREE | TPM_LOC_FOUR) /* 0x1f */
#define TPM_ENCAUTH_SIZE 20
+#define TPM_PUBEK_SIZE 256
#endif