Add support for querying TPM DAD counter on more systems.

Previously only Infineon TPMs were queried.

BUG=none
TEST=Manually checked histograms on the following platforms:
- parrot->nuvoton tpm
- stout->stmicro tpm

Change-Id: I641571f9d63e94f44a402053ef3ff976ef580edb
Reviewed-on: https://chromium-review.googlesource.com/204486
Reviewed-by: Luigi Semenzato <semenzato@chromium.org>
Commit-Queue: Darren Krahn <dkrahn@chromium.org>
Tested-by: Darren Krahn <dkrahn@chromium.org>
diff --git a/init/tcsd.conf b/init/tcsd.conf
index 30c2704..6a76576 100644
--- a/init/tcsd.conf
+++ b/init/tcsd.conf
@@ -50,18 +50,33 @@
     fi
   fi
 
-  # On some TPMs we can check the dictionary-attack counter.
+  # Check the dictionary-attack counter.
   if grep -q "Manufacturer: 0x49465800" /sys/class/misc/tpm0/device/caps; then
+    # Infineon has a vendor-specific capability for this. The following command
+    # queries the TPM_CAP_MFR capability area.
     tpm_command="00 c1 00 00 00 16 00 00 00 65 00 00 00 10 00 00 00 04 00 00 \
                  08 02"
-    count=$(($(tpmc raw $tpm_command | awk 'NR == 3 { print $8; }' || echo 0)))
-    metrics_client -b -e Platform.TPM.DictionaryAttackCounter $count 30 ||
-        logger -t "$UPSTART_JOB" "metrics_client -e: status $?"
-    if [ $count -ne 0 ]; then
-      logger -t "$UPSTART_JOB" "WARNING: Non-zero dictionary attack counter found: $count"
-      metrics_client -b -v TPM.NonZeroDictionaryAttackCounter ||
-          logger -t "$UPSTART_JOB" "metrics_client -v: status $?"
-    fi
+    # The output is vendor-specific; we're interested in the 24th byte. The
+    # output is printed in rows of 8 bytes so we want row 3, field 8.
+    count=$(($(tpmc raw $tpm_command | awk 'NR == 3 { print $8; }')))
+  elif [ -e /sys/class/misc/tpm0/device/caps ]; then
+    # If not Infineon, try to query the TPM_CAP_DA_LOGIC capability area with a
+    # TPM_ET_SRK entity type.
+    tpm_command="00 c1 00 00 00 14 00 00 00 65 00 00 00 19 00 00 00 02 00 04"
+    # The output is a TPM_DA_INFO structure; we're interested in the least
+    # significant byte of the currentCount field (row 3, field 3).
+    count=$(($(tpmc raw $tpm_command | awk 'NR == 3 { print $3; }')))
+  fi
+  if [ "$count" == "" ]; then
+    # Report 100 when we don't know the counter value.
+    count=100
+  fi
+  metrics_client -b -e Platform.TPM.DictionaryAttackCounter $count 100 ||
+      logger -t "$UPSTART_JOB" "metrics_client -e: status $?"
+  if [ $count -ne 0 ]; then
+    logger -t "$UPSTART_JOB" "WARNING: Non-zero dictionary attack counter found: $count"
+    metrics_client -b -v TPM.NonZeroDictionaryAttackCounter ||
+        logger -t "$UPSTART_JOB" "metrics_client -v: status $?"
   fi
 end script