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