mirror of
https://github.com/google/go-attestation.git
synced 2024-12-19 21:17:58 +00:00
Refactor part 1: Refactor logic for keys into structs for each TPM/platform invariant. (#53)
* Refactor serialized keys into own structure, in preparation for making Key an interface. * Refactor key logic into separate structures for each platform/TPMversion invariant. * Implement review feedback
This commit is contained in:
parent
ed3b03ef7f
commit
90e37eacce
108
attest/attest.go
108
attest/attest.go
@ -18,8 +18,10 @@ package attest
|
||||
import (
|
||||
"crypto"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/certificate-transparency-go/x509"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// TPMVersion is used to configure a preference in
|
||||
@ -52,18 +54,33 @@ type OpenConfig struct {
|
||||
TPMVersion TPMVersion
|
||||
}
|
||||
|
||||
// KeyEncoding indicates how an exported TPM key is represented.
|
||||
type KeyEncoding uint8
|
||||
// keyEncoding indicates how an exported TPM key is represented.
|
||||
type keyEncoding uint8
|
||||
|
||||
func (e keyEncoding) String() string {
|
||||
switch e {
|
||||
case keyEncodingInvalid:
|
||||
return "invalid"
|
||||
case keyEncodingOSManaged:
|
||||
return "os-managed"
|
||||
case keyEncodingEncrypted:
|
||||
return "encrypted"
|
||||
case keyEncodingParameterized:
|
||||
return "parameterized"
|
||||
default:
|
||||
return fmt.Sprintf("keyEncoding<%d>", int(e))
|
||||
}
|
||||
}
|
||||
|
||||
// Key encodings
|
||||
const (
|
||||
KeyEncodingInvalid KeyEncoding = iota
|
||||
keyEncodingInvalid keyEncoding = iota
|
||||
// Managed by the OS but loadable by name.
|
||||
KeyEncodingOSManaged
|
||||
keyEncodingOSManaged
|
||||
// Key fully represented but in encrypted form.
|
||||
KeyEncodingEncrypted
|
||||
keyEncodingEncrypted
|
||||
// Parameters stored, but key must be regenerated before use.
|
||||
KeyEncodingParameterized
|
||||
keyEncodingParameterized
|
||||
)
|
||||
|
||||
// KeyPurpose indicates the intended use of the key. It is implied that
|
||||
@ -77,6 +94,49 @@ const (
|
||||
StorageKey
|
||||
)
|
||||
|
||||
type aik interface {
|
||||
Close(*TPM) error
|
||||
Marshal() ([]byte, error)
|
||||
ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error)
|
||||
Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error)
|
||||
Parameters() AIKParameters
|
||||
}
|
||||
|
||||
// AIK represents a key which can be used for attestation.
|
||||
type AIK struct {
|
||||
aik aik
|
||||
}
|
||||
|
||||
// Close unloads the AIK from the system.
|
||||
func (k *AIK) Close(t *TPM) error {
|
||||
return k.aik.Close(t)
|
||||
}
|
||||
|
||||
// Marshal encodes the AIK in a format that can be reloaded with tpm.LoadAIK().
|
||||
// This method exists to allow consumers to store the key persistently and load
|
||||
// it as a later time. Users SHOULD NOT attempt to interpret or extract values
|
||||
// from this blob.
|
||||
func (k *AIK) Marshal() ([]byte, error) {
|
||||
return k.aik.Marshal()
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using the key.
|
||||
// This operation is synonymous with TPM2_ActivateCredential.
|
||||
func (k *AIK) ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
return k.aik.ActivateCredential(tpm, in)
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the AIK.
|
||||
func (k *AIK) Quote(tpm *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
||||
return k.aik.Quote(tpm, nonce, alg)
|
||||
}
|
||||
|
||||
// Parameters returns information about the AIK, typically used to generate
|
||||
// a credential activation challenge.
|
||||
func (k *AIK) Parameters() AIKParameters {
|
||||
return k.aik.Parameters()
|
||||
}
|
||||
|
||||
// MintOptions encapsulates parameters for minting keys. This type is defined
|
||||
// now (despite being empty) for future interface compatibility.
|
||||
type MintOptions struct {
|
||||
@ -111,6 +171,42 @@ type PlatformEK struct {
|
||||
Public crypto.PublicKey
|
||||
}
|
||||
|
||||
// AIKParameters describes information about an AIK. This information
|
||||
// is typically used to generate an activation challenge.
|
||||
type AIKParameters 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
|
||||
// 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
|
||||
|
||||
// Subsequent fields are only populated for AIKs generated on a TPM
|
||||
// implementing version 2.0 of the specification. The specific structures
|
||||
// referenced for each field are defined in the TPM Revision 2, Part 2 -
|
||||
// Structures specification, available here:
|
||||
// https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf
|
||||
|
||||
// CreateData represents the properties of a TPM 2.0 key. It is encoded
|
||||
// as a TPMS_CREATION_DATA structure.
|
||||
CreateData []byte
|
||||
// CreateAttestation represents an assertion as to the details of the key.
|
||||
// It is encoded as a TPMS_ATTEST structure.
|
||||
CreateAttestation []byte
|
||||
// CreateSignature represents a signature of the CreateAttestation structure.
|
||||
// It is encoded as a TPMT_SIGNATURE structure.
|
||||
CreateSignature []byte
|
||||
}
|
||||
|
||||
// HashAlg identifies a hashing Algorithm.
|
||||
type HashAlg uint8
|
||||
|
||||
// Valid hash algorithms.
|
||||
var (
|
||||
HashSHA1 = HashAlg(tpm2.AlgSHA1)
|
||||
HashSHA256 = HashAlg(tpm2.AlgSHA256)
|
||||
)
|
||||
|
||||
var (
|
||||
defaultOpenConfig = &OpenConfig{}
|
||||
|
||||
|
@ -86,16 +86,18 @@ func TestSimTPM20AIKCreateAndLoad(t *testing.T) {
|
||||
t.Fatalf("aik.Close() failed: %v", err)
|
||||
}
|
||||
|
||||
loaded, err := tpm.LoadKey(enc)
|
||||
loaded, err := tpm.LoadAIK(enc)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadKey() failed: %v", err)
|
||||
}
|
||||
defer loaded.Close(tpm)
|
||||
|
||||
if !bytes.Equal(loaded.Public, aik.Public) {
|
||||
k1, k2 := aik.aik.(*key20), loaded.aik.(*key20)
|
||||
|
||||
if !bytes.Equal(k1.public, k2.public) {
|
||||
t.Error("Original & loaded AIK public blobs did not match.")
|
||||
t.Logf("Original = %v", aik.Public)
|
||||
t.Logf("Loaded = %v", loaded.Public)
|
||||
t.Logf("Original = %v", k1.public)
|
||||
t.Logf("Loaded = %v", k2.public)
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +133,7 @@ func TestSimTPM20ActivateCredential(t *testing.T) {
|
||||
}
|
||||
ek := chooseEKPub(t, EKs)
|
||||
|
||||
att, err := tpm2.DecodeAttestationData(aik.CreateAttestation)
|
||||
att, err := tpm2.DecodeAttestationData(aik.aik.(*key20).createAttestation)
|
||||
if err != nil {
|
||||
t.Fatalf("tpm2.DecodeAttestationData() failed: %v", err)
|
||||
}
|
||||
@ -167,7 +169,7 @@ func TestSimTPM20Quote(t *testing.T) {
|
||||
defer aik.Close(tpm)
|
||||
|
||||
nonce := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
quote, err := aik.Quote(tpm, nonce, tpm2.AlgSHA256)
|
||||
quote, err := aik.Quote(tpm, nonce, HashSHA256)
|
||||
if err != nil {
|
||||
t.Fatalf("aik.Quote() failed: %v", err)
|
||||
}
|
||||
|
@ -105,16 +105,18 @@ func TestAIKCreateAndLoad(t *testing.T) {
|
||||
t.Fatalf("aik.Close() failed: %v", err)
|
||||
}
|
||||
|
||||
loaded, err := tpm.LoadKey(enc)
|
||||
loaded, err := tpm.LoadAIK(enc)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadKey() failed: %v", err)
|
||||
}
|
||||
defer loaded.Close(tpm)
|
||||
|
||||
if !bytes.Equal(loaded.Public, aik.Public) {
|
||||
k1, k2 := aik.aik.(*key20), loaded.aik.(*key20)
|
||||
|
||||
if !bytes.Equal(k1.public, k2.public) {
|
||||
t.Error("Original & loaded AIK public blobs did not match.")
|
||||
t.Logf("Original = %v", aik.Public)
|
||||
t.Logf("Loaded = %v", loaded.Public)
|
||||
t.Logf("Original = %v", k1.public)
|
||||
t.Logf("Loaded = %v", k2.public)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/certificate-transparency-go/x509"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tspi/verification"
|
||||
)
|
||||
|
||||
@ -114,12 +113,8 @@ func TestMintAIK(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("MintAIK failed: %v", err)
|
||||
}
|
||||
|
||||
if (aik.TPMVersion != TPMVersion12) ||
|
||||
(aik.Purpose != AttestationKey) {
|
||||
t.Error("aik does not match expected format")
|
||||
}
|
||||
t.Logf("aik blob: %x\naik pubkey: %x\n", aik.KeyBlob, aik.Public)
|
||||
k := aik.aik.(*key12)
|
||||
t.Logf("aik blob: %x\naik pubkey: %x\n", k.blob, k.public)
|
||||
}
|
||||
|
||||
func TestTPMQuote(t *testing.T) {
|
||||
@ -140,7 +135,7 @@ func TestTPMQuote(t *testing.T) {
|
||||
t.Fatalf("MintAIK failed: %v", err)
|
||||
}
|
||||
|
||||
quote, err := aik.Quote(tpm, nonce, tpm2.AlgSHA1)
|
||||
quote, err := aik.Quote(tpm, nonce, HashSHA1)
|
||||
if err != nil {
|
||||
t.Fatalf("Quote failed: %v", err)
|
||||
}
|
||||
@ -187,7 +182,7 @@ func TestTPMActivateCredential(t *testing.T) {
|
||||
}
|
||||
ekcert := chooseEKCertRaw(t, EKs)
|
||||
|
||||
challenge.Credential, challenge.Secret, err = verification.GenerateChallenge(ekcert, aik.Public, nonce)
|
||||
challenge.Credential, challenge.Secret, err = verification.GenerateChallenge(ekcert, aik.aik.(*key12).public, nonce)
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateChallenge failed: %v", err)
|
||||
}
|
||||
|
156
attest/key_linux.go
Normal file
156
attest/key_linux.go
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy of
|
||||
// the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package attest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
"github.com/google/go-tspi/attestation"
|
||||
)
|
||||
|
||||
// key12 represents a key bound to a TPM 1.2 device via tcsd.
|
||||
type key12 struct {
|
||||
blob []byte
|
||||
public []byte
|
||||
}
|
||||
|
||||
// Marshal represents the key in a persistent format which may be
|
||||
// loaded at a later time using tpm.LoadKey().
|
||||
func (k *key12) Marshal() ([]byte, error) {
|
||||
out := serializedKey{
|
||||
Encoding: keyEncodingEncrypted,
|
||||
TPMVersion: TPMVersion12,
|
||||
Blob: k.blob,
|
||||
Public: k.public,
|
||||
}
|
||||
return out.Serialize()
|
||||
}
|
||||
|
||||
func (k *key12) Close(tpm *TPM) error {
|
||||
return nil // No state for tpm 1.2.
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using key.
|
||||
// This operation is synonymous with TPM2_ActivateCredential.
|
||||
func (k *key12) ActivateCredential(t *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
cred, err := attestation.AIKChallengeResponse(t.ctx, k.blob, in.Credential, in.Secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to activate aik: %v", err)
|
||||
}
|
||||
return cred, nil
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the key.
|
||||
func (k *key12) Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
||||
quote, rawSig, err := attestation.GetQuote(t.ctx, k.blob, nonce)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Quote() failed: %v", err)
|
||||
}
|
||||
|
||||
return &Quote{
|
||||
Version: TPMVersion12,
|
||||
Quote: quote,
|
||||
Signature: rawSig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Parameters returns information about the AIK.
|
||||
func (k *key12) Parameters() AIKParameters {
|
||||
return AIKParameters{
|
||||
Public: k.public,
|
||||
}
|
||||
}
|
||||
|
||||
// key20 represents a key bound to a TPM 2.0.
|
||||
type key20 struct {
|
||||
hnd tpmutil.Handle
|
||||
|
||||
blob []byte
|
||||
public []byte // used by both TPM1.2 and 2.0
|
||||
createData []byte
|
||||
createAttestation []byte
|
||||
createSignature []byte
|
||||
}
|
||||
|
||||
// Marshal represents the key in a persistent format which may be
|
||||
// loaded at a later time using tpm.LoadKey().
|
||||
func (k *key20) Marshal() ([]byte, error) {
|
||||
return (&serializedKey{
|
||||
Encoding: keyEncodingEncrypted,
|
||||
TPMVersion: TPMVersion20,
|
||||
|
||||
Blob: k.blob,
|
||||
Public: k.public,
|
||||
CreateData: k.createData,
|
||||
CreateAttestation: k.createAttestation,
|
||||
CreateSignature: k.createSignature,
|
||||
}).Serialize()
|
||||
}
|
||||
|
||||
// Close frees any resources associated with the key.
|
||||
func (k *key20) Close(tpm *TPM) error {
|
||||
return tpm2.FlushContext(tpm.rwc, k.hnd)
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using key.
|
||||
// This operation is synonymous with TPM2_ActivateCredential.
|
||||
func (k *key20) ActivateCredential(t *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
ekHnd, _, err := t.getPrimaryKeyHandle(commonEkEquivalentHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sessHandle, _, err := tpm2.StartAuthSession(
|
||||
t.rwc,
|
||||
tpm2.HandleNull, /*tpmKey*/
|
||||
tpm2.HandleNull, /*bindKey*/
|
||||
make([]byte, 16), /*nonceCaller*/
|
||||
nil, /*secret*/
|
||||
tpm2.SessionPolicy,
|
||||
tpm2.AlgNull,
|
||||
tpm2.AlgSHA256)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating session: %v", err)
|
||||
}
|
||||
defer tpm2.FlushContext(t.rwc, sessHandle)
|
||||
|
||||
if _, err := tpm2.PolicySecret(t.rwc, tpm2.HandleEndorsement, tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}, sessHandle, nil, nil, nil, 0); err != nil {
|
||||
return nil, fmt.Errorf("tpm2.PolicySecret() failed: %v", err)
|
||||
}
|
||||
|
||||
return tpm2.ActivateCredentialUsingAuth(t.rwc, []tpm2.AuthCommand{
|
||||
{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession},
|
||||
{Session: sessHandle, Attributes: tpm2.AttrContinueSession},
|
||||
}, k.hnd, ekHnd, in.Credential[2:], in.Secret[2:])
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the key.
|
||||
func (k *key20) Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
||||
return quote20(t.rwc, k.hnd, tpm2.Algorithm(alg), nonce)
|
||||
}
|
||||
|
||||
// Parameters returns information about the AIK.
|
||||
func (k *key20) Parameters() AIKParameters {
|
||||
return AIKParameters{
|
||||
Public: k.public,
|
||||
CreateData: k.createData,
|
||||
CreateAttestation: k.createAttestation,
|
||||
CreateSignature: k.createSignature,
|
||||
}
|
||||
}
|
167
attest/key_windows.go
Normal file
167
attest/key_windows.go
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy of
|
||||
// the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
|
||||
// +build windows
|
||||
|
||||
package attest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
tpm1 "github.com/google/go-tpm/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// key12 represents a Windows-managed key on a TPM1.2 TPM.
|
||||
type key12 struct {
|
||||
hnd uintptr
|
||||
pcpKeyName string
|
||||
public []byte
|
||||
}
|
||||
|
||||
// Marshal represents the key in a persistent format which may be
|
||||
// loaded at a later time using tpm.LoadKey().
|
||||
func (k *key12) Marshal() ([]byte, error) {
|
||||
out := serializedKey{
|
||||
Encoding: keyEncodingOSManaged,
|
||||
TPMVersion: TPMVersion12,
|
||||
Name: k.pcpKeyName,
|
||||
Public: k.public,
|
||||
}
|
||||
return out.Serialize()
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using key.
|
||||
// This operation is synonymous with TPM_ActivateIdentity for TPM1.2.
|
||||
func (k *key12) ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
secretKey, err := tpm.pcp.ActivateCredential(k.hnd, in.Credential)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decryptCredential(secretKey, in.Secret)
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the key.
|
||||
func (k *key12) Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
||||
tpmKeyHnd, err := t.pcp.TPMKeyHandle(k.hnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err)
|
||||
}
|
||||
|
||||
tpm, err := t.pcp.TPMCommandInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err)
|
||||
}
|
||||
|
||||
selectedPCRs := make([]int, 24)
|
||||
for pcr, _ := range selectedPCRs {
|
||||
selectedPCRs[pcr] = pcr
|
||||
}
|
||||
|
||||
sig, pcrc, err := tpm1.Quote(tpm, tpmKeyHnd, nonce, selectedPCRs[:], wellKnownAuth[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Quote() failed: %v", err)
|
||||
}
|
||||
// Construct and return TPM_QUOTE_INFO
|
||||
// Returning TPM_QUOTE_INFO allows us to verify the Quote at a higher resolution
|
||||
// and matches what go-tspi returns.
|
||||
quote, err := tpm1.NewQuoteInfo(nonce, selectedPCRs[:], pcrc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct Quote Info: %v", err)
|
||||
}
|
||||
return &Quote{
|
||||
Quote: quote,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close frees any resources associated with the key.
|
||||
func (k *key12) Close(tpm *TPM) error {
|
||||
return closeNCryptObject(k.hnd)
|
||||
}
|
||||
|
||||
// Parameters returns information about the AIK.
|
||||
func (k *key12) Parameters() AIKParameters {
|
||||
return AIKParameters{
|
||||
Public: k.public,
|
||||
}
|
||||
}
|
||||
|
||||
// key20 represents a key bound to a TPM 2.0.
|
||||
type key20 struct {
|
||||
hnd uintptr
|
||||
|
||||
pcpKeyName string
|
||||
public []byte
|
||||
createData []byte
|
||||
createAttestation []byte
|
||||
createSignature []byte
|
||||
}
|
||||
|
||||
// Marshal represents the key in a persistent format which may be
|
||||
// loaded at a later time using tpm.LoadKey().
|
||||
func (k *key20) Marshal() ([]byte, error) {
|
||||
out := serializedKey{
|
||||
Encoding: keyEncodingOSManaged,
|
||||
TPMVersion: TPMVersion20,
|
||||
Name: k.pcpKeyName,
|
||||
|
||||
Public: k.public,
|
||||
CreateData: k.createData,
|
||||
CreateAttestation: k.createAttestation,
|
||||
CreateSignature: k.createSignature,
|
||||
}
|
||||
return out.Serialize()
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using the key.
|
||||
// This operation is synonymous with TPM2_ActivateCredential.
|
||||
func (k *key20) ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
return tpm.pcp.ActivateCredential(k.hnd, append(in.Credential, in.Secret...))
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the key.
|
||||
func (k *key20) Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
||||
tpmKeyHnd, err := t.pcp.TPMKeyHandle(k.hnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err)
|
||||
}
|
||||
|
||||
tpm, err := t.pcp.TPMCommandInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err)
|
||||
}
|
||||
return quote20(tpm, tpmKeyHnd, tpm2.Algorithm(alg), nonce)
|
||||
}
|
||||
|
||||
// Close frees any resources associated with the key.
|
||||
func (k *key20) Close(tpm *TPM) error {
|
||||
return closeNCryptObject(k.hnd)
|
||||
}
|
||||
|
||||
// Delete permenantly removes the key from the system. This method
|
||||
// invalidates Key and any further method invocations are invalid.
|
||||
func (k *key20) Delete(tpm *TPM) error {
|
||||
return tpm.pcp.DeleteKey(k.hnd)
|
||||
}
|
||||
|
||||
// Parameters returns information about the AIK.
|
||||
func (k *key20) Parameters() AIKParameters {
|
||||
return AIKParameters{
|
||||
Public: k.public,
|
||||
CreateData: k.createData,
|
||||
CreateAttestation: k.createAttestation,
|
||||
CreateSignature: k.createSignature,
|
||||
}
|
||||
}
|
69
attest/storage.go
Normal file
69
attest/storage.go
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy of
|
||||
// the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
|
||||
package attest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// serializedKey represents a loadable, TPM-backed key.
|
||||
type serializedKey struct {
|
||||
// Encoding describes the strategy by which the key should be
|
||||
// loaded/unloaded.
|
||||
Encoding keyEncoding `json:"KeyEncoding"`
|
||||
// TPMVersion describes the version of the TPM which the key was generated
|
||||
// on. deserializeKey() returns an error if it attempts to deserialize a key
|
||||
// which is from a different TPM version to the currently opened TPM.
|
||||
TPMVersion TPMVersion
|
||||
|
||||
// Public represents the public key, in a TPM-specific format. This
|
||||
// field is populated on all platforms and TPM versions.
|
||||
Public []byte
|
||||
// The following fields are only valid for TPM 2.0 hardware, holding
|
||||
// information returned as the result to a TPM2_CertifyCreation command.
|
||||
// These are stored alongside the key for later use, as the certification
|
||||
// can only be obtained immediately after the key is generated.
|
||||
CreateData []byte
|
||||
CreateAttestation []byte
|
||||
CreateSignature []byte
|
||||
|
||||
// Name is only valid for KeyEncodingOSManaged, which is only used
|
||||
// on Windows.
|
||||
Name string
|
||||
// Blob represents the key material for KeyEncodingEncrypted keys. This
|
||||
// is only used on Linux.
|
||||
Blob []byte `json:"KeyBlob"`
|
||||
}
|
||||
|
||||
// Serialize represents the key in a persistent format which may be
|
||||
// loaded at a later time using deserializeKey().
|
||||
func (k *serializedKey) Serialize() ([]byte, error) {
|
||||
return json.Marshal(k)
|
||||
}
|
||||
|
||||
func deserializeKey(b []byte, version TPMVersion) (*serializedKey, error) {
|
||||
var k serializedKey
|
||||
var err error
|
||||
if err = json.Unmarshal(b, &k); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal() failed: %v", err)
|
||||
}
|
||||
|
||||
if k.TPMVersion != version {
|
||||
return nil, fmt.Errorf("key for different TPM version: %v", k.TPMVersion)
|
||||
}
|
||||
|
||||
return &k, nil
|
||||
}
|
@ -241,3 +241,11 @@ func allPCRs20(tpm io.ReadWriter) (map[uint32][]byte, crypto.Hash, error) {
|
||||
}
|
||||
return out256, crypto.SHA256, nil
|
||||
}
|
||||
|
||||
// LoadAIK loads a previously-created aik into the TPM for use.
|
||||
// A key loaded via this function needs to be closed with .Close().
|
||||
// Only blobs generated by calling AIK.Serialize() are valid parameters
|
||||
// to this function.
|
||||
func (t *TPM) LoadAIK(opaqueBlob []byte) (*AIK, error) {
|
||||
return t.loadAIK(opaqueBlob)
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -132,6 +131,11 @@ func openTPM(tpm probedTPM) (*TPM, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Version returns the version of the TPM.
|
||||
func (t *TPM) Version() TPMVersion {
|
||||
return t.version
|
||||
}
|
||||
|
||||
// Close shuts down the connection to the TPM.
|
||||
func (t *TPM) Close() error {
|
||||
switch t.version {
|
||||
@ -262,131 +266,19 @@ func (t *TPM) EKs() ([]PlatformEK, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Key represents a key bound to the TPM.
|
||||
type Key struct {
|
||||
hnd tpmutil.Handle
|
||||
KeyEncoding KeyEncoding
|
||||
TPMVersion TPMVersion
|
||||
Purpose KeyPurpose
|
||||
|
||||
KeyBlob []byte // exclusive to TPM1.2
|
||||
Public []byte // used by both TPM1.2 and 2.0
|
||||
CreateData []byte
|
||||
CreateAttestation []byte
|
||||
CreateSignature []byte
|
||||
}
|
||||
|
||||
// Marshal represents the key in a persistent format which may be
|
||||
// loaded at a later time using tpm.LoadKey().
|
||||
func (k *Key) Marshal() ([]byte, error) {
|
||||
return json.Marshal(k)
|
||||
}
|
||||
|
||||
// Close frees any resources associated with the key.
|
||||
func (k *Key) Close(tpm *TPM) error {
|
||||
switch tpm.version {
|
||||
case TPMVersion12:
|
||||
return nil
|
||||
case TPMVersion20:
|
||||
return tpm2.FlushContext(tpm.rwc, k.hnd)
|
||||
default:
|
||||
return fmt.Errorf("unsupported TPM version: %x", tpm.version)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete is not yet supported on linux systems.
|
||||
func (k *Key) Delete(tpm *TPM) error {
|
||||
return errors.New("key deletion is not yet supported on linux systems")
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using key.
|
||||
// This operation is synonymous with TPM2_ActivateCredential.
|
||||
func (k *Key) ActivateCredential(t *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
cred, err := attestation.AIKChallengeResponse(t.ctx, k.KeyBlob, in.Credential, in.Secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to refresh aik: %v", err)
|
||||
}
|
||||
return cred, nil
|
||||
|
||||
case TPMVersion20:
|
||||
ekHnd, _, err := t.getPrimaryKeyHandle(commonEkEquivalentHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sessHandle, _, err := tpm2.StartAuthSession(
|
||||
t.rwc,
|
||||
tpm2.HandleNull, /*tpmKey*/
|
||||
tpm2.HandleNull, /*bindKey*/
|
||||
make([]byte, 16), /*nonceCaller*/
|
||||
nil, /*secret*/
|
||||
tpm2.SessionPolicy,
|
||||
tpm2.AlgNull,
|
||||
tpm2.AlgSHA256)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating session: %v", err)
|
||||
}
|
||||
defer tpm2.FlushContext(t.rwc, sessHandle)
|
||||
|
||||
if _, err := tpm2.PolicySecret(t.rwc, tpm2.HandleEndorsement, tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}, sessHandle, nil, nil, nil, 0); err != nil {
|
||||
return nil, fmt.Errorf("tpm2.PolicySecret() failed: %v", err)
|
||||
}
|
||||
|
||||
return tpm2.ActivateCredentialUsingAuth(t.rwc, []tpm2.AuthCommand{
|
||||
{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession},
|
||||
{Session: sessHandle, Attributes: tpm2.AttrContinueSession},
|
||||
}, k.hnd, ekHnd, in.Credential[2:], in.Secret[2:])
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported TPM version: %x", t.version)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Key) quote12(ctx *tspi.Context, nonce []byte) (*Quote, error) {
|
||||
quote, rawSig, err := attestation.GetQuote(ctx, k.KeyBlob, nonce)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetQuote() failed: %v", err)
|
||||
}
|
||||
|
||||
return &Quote{
|
||||
Version: TPMVersion12,
|
||||
Quote: quote,
|
||||
Signature: rawSig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the key.
|
||||
func (k *Key) Quote(t *TPM, nonce []byte, alg tpm2.Algorithm) (*Quote, error) {
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
return k.quote12(t.ctx, nonce)
|
||||
|
||||
case TPMVersion20:
|
||||
return quote20(t.rwc, k.hnd, alg, nonce)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported TPM version: %x", t.version)
|
||||
}
|
||||
}
|
||||
|
||||
// MintAIK creates an attestation key.
|
||||
func (t *TPM) MintAIK(opts *MintOptions) (*Key, error) {
|
||||
func (t *TPM) MintAIK(opts *MintOptions) (*AIK, error) {
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
pub, blob, err := attestation.CreateAIK(t.ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreateAIK failed: %v", err)
|
||||
}
|
||||
|
||||
return &Key{
|
||||
KeyEncoding: KeyEncodingEncrypted,
|
||||
TPMVersion: t.version,
|
||||
Purpose: AttestationKey,
|
||||
KeyBlob: blob,
|
||||
Public: pub,
|
||||
return &AIK{
|
||||
aik: &key12{
|
||||
blob: blob,
|
||||
public: pub,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case TPMVersion20:
|
||||
@ -398,11 +290,11 @@ func (t *TPM) MintAIK(opts *MintOptions) (*Key, error) {
|
||||
|
||||
_, blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", aikTemplate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CreateKeyEx failed: %v", err)
|
||||
return nil, fmt.Errorf("CreateKeyEx() failed: %v", err)
|
||||
}
|
||||
keyHandle, _, err := tpm2.Load(t.rwc, srk, "", pub, blob)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Load failed: %v", err)
|
||||
return nil, fmt.Errorf("Load() failed: %v", err)
|
||||
}
|
||||
// If any errors occur, free the AIK's handle.
|
||||
defer func() {
|
||||
@ -422,16 +314,15 @@ func (t *TPM) MintAIK(opts *MintOptions) (*Key, error) {
|
||||
return nil, fmt.Errorf("failed to pack TPMT_SIGNATURE: %v", err)
|
||||
}
|
||||
|
||||
return &Key{
|
||||
hnd: keyHandle,
|
||||
KeyEncoding: KeyEncodingEncrypted,
|
||||
TPMVersion: t.version,
|
||||
Purpose: AttestationKey,
|
||||
KeyBlob: blob,
|
||||
Public: pub,
|
||||
CreateData: creationData,
|
||||
CreateAttestation: attestation,
|
||||
CreateSignature: signature,
|
||||
return &AIK{
|
||||
aik: &key20{
|
||||
hnd: keyHandle,
|
||||
blob: blob,
|
||||
public: pub,
|
||||
createData: creationData,
|
||||
createAttestation: attestation,
|
||||
createSignature: signature,
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
@ -439,45 +330,46 @@ func (t *TPM) MintAIK(opts *MintOptions) (*Key, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// LoadKey loads a previously-created key into the TPM for use.
|
||||
// A key loaded via this function needs to be closed with .Close().
|
||||
func (t *TPM) LoadKey(opaqueBlob []byte) (*Key, error) {
|
||||
// TODO(b/124266168): Load under the key handle loaded by t.getPrimaryKeyHandle()
|
||||
|
||||
var k Key
|
||||
var err error
|
||||
if err = json.Unmarshal(opaqueBlob, &k); err != nil {
|
||||
return nil, fmt.Errorf("Unmarshal failed: %v", err)
|
||||
func (t *TPM) loadAIK(opaqueBlob []byte) (*AIK, error) {
|
||||
sKey, err := deserializeKey(opaqueBlob, t.version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("deserializeKey() failed: %v", err)
|
||||
}
|
||||
if sKey.Encoding != keyEncodingEncrypted {
|
||||
return nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding)
|
||||
}
|
||||
|
||||
if k.TPMVersion != t.version {
|
||||
return nil, errors.New("key TPM version does not match opened TPM")
|
||||
}
|
||||
if k.Purpose != AttestationKey {
|
||||
return nil, fmt.Errorf("unsupported key kind: %x", k.Purpose)
|
||||
}
|
||||
|
||||
switch t.version {
|
||||
switch sKey.TPMVersion {
|
||||
case TPMVersion12:
|
||||
if k.KeyEncoding != KeyEncodingEncrypted {
|
||||
return nil, fmt.Errorf("unsupported key encoding: %x", k.KeyEncoding)
|
||||
}
|
||||
|
||||
return &AIK{
|
||||
aik: &key12{
|
||||
blob: sKey.Blob,
|
||||
public: sKey.Public,
|
||||
},
|
||||
}, nil
|
||||
case TPMVersion20:
|
||||
if k.KeyEncoding != KeyEncodingEncrypted {
|
||||
return nil, fmt.Errorf("unsupported key encoding: %x", k.KeyEncoding)
|
||||
}
|
||||
|
||||
srk, _, err := t.getPrimaryKeyHandle(commonSrkEquivalentHandle)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
||||
}
|
||||
if k.hnd, _, err = tpm2.Load(t.rwc, srk, "", k.Public, k.KeyBlob); err != nil {
|
||||
return nil, fmt.Errorf("Load failed: %v", err)
|
||||
var hnd tpmutil.Handle
|
||||
if hnd, _, err = tpm2.Load(t.rwc, srk, "", sKey.Public, sKey.Blob); err != nil {
|
||||
return nil, fmt.Errorf("Load() failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &k, nil
|
||||
return &AIK{
|
||||
aik: &key20{
|
||||
hnd: hnd,
|
||||
blob: sKey.Blob,
|
||||
public: sKey.Public,
|
||||
createData: sKey.CreateData,
|
||||
createAttestation: sKey.CreateAttestation,
|
||||
createSignature: sKey.CreateSignature,
|
||||
},
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot load AIK with TPM version: %v", sKey.TPMVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// allPCRs12 returns a map of all the PCR values on the TPM
|
||||
|
@ -26,7 +26,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -36,7 +35,6 @@ import (
|
||||
|
||||
tpm1 "github.com/google/go-tpm/tpm"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
tpmtbs "github.com/google/go-tpm/tpmutil/tbs"
|
||||
)
|
||||
|
||||
@ -104,6 +102,11 @@ func openTPM(tpm probedTPM) (*TPM, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Version returns the version of the TPM.
|
||||
func (t *TPM) Version() TPMVersion {
|
||||
return t.version
|
||||
}
|
||||
|
||||
// Close shuts down the connection to the TPM.
|
||||
func (t *TPM) Close() error {
|
||||
return t.pcp.Close()
|
||||
@ -248,27 +251,6 @@ func decodeWindowsBcryptRSABlob(b []byte) (*rsa.PublicKey, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Key represents a key bound to the TPM.
|
||||
type Key struct {
|
||||
hnd uintptr
|
||||
KeyEncoding KeyEncoding
|
||||
TPMVersion TPMVersion
|
||||
Purpose KeyPurpose
|
||||
|
||||
PCPKeyName string
|
||||
KeyBlob []byte
|
||||
Public []byte
|
||||
CreateData []byte
|
||||
CreateAttestation []byte
|
||||
CreateSignature []byte
|
||||
}
|
||||
|
||||
// Marshal represents the key in a persistent format which may be
|
||||
// loaded at a later time using tpm.LoadKey().
|
||||
func (k *Key) Marshal() ([]byte, error) {
|
||||
return json.Marshal(k)
|
||||
}
|
||||
|
||||
func decryptCredential(secretKey, blob []byte) ([]byte, error) {
|
||||
var scheme uint32
|
||||
symbuf := bytes.NewReader(blob)
|
||||
@ -308,92 +290,9 @@ func decryptCredential(secretKey, blob []byte) ([]byte, error) {
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// ActivateCredential decrypts the specified credential using key.
|
||||
// This operation is synonymous with TPM2_ActivateCredential for TPM2.0
|
||||
// and TPM_ActivateIdentity with the trousers daemon for TPM1.2.
|
||||
func (k *Key) ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error) {
|
||||
if k.TPMVersion != tpm.version {
|
||||
return nil, fmt.Errorf("tpm and key version mismatch")
|
||||
}
|
||||
|
||||
switch tpm.version {
|
||||
case TPMVersion12:
|
||||
secretKey, err := tpm.pcp.ActivateCredential(k.hnd, in.Credential)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decryptCredential(secretKey, in.Secret)
|
||||
case TPMVersion20:
|
||||
return tpm.pcp.ActivateCredential(k.hnd, append(in.Credential, in.Secret...))
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid TPM version: %v", tpm.version)
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Key) quote12(tpm io.ReadWriter, hnd tpmutil.Handle, nonce []byte) (*Quote, error) {
|
||||
selectedPCRs := make([]int, 24)
|
||||
for pcr, _ := range selectedPCRs {
|
||||
selectedPCRs[pcr] = pcr
|
||||
}
|
||||
|
||||
sig, pcrc, err := tpm1.Quote(tpm, hnd, nonce, selectedPCRs[:], wellKnownAuth[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Quote() failed: %v", err)
|
||||
}
|
||||
// Construct and return TPM_QUOTE_INFO
|
||||
// Returning TPM_QUOTE_INFO allows us to verify the Quote at a higher resolution
|
||||
// and matches what go-tspi returns.
|
||||
quote, err := tpm1.NewQuoteInfo(nonce, selectedPCRs[:], pcrc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct Quote Info: %v", err)
|
||||
}
|
||||
return &Quote{
|
||||
Quote: quote,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Quote returns a quote over the platform state, signed by the key.
|
||||
func (k *Key) Quote(t *TPM, nonce []byte, alg tpm2.Algorithm) (*Quote, error) {
|
||||
tpmKeyHnd, err := t.pcp.TPMKeyHandle(k.hnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err)
|
||||
}
|
||||
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
tpm, err := t.pcp.TPMCommandInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err)
|
||||
}
|
||||
return k.quote12(tpm, tpmKeyHnd, nonce)
|
||||
|
||||
case TPMVersion20:
|
||||
tpm, err := t.pcp.TPMCommandInterface()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err)
|
||||
}
|
||||
return quote20(tpm, tpmKeyHnd, alg, nonce)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported TPM version: %x", t.version)
|
||||
}
|
||||
}
|
||||
|
||||
// Close frees any resources associated with the key.
|
||||
func (k *Key) Close(tpm *TPM) error {
|
||||
return closeNCryptObject(k.hnd)
|
||||
}
|
||||
|
||||
// Delete permenantly removes the key from the system. This method
|
||||
// invalidates Key and any further method invocations are invalid.
|
||||
func (k *Key) Delete(tpm *TPM) error {
|
||||
return tpm.pcp.DeleteKey(k.hnd)
|
||||
}
|
||||
|
||||
// MintAIK creates a persistent attestation key. The returned key must be
|
||||
// closed with a call to key.Close() when the caller has finished using it.
|
||||
func (t *TPM) MintAIK(opts *MintOptions) (*Key, error) {
|
||||
func (t *TPM) MintAIK(opts *MintOptions) (*AIK, error) {
|
||||
nameHex := make([]byte, 5)
|
||||
if n, err := rand.Read(nameHex); err != nil || n != len(nameHex) {
|
||||
return nil, fmt.Errorf("rand.Read() failed with %d/%d bytes read and error: %v", n, len(nameHex), err)
|
||||
@ -410,42 +309,71 @@ func (t *TPM) MintAIK(opts *MintOptions) (*Key, error) {
|
||||
return nil, fmt.Errorf("pcp failed to read attestation key properties: %v", err)
|
||||
}
|
||||
|
||||
return &Key{
|
||||
hnd: kh,
|
||||
KeyEncoding: KeyEncodingOSManaged,
|
||||
TPMVersion: t.version,
|
||||
Purpose: AttestationKey,
|
||||
PCPKeyName: name,
|
||||
Public: props.RawPublic,
|
||||
CreateData: props.RawCreationData,
|
||||
CreateAttestation: props.RawAttest,
|
||||
CreateSignature: props.RawSignature,
|
||||
}, nil
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
return &AIK{
|
||||
aik: &key12{
|
||||
hnd: kh,
|
||||
pcpKeyName: name,
|
||||
public: props.RawPublic,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case TPMVersion20:
|
||||
return &AIK{
|
||||
aik: &key20{
|
||||
hnd: kh,
|
||||
pcpKeyName: name,
|
||||
public: props.RawPublic,
|
||||
createData: props.RawCreationData,
|
||||
createAttestation: props.RawAttest,
|
||||
createSignature: props.RawSignature,
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot handle TPM version: %v", t.version)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadKey loads a previously-created key into the TPM for use.
|
||||
// A key loaded via this function needs to be closed with .Close().
|
||||
func (t *TPM) LoadKey(opaqueBlob []byte) (*Key, error) {
|
||||
var k Key
|
||||
var err error
|
||||
if err = json.Unmarshal(opaqueBlob, &k); err != nil {
|
||||
return nil, fmt.Errorf("Unmarshal failed: %v", err)
|
||||
func (t *TPM) loadAIK(opaqueBlob []byte) (*AIK, error) {
|
||||
sKey, err := deserializeKey(opaqueBlob, t.version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("deserializeKey() failed: %v", err)
|
||||
}
|
||||
if sKey.Encoding != keyEncodingOSManaged {
|
||||
return nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding)
|
||||
}
|
||||
|
||||
if k.TPMVersion != t.version {
|
||||
return nil, errors.New("key TPM version does not match opened TPM")
|
||||
}
|
||||
if k.KeyEncoding != KeyEncodingOSManaged {
|
||||
return nil, fmt.Errorf("unsupported key encoding: %x", k.KeyEncoding)
|
||||
}
|
||||
if k.Purpose != AttestationKey {
|
||||
return nil, fmt.Errorf("unsupported key kind: %x", k.Purpose)
|
||||
}
|
||||
|
||||
if k.hnd, err = t.pcp.LoadKeyByName(k.PCPKeyName); err != nil {
|
||||
hnd, err := t.pcp.LoadKeyByName(sKey.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pcp failed to load key: %v", err)
|
||||
}
|
||||
return &k, nil
|
||||
|
||||
switch t.version {
|
||||
case TPMVersion12:
|
||||
return &AIK{
|
||||
aik: &key12{
|
||||
hnd: hnd,
|
||||
pcpKeyName: sKey.Name,
|
||||
public: sKey.Public,
|
||||
},
|
||||
}, nil
|
||||
case TPMVersion20:
|
||||
return &AIK{
|
||||
aik: &key20{
|
||||
hnd: hnd,
|
||||
pcpKeyName: sKey.Name,
|
||||
public: sKey.Public,
|
||||
createData: sKey.CreateData,
|
||||
createAttestation: sKey.CreateAttestation,
|
||||
createSignature: sKey.CreateSignature,
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot handle TPM version: %v", t.version)
|
||||
}
|
||||
}
|
||||
|
||||
func allPCRs12(tpm io.ReadWriter) (map[uint32][]byte, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user