veyron/tools/principal: Dump out certificate details in `dumpblessings`

Change-Id: I0fa353dd9c9084a7de429ffa7d9d1e7076b54ec1
diff --git a/tools/principal/main.go b/tools/principal/main.go
index 0a80da2..ecfaf16 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -83,18 +83,23 @@
 			wire := security.MarshalBlessings(blessings)
 			fmt.Printf("Blessings          : %v\n", blessings)
 			fmt.Printf("PublicKey          : %v\n", blessings.PublicKey())
-			fmt.Printf("Certificates       : %d chains with (#certificates, #caveats) = ", len(wire.CertificateChains))
+			fmt.Printf("Certificate chains : %d\n", len(wire.CertificateChains))
 			for idx, chain := range wire.CertificateChains {
-				ncaveats := 0
-				for _, cert := range chain {
-					ncaveats += len(cert.Caveats)
+				fmt.Printf("Chain #%d (%d certificates). Root certificate public key: %v\n", idx, len(chain), rootkey(chain))
+				for certidx, cert := range chain {
+					fmt.Printf("  Certificate #%d: %v with ", certidx, cert.Extension)
+					switch n := len(cert.Caveats); n {
+					case 1:
+						fmt.Printf("1 caveat")
+					default:
+						fmt.Printf("%d caveats", n)
+					}
+					fmt.Println("")
+					for cavidx, cav := range cert.Caveats {
+						fmt.Printf("    (%d) %v\n", cavidx, &cav)
+					}
 				}
-				if idx > 0 {
-					fmt.Printf(" + ")
-				}
-				fmt.Printf("(%d, %d)", len(chain), ncaveats)
 			}
-			fmt.Println("")
 			return nil
 		},
 	}
@@ -574,3 +579,14 @@
 	}
 	return name
 }
+
+func rootkey(chain []security.Certificate) string {
+	if len(chain) == 0 {
+		return "<empty certificate chain>"
+	}
+	key, err := security.UnmarshalPublicKey(chain[0].PublicKey)
+	if err != nil {
+		return fmt.Sprintf("<invalid PublicKey: %v>", err)
+	}
+	return fmt.Sprintf("%v", key)
+}
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index d0a18d0..72eb84a 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -21,8 +21,12 @@
     sed -e "s/\([0-9a-f]\{2\}:\)\{15\}[0-9a-f]\{2\}/XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX/g"
 }
 
+rmcaveats() {
+    sed -e "s/security.unixTimeExpiryCaveat([^)]*)/security.unixTimeExpiryCaveat/"
+}
+
 dumpblessings() {
-    ./principal dumpblessings "$1" | rmpublickey
+    ./principal dumpblessings "$1" | rmpublickey | rmcaveats
 }
 
 main() {
@@ -68,7 +72,9 @@
   cat >want <<EOF
 Blessings          : alicereborn(0 caveats)
 PublicKey          : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
-Certificates       : 1 chains with (#certificates, #caveats) = (1, 0)
+Certificate chains : 1
+Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+  Certificate #0: alicereborn with 0 caveats
 EOF
   if ! diff got want; then
   	shell_test::fail "line ${LINENO}"
@@ -78,7 +84,11 @@
   cat >want <<EOF
 Blessings          : alice/friend(1 caveats)
 PublicKey          : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
-Certificates       : 1 chains with (#certificates, #caveats) = (2, 1)
+Certificate chains : 1
+Chain #0 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+  Certificate #0: alice with 0 caveats
+  Certificate #1: friend with 1 caveat
+    (0) security.unixTimeExpiryCaveat
 EOF
   if ! diff got want; then
 	shell_test::fail "line ${LINENO}"
@@ -88,7 +98,13 @@
   cat >want <<EOF
 Blessings          : bob(0 caveats)#alice/friend(1 caveats)
 PublicKey          : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
-Certificates       : 2 chains with (#certificates, #caveats) = (1, 0) + (2, 1)
+Certificate chains : 2
+Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+  Certificate #0: bob with 0 caveats
+Chain #1 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+  Certificate #0: alice with 0 caveats
+  Certificate #1: friend with 1 caveat
+    (0) security.unixTimeExpiryCaveat
 EOF
   if ! diff got want; then
 	shell_test::fail "line ${LINENO}"