go-attestation/verifier/verifier_test.go
Tom D a801f7333b
Import verifier library into go-attestation. (#13)
* Upstream the verifier sub-library.

* Rename proto package to go_attestation
2019-06-06 10:43:36 -07:00

243 lines
8.9 KiB
Go

package verifier
import (
"crypto/rsa"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"math/big"
"testing"
tpb "github.com/google/go-attestation/proto"
"github.com/google/go-tpm-tools/simulator"
"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpmutil"
)
func decodeBase64(in string, t *testing.T) []byte {
out, err := base64.StdEncoding.DecodeString(in)
if err != nil {
t.Fatal(err)
}
return out
}
func TestVerifyAIK(t *testing.T) {
pub := decodeBase64("AAEACwAFBHIAIJ3/y/NsODrmmfuYaNxty4nXFTiEvigDkiwSQVi/rSKuABAAFAAECAAAAAAAAQC/08gj/04z4xGMIVTmr02lzhI5epufXgU831xEpf2qpXfvtNGUfqTcgWF2EUux2HDPqgcj59dtXRobQdlr4uCGNzfZIGAej4JusLa4MjpG6W2DtJPot6F1Mry63talzJ36U47niy9Iesd34CO2p9Xk3+86ZmBnQ6PQ2roUNK3l7bKz6cFLM9drOLwCqU0AUl6pHvzYPPz+xXsPl3iaA2cM97oneUiJNmJM7wtR9OcaKyIA4wVlX5TndB9NwWq5Iuj8q2Sp40Dg0noXXGSPliAtVD8flkXtAcuI9UHkQbzu9cGPRdSJPMn743GONg3bYalFtcgh2VpACXkPbXB32J7B", t)
creation := decodeBase64("AAAAAAAg47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFUBAAsAIgALWI9hwDRB3zYSkannqM5z0J1coQNA1Jz/oCRxJQwTaNwAIgALmyFYBhHeIU3FUKIAPgXFD3NXyasP3siQviDEyH7avu4AAA==", t)
attest := decodeBase64("/1RDR4AaACIAC41+jhmEOue1MZhJjIk79ENar6i15rBvamXLpQnGTBCOAAAAAAAAD3GRNfU4syzJ1jQGATDCDteFC5C4ACIAC3ToMYGy9GXxcf8A0HvOuLOHbU7HPEppM47C7CMcU8TtACBDmJFUFO1f5+BYevaYdd3VtfMCsxIuHhoTZJczzLP2BA==", t)
sig := decodeBase64("ABQABAEALVzJSnKRJU39gHjETaI89/sM1L6HwBPGNekw6NojSW8bwD5/W1cLRDakCsYKUQu68mmbjs8xaIVBRvVM2YWP10tbTWNB0iJc9b8rERhkk3QIIFm/XsiVZsb0mysTxfeh8zygaAKQ/50sYyzp+raD0Ho0mYIRKJOEdQ6chsBflM3eB8mCXGTugUfrET80q3iu0gncaKWbfxQaQUb9ZTPSJrTN64HQ9tlOfnGT+8++WA3hV0NqKMnoAqiI9GZnI5MPXs6XxEncu/GJLJpAYZakBiS74Jvlr34Pur32B4xjm1M25AUGHEIgb6r49S0sV+hzaKu45858lQRMXj01GcyBhw==", t)
verificationResults, err := VerifyAIK(2, &tpb.AikInfo{
TpmAikInfo: &tpb.AikInfo_Tpm20{
Tpm20: &tpb.Tpm20AikInfo{
PublicBlob: pub,
CreationData: creation,
AttestationData: attest,
SignatureData: sig,
},
},
})
if err != nil {
t.Fatalf("VerifyAIK() returned err: %v", err)
}
if !verificationResults.GetSucceeded() {
t.Errorf("verification.Succeeded = %v, want true", verificationResults.GetSucceeded())
}
}
func setupSimulatedTPM(t *testing.T) *simulator.Simulator {
t.Helper()
tpm, err := simulator.Get()
if err != nil {
t.Fatal(err)
}
return tpm
}
func allPCRs(tpm io.ReadWriter, hash tpm2.Algorithm) (map[uint32][]byte, error) {
numPCRs := 24
out := map[uint32][]byte{}
// The TPM 2.0 spec says that the TPM can partially fulfill the
// request. As such, we repeat the command up to 8 times to get all
// 24 PCRs.
for i := 0; i < numPCRs; i++ {
// Build a selection structure, specifying all PCRs we do
// not have the value for.
sel := tpm2.PCRSelection{Hash: hash}
for pcr := 0; pcr < numPCRs; pcr++ {
if _, present := out[uint32(pcr)]; !present {
sel.PCRs = append(sel.PCRs, pcr)
}
}
// Ask the TPM for those PCR values.
ret, err := tpm2.ReadPCRs(tpm, sel)
if err != nil {
return nil, fmt.Errorf("tpm2.ReadPCRs(%+v) failed with err: %v", sel, err)
}
// Keep track of the PCRs we were actually given.
for pcr, digest := range ret {
out[uint32(pcr)] = digest
}
if len(out) == numPCRs {
break
}
}
if len(out) != numPCRs {
return nil, fmt.Errorf("failed to read all PCRs, only read %d", len(out))
}
return out, nil
}
func TestVerifyQuoteTPM20(t *testing.T) {
tpm := setupSimulatedTPM(t)
defer tpm.Close()
if err := tpm.ManufactureReset(); err != nil {
t.Fatalf("Failed to reset TPM: %v", err)
}
// Create the attestation key.
keyHandle, pub, _, _, _, _, err := tpm2.CreatePrimaryEx(tpm, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", tpm2.Public{
Type: tpm2.AlgRSA,
NameAlg: tpm2.AlgSHA256,
Attributes: tpm2.FlagSignerDefault | tpm2.FlagNoDA,
RSAParameters: &tpm2.RSAParams{
Sign: &tpm2.SigScheme{
Alg: tpm2.AlgRSASSA,
Hash: tpm2.AlgSHA256,
},
KeyBits: 2048,
Modulus: big.NewInt(0),
},
})
if err != nil {
t.Fatalf("CreatePrimaryEx() failed: %v", err)
}
defer tpm2.FlushContext(tpm, keyHandle)
for _, alg := range []tpm2.Algorithm{tpm2.AlgSHA1, tpm2.AlgSHA256} {
t.Run(fmt.Sprintf("Alg %x", alg), func(t *testing.T) {
// Generate the quote.
sel := tpm2.PCRSelection{Hash: alg}
numPCRs := 24
for pcr := 0; pcr < numPCRs; pcr++ {
sel.PCRs = append(sel.PCRs, pcr)
}
nonce := []byte{1, 2, 3, 4}
quote, qSig, err := tpm2.Quote(tpm, keyHandle, "", "", nonce, sel, tpm2.AlgNull)
if err != nil {
t.Fatalf("tpm2.Quote() failed: %v", err)
}
sig, err := tpmutil.Pack(qSig.Alg, qSig.RSA.HashAlg, qSig.RSA.Signature)
if err != nil {
t.Fatalf("tpmutil.Pack() failed: %v", err)
}
PCRs, err := allPCRs(tpm, alg)
if err != nil {
t.Fatalf("allPCRs() failed: %v", err)
}
verificationResults, err := VerifyQuote(2, pub, quote, sig, PCRs, nonce)
if err != nil {
t.Errorf("VerifyQuote failed: %v", err)
}
if !verificationResults.Succeeded {
t.Logf("Verification results: %+v", verificationResults)
t.Errorf("verificationResults.succeeded = %v, expected true", verificationResults.Succeeded)
}
})
}
}
func TestRoca(t *testing.T) {
key := &rsa.PublicKey{N: &big.Int{}}
key.N.SetString("944e13208a280c37efc31c3114485e590192adbb8e11c87cad60cdef0037ce99278330d3f471a2538fa667802ed2a3c44a8b7dea826e888d0aa341fd664f7fa7", 16)
if !ROCAVulnerableKey(key) {
t.Errorf("ROCAVulnerableKey() = %v, wanted true", ROCAVulnerableKey(key))
}
}
func TestVerifyQuoteTPM12(t *testing.T) {
tcs := []struct {
PublicHex string
QuoteHex string
SignatureHex string
Nonce []byte
PCRs map[int]string
}{
{
PublicHex: "00000001000100020000000c00000800000000020000000000000100be855eadb504443ec1a85f5894cf9ae6b97fe75c39debe2376d13e49632ea34dc917c99f0ea29c52349eba9b1abfd2a92e814057568338ea68a32a45f92ae23944d0765805489414f9c588778220a3f384b7b2c4be8132515e276eefde7cb807303f7a7d57900f94dda27e6abe5e411026b8be7637483747073fa731643807e4c3d7e6fdad0ea297beaaeb208465aa4906447fcddf1955f5ac0a439295f7b43fbe38d018009456c17426e4ebf1581c99e3a97ff151a0c649335a46ec8189849b4efe932cb3a7d57e2ee45e67a7fcb64da5041604f24fd6153898fbe5d8432d95b2ad5d4b89088f6306f6b1a7d8c55c748838a96d106efc39ce119b11ac51211b",
QuoteHex: "0101000051554f54d45a9b15807eac8d85cd467ec0060815cc687c18a8b93257fea90bba13ede78f0db2d81ae4173c19",
SignatureHex: "33a4260f049c64f7539ab5a5f5adf1c87fc31d9ae5165340636ba96c88b82eb402b46902315c65d0d8b7a861ec8cd3f0d1bb7d264420cb7dca8e3d5862c5ecf5114f3bde50890cbf8c05b95fb0f2c70c816f9e86f247c4377aa58e84f24e6a910ea414664b9cdd1ff4a3522994ec1e1f419a2e1e3f503689e4eb0606c0b3e9a42f4f7b74c937d4d061161390e1790b6561b0d288e3534fd1b62af6a8c232174e1cb1586b863bd20e95e73e52e27a0781c7160672257831eb9b1d5192098495ad2170490c5e52693385e43aeab95069eecdd3f80529fdcc7ff2ef6086c24c06576e53b77e2f88eafb3e9b9fd40d954a7e0ab4c01e5b9a73d5d1841c49924beb64",
Nonce: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
PCRs: map[int]string{
0: "b777654263752ed0bfe13b369cf512b4661eee04",
1: "c2b93db7e6f705f98419a35cc6e46deb639c6a28",
2: "b2a83b0ebf2f8374299a5b2bdfc31ea955ad7236",
3: "b2a83b0ebf2f8374299a5b2bdfc31ea955ad7236",
4: "8f3fe5e128e3f2186bfca0b804900ec9ded96e39",
5: "45a323382bd933f08e7f0e256bc8249e4095b1ec",
6: "ee1b0f997d7517b286bc9d73a4cf742c65a769be",
7: "9d42f8fe8bfd73fba0274c7db891d91fb7861562",
8: "0000000000000000000000000000000000000000",
9: "0000000000000000000000000000000000000000",
10: "0000000000000000000000000000000000000000",
11: "ebb98df76613280f20dc38221143a9e727399486",
12: "575e12d9ec16d6512648f25b65d38b4eb27a2d6d",
13: "a9f1781a95d2e37970d1d73c463157fa016d9858",
14: "fc76feaf714c844cc888ea454ddf97c0ed220b61",
15: "0000000000000000000000000000000000000000",
16: "0000000000000000000000000000000000000000",
17: "ffffffffffffffffffffffffffffffffffffffff",
18: "ffffffffffffffffffffffffffffffffffffffff",
19: "ffffffffffffffffffffffffffffffffffffffff",
20: "ffffffffffffffffffffffffffffffffffffffff",
21: "ffffffffffffffffffffffffffffffffffffffff",
22: "ffffffffffffffffffffffffffffffffffffffff",
23: "0000000000000000000000000000000000000000",
},
},
}
for i, testcase := range tcs {
tc := testcase
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
pub, err := hex.DecodeString(tc.PublicHex)
if err != nil {
t.Fatal(err)
}
quote, err := hex.DecodeString(tc.QuoteHex)
if err != nil {
t.Fatal(err)
}
sig, err := hex.DecodeString(tc.SignatureHex)
if err != nil {
t.Fatal(err)
}
pcrs := make(map[uint32][]byte)
for idx, h := range tc.PCRs {
pcrs[uint32(idx)], err = hex.DecodeString(h)
if err != nil {
t.Fatal(err)
}
}
verificationResults, err := VerifyQuote(1, pub, quote, sig, pcrs, tc.Nonce)
if err != nil {
t.Errorf("VerifyQuote failed: %v", err)
}
if !verificationResults.Succeeded {
t.Errorf("verificationResults.Succeeded = %v, want %v", verificationResults.Succeeded, true)
}
})
}
}