Skip to content

Commit

Permalink
Merge pull request #149 from alexmwu/ak-certs
Browse files Browse the repository at this point in the history
Add AK cert support in VerifyAttestation
  • Loading branch information
josephlr authored Dec 22, 2021
2 parents 23dfe72 + 1b7a889 commit 7692c0c
Show file tree
Hide file tree
Showing 16 changed files with 991 additions and 153 deletions.
1 change: 1 addition & 0 deletions client/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func (k *Key) Attest(opts AttestOpts) (*pb.Attestation, error) {
if attestation.AkPub, err = k.PublicArea().Encode(); err != nil {
return nil, fmt.Errorf("failed to encode public area: %w", err)
}
attestation.AkCert = k.CertDERBytes()
for _, sel := range sels {
quote, err := k.Quote(sel, opts.Nonce)
if err != nil {
Expand Down
14 changes: 13 additions & 1 deletion client/handles.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,28 @@ const (
SRKECCReservedHandle = tpmutil.Handle(0x81000002)
)

// From "TCG EK Credential Profile", v2.3r2 Section 2.2.1.4
const (
// RSA 2048 EK Cert.
EKCertNVIndexRSA uint32 = 0x01c00002
// ECC P256 EK Cert.
EKCertNVIndexECC uint32 = 0x01c0000a
)

// Picked available handles from TPM 2.0 Handles and Localities 2.3.1 - Table 11
// go-tpm-tools will use handles in the range from 0x81008F00 to 0x81008FFF
const (
DefaultAKECCHandle = tpmutil.Handle(0x81008F00)
DefaultAKRSAHandle = tpmutil.Handle(0x81008F01)
)

// NV Indices holding GCE AK Templates
// GCE Attestation Key NV Indices
const (
// RSA 2048 AK.
GceAKCertNVIndexRSA uint32 = 0x01c10000
GceAKTemplateNVIndexRSA uint32 = 0x01c10001
// ECC P256 AK.
GceAKCertNVIndexECC uint32 = 0x01c10002
GceAKTemplateNVIndexECC uint32 = 0x01c10003
)

Expand Down
60 changes: 56 additions & 4 deletions client/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"bytes"
"crypto"
"crypto/subtle"
"crypto/x509"
"fmt"
"io"

Expand All @@ -24,16 +25,29 @@ type Key struct {
pubKey crypto.PublicKey
name tpm2.Name
session session
cert *x509.Certificate
}

// EndorsementKeyRSA generates and loads a key from DefaultEKTemplateRSA.
func EndorsementKeyRSA(rw io.ReadWriter) (*Key, error) {
return NewCachedKey(rw, tpm2.HandleEndorsement, DefaultEKTemplateRSA(), EKReservedHandle)
ekRsa, err := NewCachedKey(rw, tpm2.HandleEndorsement, DefaultEKTemplateRSA(), EKReservedHandle)
if err != nil {
return nil, err
}
// Error ignored, because not all TPMs will have an EK.
ekRsa.cert, _ = getCertificateFromNvram(rw, EKCertNVIndexRSA)
return ekRsa, nil
}

// EndorsementKeyECC generates and loads a key from DefaultEKTemplateECC.
func EndorsementKeyECC(rw io.ReadWriter) (*Key, error) {
return NewCachedKey(rw, tpm2.HandleEndorsement, DefaultEKTemplateECC(), EKECCReservedHandle)
ekEcc, err := NewCachedKey(rw, tpm2.HandleEndorsement, DefaultEKTemplateECC(), EKECCReservedHandle)
if err != nil {
return nil, err
}
// Error ignored, because not all TPMs will have an EK.
ekEcc.cert, _ = getCertificateFromNvram(rw, EKCertNVIndexECC)
return ekEcc, nil
}

// StorageRootKeyRSA generates and loads a key from SRKTemplateRSA.
Expand Down Expand Up @@ -67,14 +81,26 @@ func EndorsementKeyFromNvIndex(rw io.ReadWriter, idx uint32) (*Key, error) {
// function will only work on a GCE VM. Unlike AttestationKeyRSA, this key uses
// the Endorsement Hierarchy and its template loaded from GceAKTemplateNVIndexRSA.
func GceAttestationKeyRSA(rw io.ReadWriter) (*Key, error) {
return EndorsementKeyFromNvIndex(rw, GceAKTemplateNVIndexRSA)
akRsa, err := EndorsementKeyFromNvIndex(rw, GceAKTemplateNVIndexRSA)
if err != nil {
return nil, err
}
// Error ignored, because not all GCE instances will have an AK cert.
akRsa.cert, _ = getCertificateFromNvram(rw, GceAKCertNVIndexRSA)
return akRsa, nil
}

// GceAttestationKeyECC generates and loads the GCE ECC AK. Note that this
// function will only work on a GCE VM. Unlike AttestationKeyECC, this key uses
// the Endorsement Hierarchy and its template loaded from GceAKTemplateNVIndexECC.
func GceAttestationKeyECC(rw io.ReadWriter) (*Key, error) {
return EndorsementKeyFromNvIndex(rw, GceAKTemplateNVIndexECC)
akEcc, err := EndorsementKeyFromNvIndex(rw, GceAKTemplateNVIndexECC)
if err != nil {
return nil, err
}
// Error ignored, because not all GCE instances will have an AK cert.
akEcc.cert, _ = getCertificateFromNvram(rw, GceAKCertNVIndexECC)
return akEcc, nil
}

// KeyFromNvIndex generates and loads a key under the provided parent
Expand Down Expand Up @@ -427,3 +453,29 @@ func (k *Key) Reseal(in *pb.SealedBytes, uOpts UnsealOpts, sOpts SealOpts) (*pb.
func (k *Key) hasAttribute(attr tpm2.KeyProp) bool {
return k.pubArea.Attributes&attr != 0
}

// Cert returns the parsed certificate (or nil) for the given key.
func (k *Key) Cert() *x509.Certificate {
return k.cert
}

// CertDERBytes provides the ASN.1 DER content of the key's certificate. If the
// key does not have a certficate, returns nil.
func (k *Key) CertDERBytes() []byte {
if k.cert == nil {
return nil
}
return k.cert.Raw
}

func getCertificateFromNvram(rw io.ReadWriter, index uint32) (*x509.Certificate, error) {
certASN1, err := tpm2.NVReadEx(rw, tpmutil.Handle(index), tpm2.HandleOwner, "", 0)
if err != nil {
return nil, fmt.Errorf("failed to read certificate from NV index %d: %w", index, err)
}
x509Cert, err := x509.ParseCertificate(certASN1)
if err != nil {
return nil, fmt.Errorf("failed to parse certificate from NV memory: %w", err)
}
return x509Cert, nil
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ module github.com/google/go-tpm-tools
go 1.16

require (
github.com/google/certificate-transparency-go v1.1.1
github.com/google/certificate-transparency-go v1.1.2
github.com/google/go-attestation v0.3.2
github.com/google/go-cmp v0.5.5
github.com/google/go-cmp v0.5.6
github.com/google/go-tpm v0.3.2
github.com/spf13/cobra v1.1.3
google.golang.org/protobuf v1.27.1
Expand Down
Loading

0 comments on commit 7692c0c

Please sign in to comment.