Merge pull request #62 from ericchiang/aik_pub

attest: move public key parsing server side
This commit is contained in:
Eric Chiang 2019-08-07 08:05:08 -07:00 committed by GitHub
commit 3a523cf51f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 155 deletions

View File

@ -21,6 +21,7 @@ import (
"fmt"
"github.com/google/certificate-transparency-go/x509"
"github.com/google/go-tpm/tpm"
"github.com/google/go-tpm/tpm2"
)
@ -89,7 +90,6 @@ type aik interface {
ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error)
Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error)
AttestationParameters() AttestationParameters
Public() crypto.PublicKey
}
// AIK represents a key which can be used for attestation.
@ -129,11 +129,6 @@ func (k *AIK) AttestationParameters() AttestationParameters {
return k.aik.AttestationParameters()
}
// Public returns the public part of the AIK.
func (k *AIK) Public() crypto.PublicKey {
return k.aik.Public()
}
// MintOptions encapsulates parameters for minting keys. This type is defined
// now (despite being empty) for future interface compatibility.
type MintOptions struct {
@ -171,12 +166,16 @@ type PlatformEK struct {
// AttestationParameters describes information about a key which is necessary
// for verifying its properties remotely.
type AttestationParameters struct {
// Public represents the public key in a TPM-version specific encoding.
// For TPM 2.0 devices, this is encoded as a TPMT_PUBLIC structure.
// For TPM 1.2 devices, this is a TPM_PUBKEY structure, as defined in
// Public represents the AIK's canonical encoding. This blob includes the
// public key, as well as signing parameters such as the hash algorithm
// used to generate quotes.
//
// Use ParseAIKPublic to access the key's data.
Public []byte
// For TPM 2.0 devices, Public is encoded as a TPMT_PUBLIC structure.
// For TPM 1.2 devices, Public is a TPM_PUBKEY structure, as defined in
// the TPM Part 2 Structures specification, available at
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011.pdf
Public []byte
// UseTCSDActivationFormat is set when tcsd (trousers daemon) is operating
// as an intermediary between this library and the TPM. A value of true
@ -200,6 +199,52 @@ type AttestationParameters struct {
CreateSignature []byte
}
// AIKPublic holds structured information about an AIK's public key.
type AIKPublic struct {
// Public is the public part of the AIK. This can either be an *rsa.PublicKey or
// and *ecdsa.PublicKey.
Public crypto.PublicKey
// Hash is the hashing algorithm the AIK will use when signing quotes.
Hash crypto.Hash
}
// ParseAIKPublic parses the Public blob from the AttestationParameters,
// returning the public key and signing parameters for the key.
func ParseAIKPublic(version TPMVersion, public []byte) (*AIKPublic, error) {
switch version {
case TPMVersion12:
rsaPub, err := tpm.UnmarshalPubRSAPublicKey(public)
if err != nil {
return nil, fmt.Errorf("parsing public key: %v", err)
}
return &AIKPublic{Public: rsaPub, Hash: crypto.SHA1}, nil
case TPMVersion20:
pub, err := tpm2.DecodePublic(public)
if err != nil {
return nil, fmt.Errorf("parsing TPM public key structure: %v", err)
}
pubKey, err := pub.Key()
if err != nil {
return nil, fmt.Errorf("parsing public key: %v", err)
}
var h crypto.Hash
switch pub.Type {
case tpm2.AlgRSA:
h, err = cryptoHash(pub.RSAParameters.Sign.Hash)
case tpm2.AlgECC:
h, err = cryptoHash(pub.ECCParameters.Sign.Hash)
default:
return nil, fmt.Errorf("unsupported public key type 0x%x", pub.Type)
}
if err != nil {
return nil, fmt.Errorf("invalid public key hash: %v", err)
}
return &AIKPublic{Public: pubKey, Hash: h}, nil
default:
return nil, fmt.Errorf("unknown tpm version 0x%x", version)
}
}
// HashAlg identifies a hashing Algorithm.
type HashAlg uint8

View File

@ -153,6 +153,21 @@ func TestSimTPM20ActivateCredential(t *testing.T) {
}
}
func TestParseAIKPublic20(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
aik, err := tpm.MintAIK(nil)
if err != nil {
t.Fatalf("MintAIK() failed: %v", err)
}
defer aik.Close(tpm)
params := aik.AttestationParameters()
if _, err := ParseAIKPublic(TPMVersion20, params.Public); err != nil {
t.Errorf("parsing AIK public blob: %v", err)
}
}
func TestSimTPM20Quote(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()

View File

@ -27,7 +27,7 @@ var (
tpm12config = &OpenConfig{TPMVersion12}
)
func TestTPM12Info(t *testing.T) {
func openTPM12(t *testing.T) *TPM {
if !*testTPM12 {
t.SkipNow()
}
@ -35,6 +35,11 @@ func TestTPM12Info(t *testing.T) {
if err != nil {
t.Fatalf("Failed to open tpm 1.2: %v", err)
}
return tpm
}
func TestTPM12Info(t *testing.T) {
tpm := openTPM12(t)
defer tpm.Close()
Info, err := tpm.Info()
@ -46,13 +51,7 @@ func TestTPM12Info(t *testing.T) {
}
func TestTPM12PCRs(t *testing.T) {
if !*testTPM12 {
t.SkipNow()
}
tpm, err := OpenTPM(tpm12config)
if err != nil {
t.Fatalf("Failed to open tpm 1.2: %v", err)
}
tpm := openTPM12(t)
defer tpm.Close()
PCRs, _, err := tpm.PCRs()
@ -75,13 +74,7 @@ func TestTPM12PCRs(t *testing.T) {
}
func TestTPM12EKs(t *testing.T) {
if !*testTPM12 {
t.SkipNow()
}
tpm, err := OpenTPM(tpm12config)
if err != nil {
t.Fatalf("Failed to open tpm 1.2: %v", err)
}
tpm := openTPM12(t)
defer tpm.Close()
EKs, err := tpm.EKs()
@ -97,13 +90,7 @@ func TestTPM12EKs(t *testing.T) {
}
func TestMintAIK(t *testing.T) {
if !*testTPM12 {
t.SkipNow()
}
tpm, err := OpenTPM(tpm12config)
if err != nil {
t.Fatalf("failed to open tpm 1.2: %v", err)
}
tpm := openTPM12(t)
defer tpm.Close()
aik, err := tpm.MintAIK(nil)
@ -115,18 +102,14 @@ func TestMintAIK(t *testing.T) {
}
func TestTPMQuote(t *testing.T) {
if !*testTPM12 {
t.SkipNow()
}
nonce := make([]byte, 20)
rand.Read(nonce)
tpm, err := OpenTPM(tpm12config)
if err != nil {
t.Fatalf("Failed to open tpm 1.2: %v", err)
}
tpm := openTPM12(t)
defer tpm.Close()
nonce := make([]byte, 20)
if _, err := rand.Read(nonce); err != nil {
t.Fatalf("reading nonce: %v", err)
}
aik, err := tpm.MintAIK(nil)
if err != nil {
t.Fatalf("MintAIK failed: %v", err)
@ -140,15 +123,23 @@ func TestTPMQuote(t *testing.T) {
t.Logf("Quote{version: %v, quote: %x, signature: %x}\n", quote.Version, quote.Quote, quote.Signature)
}
func TestTPMActivateCredential(t *testing.T) {
if !*testTPM12 {
t.SkipNow()
}
func TestParseAIKPublic12(t *testing.T) {
tpm := openTPM12(t)
defer tpm.Close()
tpm, err := OpenTPM(tpm12config)
aik, err := tpm.MintAIK(nil)
if err != nil {
t.Fatalf("failed to open tpm 1.2: %v", err)
t.Fatalf("MintAIK() failed: %v", err)
}
defer aik.Close(tpm)
params := aik.AttestationParameters()
if _, err := ParseAIKPublic(TPMVersion12, params.Public); err != nil {
t.Errorf("parsing AIK public blob: %v", err)
}
}
func TestTPMActivateCredential(t *testing.T) {
tpm := openTPM12(t)
defer tpm.Close()
aik, err := tpm.MintAIK(nil)

View File

@ -17,10 +17,8 @@
package attest
import (
"crypto"
"fmt"
"github.com/google/go-tpm/tpm"
"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpmutil"
"github.com/google/go-tspi/attestation"
@ -30,20 +28,13 @@ import (
type key12 struct {
blob []byte
public []byte
publicKey crypto.PublicKey
}
func newKey12(blob, public []byte) (aik, error) {
rsaPub, err := tpm.UnmarshalPubRSAPublicKey(public)
if err != nil {
return nil, fmt.Errorf("parsing public key: %v", err)
}
func newKey12(blob, public []byte) aik {
return &key12{
blob: blob,
public: public,
publicKey: rsaPub,
}, nil
blob: blob,
public: public,
}
}
// Marshal represents the key in a persistent format which may be
@ -86,10 +77,6 @@ func (k *key12) Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
}, nil
}
func (k *key12) Public() crypto.PublicKey {
return k.publicKey
}
// AttestationParameters returns information about the AIK.
func (k *key12) AttestationParameters() AttestationParameters {
return AttestationParameters{
@ -107,19 +94,9 @@ type key20 struct {
createData []byte
createAttestation []byte
createSignature []byte
publicKey crypto.PublicKey
}
func newKey20(hnd tpmutil.Handle, blob, public, createData, createAttestation, createSig []byte) (aik, error) {
pub, err := tpm2.DecodePublic(public)
if err != nil {
return nil, fmt.Errorf("parsing TPM public key structure: %v", err)
}
pubKey, err := pub.Key()
if err != nil {
return nil, fmt.Errorf("parsing public key: %v", err)
}
func newKey20(hnd tpmutil.Handle, blob, public, createData, createAttestation, createSig []byte) aik {
return &key20{
hnd: hnd,
blob: blob,
@ -127,8 +104,7 @@ func newKey20(hnd tpmutil.Handle, blob, public, createData, createAttestation, c
createData: createData,
createAttestation: createAttestation,
createSignature: createSig,
publicKey: pubKey,
}, nil
}
}
// Marshal represents the key in a persistent format which may be
@ -197,7 +173,3 @@ func (k *key20) AttestationParameters() AttestationParameters {
CreateSignature: k.createSignature,
}
}
func (k *key20) Public() crypto.PublicKey {
return k.publicKey
}

View File

@ -17,7 +17,6 @@
package attest
import (
"crypto"
"fmt"
tpm1 "github.com/google/go-tpm/tpm"
@ -29,25 +28,14 @@ type key12 struct {
hnd uintptr
pcpKeyName string
public []byte
publicKey crypto.PublicKey
}
func newKey12(hnd uintptr, pcpKeyName string, public []byte) (aik, error) {
rsaPub, err := tpm1.UnmarshalPubRSAPublicKey(public)
if err != nil {
return nil, fmt.Errorf("parsing public key: %v", err)
}
func newKey12(hnd uintptr, pcpKeyName string, public []byte) aik {
return &key12{
hnd: hnd,
pcpKeyName: pcpKeyName,
public: public,
publicKey: rsaPub,
}, nil
}
func (k *key12) Public() crypto.PublicKey {
return k.publicKey
}
}
// Marshal represents the key in a persistent format which may be
@ -127,19 +115,9 @@ type key20 struct {
createData []byte
createAttestation []byte
createSignature []byte
publicKey crypto.PublicKey
}
func newKey20(hnd uintptr, pcpKeyName string, public, createData, createAttest, createSig []byte) (aik, error) {
pub, err := tpm2.DecodePublic(public)
if err != nil {
return nil, fmt.Errorf("parsing TPM public key structure: %v", err)
}
pubKey, err := pub.Key()
if err != nil {
return nil, fmt.Errorf("parsing public key: %v", err)
}
func newKey20(hnd uintptr, pcpKeyName string, public, createData, createAttest, createSig []byte) aik {
return &key20{
hnd: hnd,
pcpKeyName: pcpKeyName,
@ -147,12 +125,7 @@ func newKey20(hnd uintptr, pcpKeyName string, public, createData, createAttest,
createData: createData,
createAttestation: createAttest,
createSignature: createSig,
publicKey: pubKey,
}, nil
}
func (k *key20) Public() crypto.PublicKey {
return k.publicKey
}
}
// Marshal represents the key in a persistent format which may be

View File

@ -274,11 +274,7 @@ func (t *TPM) MintAIK(opts *MintOptions) (*AIK, error) {
if err != nil {
return nil, fmt.Errorf("CreateAIK failed: %v", err)
}
aik, err := newKey12(blob, pub)
if err != nil {
return nil, fmt.Errorf("")
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey12(blob, pub)}, nil
case TPMVersion20:
// TODO(jsonp): Abstract choice of hierarchy & parent.
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
@ -311,12 +307,7 @@ func (t *TPM) MintAIK(opts *MintOptions) (*AIK, error) {
if err != nil {
return nil, fmt.Errorf("failed to pack TPMT_SIGNATURE: %v", err)
}
aik, err := newKey20(keyHandle, blob, pub, creationData, attestation, signature)
if err != nil {
return nil, fmt.Errorf("unpacking public key: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey20(keyHandle, blob, pub, creationData, attestation, signature)}, nil
default:
return nil, fmt.Errorf("unsupported TPM version: %x", t.version)
}
@ -333,11 +324,7 @@ func (t *TPM) loadAIK(opaqueBlob []byte) (*AIK, error) {
switch sKey.TPMVersion {
case TPMVersion12:
aik, err := newKey12(sKey.Blob, sKey.Public)
if err != nil {
return nil, fmt.Errorf("unpacking aik: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey12(sKey.Blob, sKey.Public)}, nil
case TPMVersion20:
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
if err != nil {
@ -347,12 +334,7 @@ func (t *TPM) loadAIK(opaqueBlob []byte) (*AIK, error) {
if hnd, _, err = tpm2.Load(t.rwc, srk, "", sKey.Public, sKey.Blob); err != nil {
return nil, fmt.Errorf("Load() failed: %v", err)
}
aik, err := newKey20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)
if err != nil {
return nil, fmt.Errorf("unpacking aik: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)}, nil
default:
return nil, fmt.Errorf("cannot load AIK with TPM version: %v", sKey.TPMVersion)
}

View File

@ -311,17 +311,9 @@ func (t *TPM) MintAIK(opts *MintOptions) (*AIK, error) {
switch t.version {
case TPMVersion12:
aik, err := newKey12(kh, name, props.RawPublic)
if err != nil {
return nil, fmt.Errorf("unpacking aik: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey12(kh, name, props.RawPublic)}, nil
case TPMVersion20:
aik, err := newKey20(kh, name, props.RawPublic, props.RawCreationData, props.RawAttest, props.RawSignature)
if err != nil {
return nil, fmt.Errorf("unpacking aik: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey20(kh, name, props.RawPublic, props.RawCreationData, props.RawAttest, props.RawSignature)}, nil
default:
return nil, fmt.Errorf("cannot handle TPM version: %v", t.version)
}
@ -343,17 +335,9 @@ func (t *TPM) loadAIK(opaqueBlob []byte) (*AIK, error) {
switch t.version {
case TPMVersion12:
aik, err := newKey12(hnd, sKey.Name, sKey.Public)
if err != nil {
return nil, fmt.Errorf("unpacking aik: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey12(hnd, sKey.Name, sKey.Public)}, nil
case TPMVersion20:
aik, err := newKey20(hnd, sKey.Name, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)
if err != nil {
return nil, fmt.Errorf("unpacking aik: %v", err)
}
return &AIK{aik: aik}, nil
return &AIK{aik: newKey20(hnd, sKey.Name, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)}, nil
default:
return nil, fmt.Errorf("cannot handle TPM version: %v", t.version)
}