diff --git a/attest/tpm.go b/attest/tpm.go index 31217728..51f06542 100644 --- a/attest/tpm.go +++ b/attest/tpm.go @@ -268,6 +268,25 @@ func intelEKURL(ekPub *rsa.PublicKey) string { return intelEKCertServiceURL + url.QueryEscape(base64.URLEncoding.EncodeToString(pubHash.Sum(nil))) } +const ( + manufacturerAMD = "AMD" + amdEKCertServiceURL = "https://ftpm.amd.com/pki/aia/" +) + +func amdEKURL(ekPub *rsa.PublicKey) string { + pubHash := sha256.New() + pubHash.Write([]byte{0x00, 0x00, 0x22, 0x22}) + exp := ekPub.E + if exp == 0 { + exp = int(0x00010001) + } + expBytes := make([]byte, 4) + binary.BigEndian.PutUint32(expBytes, uint32(ekPub.E)) + pubHash.Write(expBytes) + pubHash.Write(ekPub.N.Bytes()) + return amdEKCertServiceURL + url.QueryEscape(fmt.Sprintf("%X", pubHash.Sum(nil)[0:16])) +} + func readEKCertFromNVRAM20(tpm io.ReadWriter, nvramCertIndex tpmutil.Handle) (*x509.Certificate, error) { // By passing nvramCertIndex as our auth handle we're using the NV index // itself as the auth hierarchy, which is the same approach diff --git a/attest/tpm_test.go b/attest/tpm_test.go index 1a385631..3c85b9e2 100644 --- a/attest/tpm_test.go +++ b/attest/tpm_test.go @@ -16,7 +16,7 @@ import ( // // This is the public key from the EK cert that's used for testing tpm2-tools: // https://github.com/tpm2-software/tpm2-tools/blob/master/test/integration/tests/getekcertificate.sh -var testRSAKey = mustParseRSAKey(`-----BEGIN PUBLIC KEY----- +var testIntelRSAKey = mustParseRSAKey(`-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwyDi8kSoYBqs8+AdJsZl JJk1Vi3h2hl+nn8HbEaWE8+2U+mOwsOG/B0TPyyMbMM4tzLwsgi9g4qHej5bvD4d QIToNcfIkGocBbTS0w/b68HbrZUPprFlvUtqhkYDFGFkwMT1nUiQEe8fko3upukA @@ -26,6 +26,23 @@ pE3GeajzKTjdgZfina6Dn1tMoPXeJ8lSLCPFThws5XhZUlEYvURwsYGA7veK5CZ7 zQIDAQAB -----END PUBLIC KEY-----`) +// Created by downloading the binary PEM data from +// https://ftpm.amd.com/pki/aia/D027B3CE6A9B6B56846D2B9935884A88 +// extracting its public key, and formatting it to PEM using +// +// openssl x509 -in ekcert.crt -pubkey +// +// This public key is from the EK cert from a real AMD fTPM platform +var testAMDRSAKey = mustParseRSAKey(`-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo8ID3MRLZQWgq2WIK1qT +e2HQxzZgiDWn6Tzw6uQOoXI1iyO9pxIailRxll2NeK1lRVP/dEKCV+mGwv75T+y2 +MmzpFhUY/O5RtEG8TiocDw6WkHRAJ9A9h1OMP+vD3mPClNoA9/ssB36/0ScmVtYR +0gRkL+cZkAT6qro7xz4eRKLt8KfX6OG/Y9kCfJsKDCtYbc4OavHSf11VgbBLtxm7 +jSVE+pnO+x/om6qwACjZbU4qrq4PUbAxD1S9dJ2cZzKaYSsCA8wMIho0umYa3jGv +eptunXDcE993BlsUGjLNbXC4aWVEtgo9yu98gKqhYGFEx7Mtk5NYOvWoNvcUBe2L +2QIDAQAB +-----END PUBLIC KEY-----`) + func mustParseRSAKey(data string) *rsa.PublicKey { pub, err := parseRSAKey(data) if err != nil { @@ -51,8 +68,16 @@ func parseRSAKey(data string) (*rsa.PublicKey, error) { func TestIntelEKURL(t *testing.T) { want := "https://ekop.intel.com/ekcertservice/WVEG2rRwkQ7m3RpXlUphgo6Y2HLxl18h6ZZkkOAdnBE%3D" - got := intelEKURL(testRSAKey) + got := intelEKURL(testIntelRSAKey) if got != want { t.Fatalf("intelEKURL(), got=%q, want=%q", got, want) } } + +func TestAMDEKURL(t *testing.T) { + want:= "https://ftpm.amd.com/pki/aia/D027B3CE6A9B6B56846D2B9935884A88" + got := amdEKURL(testAMDRSAKey) + if got != want { + t.Fatalf("amdEKURL(), got=%q, want=%q",got,want) + } +} diff --git a/attest/tpm_windows.go b/attest/tpm_windows.go index ccaf1eeb..a3a45793 100644 --- a/attest/tpm_windows.go +++ b/attest/tpm_windows.go @@ -190,6 +190,9 @@ func (t *windowsTPM) eks() ([]EK, error) { if i.Manufacturer.String() == manufacturerIntel { ek.CertificateURL = intelEKURL(pub) } + if i.Manufacturer.String() == manufacturerAMD { + ek.CertificateURL = amdEKURL(pub) + } return []EK{ek}, nil } diff --git a/attest/wrapped_tpm20.go b/attest/wrapped_tpm20.go index 1468c1bd..5495d24c 100644 --- a/attest/wrapped_tpm20.go +++ b/attest/wrapped_tpm20.go @@ -225,6 +225,9 @@ func (t *wrappedTPM20) eks() ([]EK, error) { if i.Manufacturer.String() == manufacturerIntel { certificateURL = intelEKURL(ekPub) } + if i.Manufacturer.String() == manufacturerAMD { + certificateURL = amdEKURL(ekPub) + } return []EK{ { Public: ekPub,