diff --git a/attest/attest.go b/attest/attest.go index 424622a..4d2001a 100644 --- a/attest/attest.go +++ b/attest/attest.go @@ -131,13 +131,24 @@ func (k *AK) Marshal() ([]byte, error) { } // ActivateCredential decrypts the secret using the key to prove that the AK -// was generated on the same TPM as the EK. +// was generated on the same TPM as the EK. This method can be used with TPMs +// that have the default EK, i.e. RSA EK with handle 0x81010001. // // This operation is synonymous with TPM2_ActivateCredential. func (k *AK) ActivateCredential(tpm *TPM, in EncryptedCredential) (secret []byte, err error) { return k.ak.activateCredential(tpm.tpm, in, k.ek) } +// ActivateCredential decrypts the secret using the key to prove that the AK +// was generated on the same TPM as the EK. This method can be used with TPMs +// that have an ECC EK. The 'ek' argument must be one of EKs returned from +// TPM.EKs() or TPM.EKCertificates(). +// +// This operation is synonymous with TPM2_ActivateCredential. +func (k *AK) ActivateCredentialWithEK(tpm *TPM, in EncryptedCredential, ek EK) (secret []byte, err error) { + return k.ak.activateCredential(tpm.tpm, in, &ek) +} + // Quote returns a quote over the platform state, signed by the AK. // // This is a low-level API. Consumers seeking to attest the state of the diff --git a/attest/attest_simulated_tpm20_test.go b/attest/attest_simulated_tpm20_test.go index af01f39..74ff7f7 100644 --- a/attest/attest_simulated_tpm20_test.go +++ b/attest/attest_simulated_tpm20_test.go @@ -115,11 +115,7 @@ func testActivateCredential(t *testing.T, useEK bool) { } ek := chooseEK(t, EKs) - var akConfig *AKConfig - if useEK { - akConfig = &AKConfig{EK: &ek} - } - ak, err := tpm.NewAK(akConfig) + ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } @@ -135,7 +131,12 @@ func testActivateCredential(t *testing.T, useEK bool) { t.Fatalf("Generate() failed: %v", err) } - decryptedSecret, err := ak.ActivateCredential(tpm, *challenge) + var decryptedSecret []byte + if useEK { + decryptedSecret, err = ak.ActivateCredentialWithEK(tpm, *challenge, ek) + } else { + decryptedSecret, err = ak.ActivateCredential(tpm, *challenge) + } if err != nil { t.Errorf("ak.ActivateCredential() failed: %v", err) } diff --git a/attest/example_test.go b/attest/example_test.go index 057a237..5a8263a 100644 --- a/attest/example_test.go +++ b/attest/example_test.go @@ -91,12 +91,62 @@ func ExampleAK_credentialActivation() { } } +func ExampleAK_credentialActivationWithEK() { + tpm, err := attest.OpenTPM(nil) + if err != nil { + log.Fatalf("Failed to open TPM: %v", err) + } + defer tpm.Close() + + // Create a new AK. + ak, err := tpm.NewAK(nil) + if err != nil { + log.Fatalf("Failed to create AK: %v", err) + } + defer ak.Close(tpm) + + // Read the EK certificates. + ekCerts, err := tpm.EKCertificates() + if err != nil { + log.Fatalf("Failed to enumerate EKs: %v", err) + } + + // Read parameters necessary to generate a challenge. + ap := ak.AttestationParameters() + + // Try activating with each EK certificate. + for _, ek := range ekCerts { + // Generate a credential activation challenge (usually done on the server). + activation := attest.ActivationParameters{ + TPMVersion: tpm.Version(), + EK: ek.Public, + AK: ap, + } + secret, challenge, err := activation.Generate() + if err != nil { + log.Fatalf("Failed to generate activation challenge: %v", err) + } + + // Challenge the AK & EK properties to recieve the decrypted secret. + decrypted, err := ak.ActivateCredentialWithEK(tpm, *challenge, ek) + if err != nil { + log.Fatalf("Failed to activate credential: %v", err) + } + + // Check that the AK completed the challenge (usually done on the server). + if subtle.ConstantTimeCompare(secret, decrypted) == 0 { + log.Fatal("Activation response did not match secret") + } + } +} + func TestExampleAK(t *testing.T) { if !*testExamples { t.SkipNow() } ExampleAK() ExampleAK_credentialActivation() + ExampleAK_credentialActivationWithEK() } func TestExampleTPM(t *testing.T) {