// ValidSigner checks the signature on an attestation and, if so, returns the // principal name for the signer. func (a *Attestation) ValidSigner() (auth.Prin, error) { signer := auth.NewPrin(*a.SignerType, a.SignerKey) switch *a.SignerType { case "tpm": // The PCRs are contained in the Speaker of an auth.Says statement that // makes up the a.SerializedStatement. f, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err) } // A TPM attestation must be an auth.Says. says, ok := f.(auth.Says) if !ok { return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement") } // Signer is tpm; use tpm-specific signature verification. Extract the // PCRs from the issuer name, unmarshal the key as an RSA key, and call // tpm.VerifyQuote(). speaker, ok := says.Speaker.(auth.Prin) if !ok { return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin") } pcrNums, pcrVals, err := extractPCRs(speaker) if err != nil { return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err) } pk, err := extractTPMKey(a.SignerKey) if err != nil { return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err) } if err := tpm.VerifyQuote(pk, a.SerializedStatement, a.Signature, pcrNums, pcrVals); err != nil { return auth.Prin{}, newError("tao: TPM quote failed verification: %s", err) } return signer, nil case "tpm2": // TODO -- tpm2 // The PCRs are contained in the Speaker of an auth.Says statement that // makes up the a.SerializedStatement. f, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err) } // put this back in // A TPM attestation must be an auth.Says. says, ok := f.(auth.Says) if !ok { return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement") } // Signer is tpm; use tpm-specific signature verification. Extract the // PCRs from the issuer name, unmarshal the key as an RSA key, and call // tpm2.VerifyQuote(). speaker, ok := says.Speaker.(auth.Prin) if !ok { return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin") } key, err := extractTPM2Key(a.SignerKey) if err != nil { return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err) } pcrNums, pcrVal, err := extractTpm2PCRs(speaker) if err != nil { return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err) } ok, err = tpm2.VerifyTpm2Quote(a.SerializedStatement, pcrNums, pcrVal, a.Tpm2QuoteStructure, a.Signature, key) if err != nil { return auth.Prin{}, newError("tao: TPM quote verification error") } if !ok { return auth.Prin{}, newError("tao: TPM quote failed verification") } return signer, nil case "key": // Signer is ECDSA key, use Tao signature verification. v, err := UnmarshalKey(a.SignerKey) if err != nil { return auth.Prin{}, err } ok, err := v.Verify(a.SerializedStatement, AttestationSigningContext, a.Signature) if err != nil { return auth.Prin{}, err } if !ok { return auth.Prin{}, newError("tao: attestation signature invalid") } return signer, nil default: return auth.Prin{}, newError("tao: attestation signer principal unrecognized: %s", signer.String()) } }
func TestTPM2TaoAttest(t *testing.T) { // Fix hash_alg_id := uint16(tpm2.AlgTPM_ALG_SHA1) tpmtao, err := NewTPM2Tao("/dev/tpm0", "../tpm2/tmptest", []int{17, 18}) if err != nil { t.Skip("Couldn't create a new TPM Tao:", err) } tt, ok := tpmtao.(*TPM2Tao) if !ok { t.Fatal("Failed to create the right kind of Tao object from NewTPM2Tao") } defer cleanUpTPM2Tao(tt) // Set up a fake key delegation. taoname, err := tpmtao.GetTaoName() if err != nil { t.Fatal("Couldn't get the name of the tao:", err) } stmt := auth.Speaksfor{ Delegate: auth.NewKeyPrin([]byte(`FakeKeyBytes`)), Delegator: taoname, } // Let the TPMTao set up the issuer and time and expiration. a, err := tpmtao.Attest(nil, nil, nil, stmt) if err != nil { t.Fatal("Couldn't attest to a key delegation:", err) } digests, err := tt.ReadPcrs([]int{17, 18}) // tt.pcrs if err != nil { t.Fatal("ReadPcrs failed\n") } var allDigests []byte for i := 0; i < len(digests); i++ { allDigests = append(allDigests, digests[i]...) } computedDigest, err := tpm2.ComputeHashValue(hash_alg_id, allDigests) if err != nil { t.Fatal("Can't compute combined quote digest") } fmt.Printf("Pcr combined digest: %x\n", computedDigest) pms, err := tpm2.UnmarshalCertifyInfo(a.Tpm2QuoteStructure) if err != nil { fmt.Printf("a.Tpm2QuoteStructure: %x\n", a.Tpm2QuoteStructure) t.Fatal("Can't unmarshal quote structure\n") } tpm2.PrintAttestData(pms) key, _ := tt.GetRsaQuoteKey() ok, err = tpm2.VerifyTpm2Quote(a.SerializedStatement, tt.GetPcrNums(), computedDigest, a.Tpm2QuoteStructure, a.Signature, key) if err != nil { t.Fatal("VerifyQuote error") } if !ok { t.Fatal("VerifyQuote succeeds") } }