mirror of
https://github.com/google/go-attestation.git
synced 2025-01-31 07:55:22 +00:00
Implement credential activation API (#56)
This commit is contained in:
parent
2464131d7c
commit
8f4f17e679
280
attest/activation.go
Normal file
280
attest/activation.go
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
package attest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
tpm1 "github.com/google/go-tpm/tpm"
|
||||||
|
"github.com/google/go-tpm/tpm2"
|
||||||
|
|
||||||
|
// TODO(jsonp): Move activation generation code to internal package.
|
||||||
|
"github.com/google/go-tpm/tpm2/credactivation"
|
||||||
|
"github.com/google/go-tspi/verification"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// minRSABits is the minimum accepted bit size of an RSA key.
|
||||||
|
minRSABits = 2048
|
||||||
|
// activationSecretLen is the size in bytes of the generated secret
|
||||||
|
// which is generated for credential activation.
|
||||||
|
activationSecretLen = 32
|
||||||
|
// symBlockSize is the block size used for symmetric ciphers used
|
||||||
|
// when generating the credential activation challenge.
|
||||||
|
symBlockSize = 16
|
||||||
|
// tpm20GeneratedMagic is a magic tag when can only be present on a
|
||||||
|
// TPM structure if the structure was generated wholly by the TPM.
|
||||||
|
tpm20GeneratedMagic = 0xff544347
|
||||||
|
)
|
||||||
|
|
||||||
|
func cryptoHash(h tpm2.Algorithm) (crypto.Hash, error) {
|
||||||
|
switch h {
|
||||||
|
case tpm2.AlgSHA1:
|
||||||
|
return crypto.SHA1, nil
|
||||||
|
case tpm2.AlgSHA256:
|
||||||
|
return crypto.SHA256, nil
|
||||||
|
case tpm2.AlgSHA384:
|
||||||
|
return crypto.SHA384, nil
|
||||||
|
case tpm2.AlgSHA512:
|
||||||
|
return crypto.SHA512, nil
|
||||||
|
default:
|
||||||
|
return crypto.Hash(0), fmt.Errorf("unsupported signature digest: %v", h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActivationParameters encapsulates the inputs for activating an AIK.
|
||||||
|
type ActivationParameters struct {
|
||||||
|
// TPMVersion holds the version of the TPM, either 1.2 or 2.0.
|
||||||
|
TPMVersion TPMVersion
|
||||||
|
|
||||||
|
// EK, the endorsement key, describes an asymmetric key who's
|
||||||
|
// private key is permenantly bound to the TPM.
|
||||||
|
//
|
||||||
|
// Activation will verify that the provided EK is held on the same
|
||||||
|
// TPM as the AIK. However, it is the callers responsibility to
|
||||||
|
// ensure the EK they provide corresponds to the the device which
|
||||||
|
// they are trying to associate the AIK with.
|
||||||
|
EK crypto.PublicKey
|
||||||
|
|
||||||
|
// AIK, the Attestation Identity Key, describes the properties of
|
||||||
|
// an asymmetric key (managed by the TPM) which signs attestation
|
||||||
|
// structures.
|
||||||
|
// The values from this structure can be obtained by calling
|
||||||
|
// Parameters() on an attest.AIK.
|
||||||
|
AIK AttestationParameters
|
||||||
|
|
||||||
|
// Rand is a source of randomness to generate a seed and secret for the
|
||||||
|
// challenge.
|
||||||
|
//
|
||||||
|
// If nil, this defaults to crypto.Rand.
|
||||||
|
Rand io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkAIKParameters examines properties of an AIK and a creation
|
||||||
|
// attestation, to determine if it is suitable for use as an attestation key.
|
||||||
|
func (p *ActivationParameters) checkAIKParameters() error {
|
||||||
|
switch p.TPMVersion {
|
||||||
|
case TPMVersion12:
|
||||||
|
return p.checkTPM12AIKParameters()
|
||||||
|
|
||||||
|
case TPMVersion20:
|
||||||
|
return p.checkTPM20AIKParameters()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("TPM version %d not supported", p.TPMVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ActivationParameters) checkTPM12AIKParameters() error {
|
||||||
|
// TODO(jsonp): Implement helper to parse public blobs, ie:
|
||||||
|
// func ParsePublic(publicBlob []byte) (crypto.Public, error)
|
||||||
|
|
||||||
|
pub, err := tpm1.UnmarshalPubRSAPublicKey(p.AIK.Public)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unmarshalling public key: %v", err)
|
||||||
|
}
|
||||||
|
if bits := pub.Size() * 8; bits < minRSABits {
|
||||||
|
return fmt.Errorf("attestation key too small: must be at least %d bits but was %d bits", minRSABits, bits)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ActivationParameters) checkTPM20AIKParameters() error {
|
||||||
|
if len(p.AIK.CreateSignature) < 8 {
|
||||||
|
return fmt.Errorf("signature is too short to be valid: only %d bytes", len(p.AIK.CreateSignature))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub, err := tpm2.DecodePublic(p.AIK.Public)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("DecodePublic() failed: %v", err)
|
||||||
|
}
|
||||||
|
_, err = tpm2.DecodeCreationData(p.AIK.CreateData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("DecodeCreationData() failed: %v", err)
|
||||||
|
}
|
||||||
|
att, err := tpm2.DecodeAttestationData(p.AIK.CreateAttestation)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("DecodeAttestationData() failed: %v", err)
|
||||||
|
}
|
||||||
|
if att.Type != tpm2.TagAttestCreation {
|
||||||
|
return fmt.Errorf("attestation does not apply to creation data, got tag %x", att.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support ECC AIKs.
|
||||||
|
switch pub.Type {
|
||||||
|
case tpm2.AlgRSA:
|
||||||
|
if pub.RSAParameters.KeyBits < minRSABits {
|
||||||
|
return fmt.Errorf("attestation key too small: must be at least %d bits but was %d bits", minRSABits, pub.RSAParameters.KeyBits)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("public key of alg 0x%x not supported", pub.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute & verify that the creation data matches the digest in the
|
||||||
|
// attestation structure.
|
||||||
|
nameHashConstructor, err := pub.NameAlg.HashConstructor()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("HashConstructor() failed: %v", err)
|
||||||
|
}
|
||||||
|
h := nameHashConstructor()
|
||||||
|
h.Write(p.AIK.CreateData)
|
||||||
|
if !bytes.Equal(att.AttestedCreationInfo.OpaqueDigest, h.Sum(nil)) {
|
||||||
|
return errors.New("attestation refers to different public key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the AIK has sane key parameters (Attestation can be faked if an AIK
|
||||||
|
// can be used for arbitrary signatures).
|
||||||
|
// We verify the following:
|
||||||
|
// - Key is TPM backed.
|
||||||
|
// - Key is TPM generated.
|
||||||
|
// - Key is a restricted key (means it cannot do arbitrary signing/decrypt ops).
|
||||||
|
// - Key cannot be duplicated.
|
||||||
|
// - Key was generated by a call to TPM_Create*.
|
||||||
|
if att.Magic != tpm20GeneratedMagic {
|
||||||
|
return errors.New("creation attestation was not produced by a TPM")
|
||||||
|
}
|
||||||
|
if (pub.Attributes & tpm2.FlagFixedTPM) == 0 {
|
||||||
|
return errors.New("AIK is exportable")
|
||||||
|
}
|
||||||
|
if ((pub.Attributes & tpm2.FlagRestricted) == 0) || ((pub.Attributes & tpm2.FlagFixedParent) == 0) || ((pub.Attributes & tpm2.FlagSensitiveDataOrigin) == 0) {
|
||||||
|
return errors.New("provided key is not limited to attestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the attested creation name matches what is computed from
|
||||||
|
// the public key.
|
||||||
|
match, err := att.AttestedCreationInfo.Name.MatchesPublic(pub)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
return errors.New("creation attestation refers to a different key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the signature over the attestation data verifies correctly.
|
||||||
|
pk := rsa.PublicKey{E: int(pub.RSAParameters.Exponent), N: pub.RSAParameters.Modulus}
|
||||||
|
signHashConstructor, err := pub.RSAParameters.Sign.Hash.HashConstructor()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hsh := signHashConstructor()
|
||||||
|
hsh.Write(p.AIK.CreateAttestation)
|
||||||
|
verifyHash, err := cryptoHash(pub.RSAParameters.Sign.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.AIK.CreateSignature) < 8 {
|
||||||
|
return fmt.Errorf("signature invalid: length of %d is shorter than 8", len(p.AIK.CreateSignature))
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := tpm2.DecodeSignature(bytes.NewBuffer(p.AIK.CreateSignature))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("DecodeSignature() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rsa.VerifyPKCS1v15(&pk, verifyHash, hsh.Sum(nil), sig.RSA.Signature); err != nil {
|
||||||
|
return fmt.Errorf("could not verify attestation: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate returns a credential activation challenge, which can be provided
|
||||||
|
// to the TPM to verify the AIK parameters given are authentic & the AIK
|
||||||
|
// is present on the same TPM as the EK.
|
||||||
|
func (p *ActivationParameters) Generate() (secret []byte, ec *EncryptedCredential, err error) {
|
||||||
|
if err := p.checkAIKParameters(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.EK == nil {
|
||||||
|
return nil, nil, errors.New("no EK provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
rnd, secret := p.Rand, make([]byte, activationSecretLen)
|
||||||
|
if rnd == nil {
|
||||||
|
rnd = rand.Reader
|
||||||
|
}
|
||||||
|
if _, err = io.ReadFull(rnd, secret); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("error generating activation secret: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch p.TPMVersion {
|
||||||
|
case TPMVersion12:
|
||||||
|
ec, err = p.generateChallengeTPM12(secret)
|
||||||
|
case TPMVersion20:
|
||||||
|
ec, err = p.generateChallengeTPM20(secret)
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("unrecognised TPM version: %v", p.TPMVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return secret, ec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ActivationParameters) generateChallengeTPM20(secret []byte) (*EncryptedCredential, error) {
|
||||||
|
att, err := tpm2.DecodeAttestationData(p.AIK.CreateAttestation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("DecodeAttestationData() failed: %v", err)
|
||||||
|
}
|
||||||
|
cred, encSecret, err := credactivation.Generate(att.AttestedCreationInfo.Name.Digest, p.EK, symBlockSize, secret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("credactivation.Generate() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EncryptedCredential{
|
||||||
|
Credential: cred,
|
||||||
|
Secret: encSecret,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ActivationParameters) generateChallengeTPM12(secret []byte) (*EncryptedCredential, error) {
|
||||||
|
pk, ok := p.EK.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("got EK of type %T, want an RSA key", p.EK)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
cred, encSecret []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if p.AIK.UseTCSDActivationFormat {
|
||||||
|
cred, encSecret, err = verification.GenerateChallengeEx(pk, p.AIK.Public, secret)
|
||||||
|
} else {
|
||||||
|
cred, encSecret, err = generateChallenge12(pk, p.AIK.Public, secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("challenge generation failed: %v", err)
|
||||||
|
}
|
||||||
|
return &EncryptedCredential{
|
||||||
|
Credential: cred,
|
||||||
|
Secret: encSecret,
|
||||||
|
}, nil
|
||||||
|
}
|
69
attest/activation_test.go
Normal file
69
attest/activation_test.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package attest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func decodeBase10(base10 string, t *testing.T) *big.Int {
|
||||||
|
i, ok := new(big.Int).SetString(base10, 10)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("failed decode of base10: %q", base10)
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeBase64(in string, t *testing.T) []byte {
|
||||||
|
out, err := base64.StdEncoding.DecodeString(in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ekCertSigner(t *testing.T) *rsa.PrivateKey {
|
||||||
|
return &rsa.PrivateKey{
|
||||||
|
PublicKey: rsa.PublicKey{
|
||||||
|
N: decodeBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557", t),
|
||||||
|
E: 3,
|
||||||
|
},
|
||||||
|
D: decodeBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731", t),
|
||||||
|
Primes: []*big.Int{
|
||||||
|
decodeBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433", t),
|
||||||
|
decodeBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029", t),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestActivationTPM20(t *testing.T) {
|
||||||
|
priv := ekCertSigner(t)
|
||||||
|
rand := rand.New(rand.NewSource(123456))
|
||||||
|
|
||||||
|
// These parameters represent an AIK generated on a real-world, infineon TPM.
|
||||||
|
params := ActivationParameters{
|
||||||
|
TPMVersion: TPMVersion20,
|
||||||
|
AIK: AttestationParameters{
|
||||||
|
Public: decodeBase64("AAEACwAFBHIAIJ3/y/NsODrmmfuYaNxty4nXFTiEvigDkiwSQVi/rSKuABAAFAAECAAAAAAAAQC/08gj/04z4xGMIVTmr02lzhI5epufXgU831xEpf2qpXfvtNGUfqTcgWF2EUux2HDPqgcj59dtXRobQdlr4uCGNzfZIGAej4JusLa4MjpG6W2DtJPot6F1Mry63talzJ36U47niy9Iesd34CO2p9Xk3+86ZmBnQ6PQ2roUNK3l7bKz6cFLM9drOLwCqU0AUl6pHvzYPPz+xXsPl3iaA2cM97oneUiJNmJM7wtR9OcaKyIA4wVlX5TndB9NwWq5Iuj8q2Sp40Dg0noXXGSPliAtVD8flkXtAcuI9UHkQbzu9cGPRdSJPMn743GONg3bYalFtcgh2VpACXkPbXB32J7B", t),
|
||||||
|
CreateData: decodeBase64("AAAAAAAg47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFUBAAsAIgALWI9hwDRB3zYSkannqM5z0J1coQNA1Jz/oCRxJQwTaNwAIgALmyFYBhHeIU3FUKIAPgXFD3NXyasP3siQviDEyH7avu4AAA==", t),
|
||||||
|
CreateAttestation: decodeBase64("/1RDR4AaACIAC41+jhmEOue1MZhJjIk79ENar6i15rBvamXLpQnGTBCOAAAAAAAAD3GRNfU4syzJ1jQGATDCDteFC5C4ACIAC3ToMYGy9GXxcf8A0HvOuLOHbU7HPEppM47C7CMcU8TtACBDmJFUFO1f5+BYevaYdd3VtfMCsxIuHhoTZJczzLP2BA==", t),
|
||||||
|
CreateSignature: decodeBase64("ABQABAEALVzJSnKRJU39gHjETaI89/sM1L6HwBPGNekw6NojSW8bwD5/W1cLRDakCsYKUQu68mmbjs8xaIVBRvVM2YWP10tbTWNB0iJc9b8rERhkk3QIIFm/XsiVZsb0mysTxfeh8zygaAKQ/50sYyzp+raD0Ho0mYIRKJOEdQ6chsBflM3eB8mCXGTugUfrET80q3iu0gncaKWbfxQaQUb9ZTPSJrTN64HQ9tlOfnGT+8++WA3hV0NqKMnoAqiI9GZnI5MPXs6XxEncu/GJLJpAYZakBiS74Jvlr34Pur32B4xjm1M25AUGHEIgb6r49S0sV+hzaKu45858lQRMXj01GcyBhw==", t),
|
||||||
|
},
|
||||||
|
EK: &rsa.PublicKey{
|
||||||
|
E: priv.E,
|
||||||
|
N: priv.N,
|
||||||
|
},
|
||||||
|
Rand: rand,
|
||||||
|
}
|
||||||
|
|
||||||
|
secret, _, err := params.Generate()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Generate() returned err: %v", err)
|
||||||
|
}
|
||||||
|
if got, want := secret, decodeBase64("0vhS7HtORX9uf/iyQ8Sf9WkpJuoJ1olCfTjSZuyNNxY=", t); !bytes.Equal(got, want) {
|
||||||
|
t.Fatalf("secret = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
@ -99,7 +99,7 @@ type aik interface {
|
|||||||
Marshal() ([]byte, error)
|
Marshal() ([]byte, error)
|
||||||
ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error)
|
ActivateCredential(tpm *TPM, in EncryptedCredential) ([]byte, error)
|
||||||
Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error)
|
Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error)
|
||||||
Parameters() AIKParameters
|
AttestationParameters() AttestationParameters
|
||||||
Public() crypto.PublicKey
|
Public() crypto.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +134,8 @@ func (k *AIK) Quote(tpm *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
|||||||
|
|
||||||
// Parameters returns information about the AIK, typically used to generate
|
// Parameters returns information about the AIK, typically used to generate
|
||||||
// a credential activation challenge.
|
// a credential activation challenge.
|
||||||
func (k *AIK) Parameters() AIKParameters {
|
func (k *AIK) AttestationParameters() AttestationParameters {
|
||||||
return k.aik.Parameters()
|
return k.aik.AttestationParameters()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public returns the public part of the AIK.
|
// Public returns the public part of the AIK.
|
||||||
@ -177,9 +177,9 @@ type PlatformEK struct {
|
|||||||
Public crypto.PublicKey
|
Public crypto.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// AIKParameters describes information about an AIK. This information
|
// AttestationParameters describes information about a key which is necessary
|
||||||
// is typically used to generate an activation challenge.
|
// for verifying its properties remotely.
|
||||||
type AIKParameters struct {
|
type AttestationParameters struct {
|
||||||
// Public represents the public key in a TPM-version specific encoding.
|
// 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 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
|
// For TPM 1.2 devices, this is a TPM_PUBKEY structure, as defined in
|
||||||
@ -187,6 +187,11 @@ type AIKParameters struct {
|
|||||||
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011.pdf
|
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011.pdf
|
||||||
Public []byte
|
Public []byte
|
||||||
|
|
||||||
|
// UseTCSDActivationFormat is set when tcsd (trousers daemon) is operating
|
||||||
|
// as an intermediary between this library and the TPM. A value of true
|
||||||
|
// indicates that activation challenges should use the TCSD-specific format.
|
||||||
|
UseTCSDActivationFormat bool
|
||||||
|
|
||||||
// Subsequent fields are only populated for AIKs generated on a TPM
|
// Subsequent fields are only populated for AIKs generated on a TPM
|
||||||
// implementing version 2.0 of the specification. The specific structures
|
// implementing version 2.0 of the specification. The specific structures
|
||||||
// referenced for each field are defined in the TPM Revision 2, Part 2 -
|
// referenced for each field are defined in the TPM Revision 2, Part 2 -
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-tpm-tools/simulator"
|
"github.com/google/go-tpm-tools/simulator"
|
||||||
"github.com/google/go-tpm/tpm2"
|
"github.com/google/go-tpm/tpm2"
|
||||||
"github.com/google/go-tpm/tpm2/credactivation"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupSimulatedTPM(t *testing.T) (*simulator.Simulator, *TPM) {
|
func setupSimulatedTPM(t *testing.T) (*simulator.Simulator, *TPM) {
|
||||||
@ -133,21 +132,17 @@ func TestSimTPM20ActivateCredential(t *testing.T) {
|
|||||||
}
|
}
|
||||||
ek := chooseEKPub(t, EKs)
|
ek := chooseEKPub(t, EKs)
|
||||||
|
|
||||||
att, err := tpm2.DecodeAttestationData(aik.aik.(*key20).createAttestation)
|
ap := ActivationParameters{
|
||||||
if err != nil {
|
TPMVersion: TPMVersion20,
|
||||||
t.Fatalf("tpm2.DecodeAttestationData() failed: %v", err)
|
AIK: aik.AttestationParameters(),
|
||||||
|
EK: ek,
|
||||||
}
|
}
|
||||||
secret := []byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}
|
secret, challenge, err := ap.Generate()
|
||||||
|
|
||||||
id, encSecret, err := credactivation.Generate(att.AttestedCreationInfo.Name.Digest, ek, 16, secret)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("credactivation.Generate() failed: %v", err)
|
t.Fatalf("Generate() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
decryptedSecret, err := aik.ActivateCredential(tpm, EncryptedCredential{
|
decryptedSecret, err := aik.ActivateCredential(tpm, *challenge)
|
||||||
Credential: id,
|
|
||||||
Secret: encSecret,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("aik.ActivateCredential() failed: %v", err)
|
t.Errorf("aik.ActivateCredential() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,6 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/certificate-transparency-go/x509"
|
|
||||||
"github.com/google/go-tspi/verification"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -143,27 +140,10 @@ func TestTPMQuote(t *testing.T) {
|
|||||||
t.Logf("Quote{version: %v, quote: %x, signature: %x}\n", quote.Version, quote.Quote, quote.Signature)
|
t.Logf("Quote{version: %v, quote: %x, signature: %x}\n", quote.Version, quote.Quote, quote.Signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
// chooseEKCertRaw selects the EK cert which will be activated against.
|
|
||||||
func chooseEKCertRaw(t *testing.T, eks []PlatformEK) []byte {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
for _, ek := range eks {
|
|
||||||
if ek.Cert != nil && ek.Cert.PublicKeyAlgorithm == x509.RSA || ek.Cert.PublicKeyAlgorithm == x509.RSAESOAEP {
|
|
||||||
return ek.Cert.Raw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Skip("No suitable RSA EK found")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTPMActivateCredential(t *testing.T) {
|
func TestTPMActivateCredential(t *testing.T) {
|
||||||
if !*testTPM12 {
|
if !*testTPM12 {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
var challenge EncryptedCredential
|
|
||||||
nonce := make([]byte, 20)
|
|
||||||
rand.Read(nonce)
|
|
||||||
|
|
||||||
tpm, err := OpenTPM(tpm12config)
|
tpm, err := OpenTPM(tpm12config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -180,20 +160,25 @@ func TestTPMActivateCredential(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to read EKs: %v", err)
|
t.Fatalf("failed to read EKs: %v", err)
|
||||||
}
|
}
|
||||||
ekcert := chooseEKCertRaw(t, EKs)
|
ek := chooseEKPub(t, EKs)
|
||||||
|
|
||||||
challenge.Credential, challenge.Secret, err = verification.GenerateChallenge(ekcert, aik.aik.(*key12).public, nonce)
|
ap := ActivationParameters{
|
||||||
|
TPMVersion: TPMVersion12,
|
||||||
|
AIK: aik.AttestationParameters(),
|
||||||
|
EK: ek,
|
||||||
|
}
|
||||||
|
secret, challenge, err := ap.Generate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("GenerateChallenge failed: %v", err)
|
t.Fatalf("Generate() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validation, err := aik.ActivateCredential(tpm, challenge)
|
validation, err := aik.ActivateCredential(tpm, *challenge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ActivateCredential failed: %v", err)
|
t.Fatalf("ActivateCredential failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bytes.Equal(validation, nonce) {
|
if !bytes.Equal(validation, secret) {
|
||||||
t.Errorf("secret mismatch: expected %x, got %x", nonce, validation)
|
t.Errorf("secret mismatch: expected %x, got %x", secret, validation)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("validation: %x", validation)
|
t.Logf("validation: %x", validation)
|
||||||
|
140
attest/challenge.go
Normal file
140
attest/challenge.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package attest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ekBlobTag = 0x000c
|
||||||
|
ekBlobActivateTag = 0x002b
|
||||||
|
ekTypeActivate = 0x0001
|
||||||
|
|
||||||
|
algXOR = 0x0000000a
|
||||||
|
|
||||||
|
schemeESNone = 0x0001
|
||||||
|
)
|
||||||
|
|
||||||
|
type symKeyHeader struct {
|
||||||
|
Alg uint32
|
||||||
|
Scheme uint16
|
||||||
|
KeySize uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type activationBlobHeader struct {
|
||||||
|
Tag uint16
|
||||||
|
KeyHeader symKeyHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeEmptyPCRInfo() []byte {
|
||||||
|
var b bytes.Buffer
|
||||||
|
binary.Write(&b, binary.BigEndian, uint16(3)) // SIZE_OF_SELECT
|
||||||
|
b.Write([]byte{0x00, 0x00, 0x00}) // empty bitfield for 3 PCRs
|
||||||
|
b.Write([]byte{0x01}) // TPM_LOCALITY_SELECTION = TPM_LOC_ZERO
|
||||||
|
b.Write(bytes.Repeat([]byte{0}, sha1.Size)) // TPM_COMPOSITE_HASH
|
||||||
|
return b.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeActivationBlob(symKey, aikpub []byte) (blob []byte, err error) {
|
||||||
|
aikHash := sha1.Sum(aikpub)
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
if err := binary.Write(&out, binary.BigEndian, activationBlobHeader{
|
||||||
|
Tag: ekBlobActivateTag,
|
||||||
|
KeyHeader: symKeyHeader{
|
||||||
|
Alg: algXOR,
|
||||||
|
Scheme: schemeESNone,
|
||||||
|
KeySize: uint16(len(symKey)),
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Write(symKey)
|
||||||
|
out.Write(aikHash[:])
|
||||||
|
out.Write(makeEmptyPCRInfo())
|
||||||
|
return out.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ekBlobHeader struct {
|
||||||
|
Tag uint16
|
||||||
|
EkType uint16
|
||||||
|
BlobLen uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeEkBlob(activationBlob []byte) []byte {
|
||||||
|
var out bytes.Buffer
|
||||||
|
binary.Write(&out, binary.BigEndian, ekBlobHeader{
|
||||||
|
Tag: ekBlobTag,
|
||||||
|
EkType: ekTypeActivate,
|
||||||
|
BlobLen: uint32(len(activationBlob)),
|
||||||
|
})
|
||||||
|
out.Write(activationBlob)
|
||||||
|
|
||||||
|
return out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func pad(plaintext []byte, bsize int) []byte {
|
||||||
|
pad := bsize - (len(plaintext) % bsize)
|
||||||
|
if pad == 0 {
|
||||||
|
pad = bsize
|
||||||
|
}
|
||||||
|
for i := 0; i < pad; i++ {
|
||||||
|
plaintext = append(plaintext, byte(pad))
|
||||||
|
}
|
||||||
|
return plaintext
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateChallenge12 generates a TPM_EK_BLOB challenge for a TPM 1.2 device.
|
||||||
|
// This process is defined in section 15.1 of the TPM 1.2 commands spec,
|
||||||
|
// available at: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Main-Part-3-Commands_v1.2_rev116_01032011.pdf
|
||||||
|
//
|
||||||
|
// asymenc is a TPM_EK_BLOB structure containing a TPM_EK_BLOB_ACTIVATE structure,
|
||||||
|
// encrypted with the EK of the TPM. The contained credential is the aes key
|
||||||
|
// for symenc.
|
||||||
|
// symenc is a structure with TPM_SYM_MODE_CBC leading, then the IV, and then
|
||||||
|
// the secret encrypted with the session key credential contained in asymenc.
|
||||||
|
// To use this, pass asymenc as the input to the TPM_ActivateIdentity command.
|
||||||
|
// Use the returned credential as the aes key to decode the secret in symenc.
|
||||||
|
func generateChallenge12(pubkey *rsa.PublicKey, aikpub, secret []byte) (asymenc []byte, symenc []byte, err error) {
|
||||||
|
aeskey := make([]byte, 16)
|
||||||
|
iv := make([]byte, 16)
|
||||||
|
if _, err = rand.Read(aeskey); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if _, err = rand.Read(iv); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
activationBlob, err := makeActivationBlob(aeskey, aikpub)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
label := []byte{'T', 'C', 'P', 'A'}
|
||||||
|
asymenc, err = rsa.EncryptOAEP(sha1.New(), rand.Reader, pubkey, makeEkBlob(activationBlob), label)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("EncryptOAEP() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := aes.NewCipher(aeskey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
cbc := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
secret = pad(secret, len(iv))
|
||||||
|
symenc = make([]byte, len(secret))
|
||||||
|
cbc.CryptBlocks(symenc, secret)
|
||||||
|
|
||||||
|
var symOut bytes.Buffer
|
||||||
|
binary.Write(&symOut, binary.BigEndian, uint32(0x02)) // TPM_SYM_MODE_CBC
|
||||||
|
symOut.Write(iv)
|
||||||
|
symOut.Write(symenc)
|
||||||
|
|
||||||
|
return asymenc, symOut.Bytes(), nil
|
||||||
|
}
|
65
attest/challenge_test.go
Normal file
65
attest/challenge_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package attest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMakeActivationBlob(t *testing.T) {
|
||||||
|
blob, err := makeActivationBlob([]byte{1, 2, 3, 4, 5}, []byte{5, 6, 7, 8})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := blob[0:2], []byte{0, 0x2b}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("tag = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[2:6], []byte{0, 0, 0, 0x0a}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("alg = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[6:8], []byte{0, 1}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("scheme = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[8:10], []byte{0, 5}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("len = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[10:15], []byte{1, 2, 3, 4, 5}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("symKey = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[15:35], []byte{133, 217, 101, 29, 154, 57, 154, 103, 224, 21, 208, 71, 253, 158, 106, 148, 30, 107, 32, 187}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("aik digest = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[35:37], []byte{0, 3}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("size of select = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[37:40], []byte{0, 0, 0}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("select bitfield = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[40:41], []byte{1}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("locality = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := blob[41:61], bytes.Repeat([]byte{0}, 20); !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("select digest = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateChallengeSymHeader(t *testing.T) {
|
||||||
|
cert, err := x509.ParseCertificate(decodeBase64("MIID2jCCA4CgAwIBAgIKFsBPsR6KEUuzHjAKBggqhkjOPQQDAjBVMVMwHwYDVQQDExhOdXZvdG9uIFRQTSBSb290IENBIDIxMTAwJQYDVQQKEx5OdXZvdG9uIFRlY2hub2xvZ3kgQ29ycG9yYXRpb24wCQYDVQQGEwJUVzAeFw0xNzEwMTgyMzQ5MjBaFw0zNzEwMTQyMzQ5MjBaMAAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsiqa4C+4hxqQgQ93aFmVq+hvbV6FDvNod24lA1s24pVJzUdOW/D0ORY3TdvRKS1xEh+yPD+iao+XrRGELHSOrGxid/kaTiOF8KdR5BWJwCoedQasqMyQsgZNlU6nKoERcex2G6DDozkdUgrJ/A04qG8tkpEfwmS+0SVWEtDoTb4fzdehKmS32gKcY/I3ZnmpE/5+FCJHKUwIPxHPwAGdhWoYEGsb7ZwG3/S4UuPEfHaab/iwj/WxwbnGtysMu9r1ZkHjQx6FblWVLoXCqrTl0q0samTuW52MffybbOEzn9R0pnfiyQlpL8CLKP4/kBPUGkkvZm2MJsF2cwNRJtEXVAgMBAAGjggHAMIIBvDBKBgNVHREBAf8EQDA+pDwwOjE4MBQGBWeBBQIBEwtpZDo0RTU0NDMwMDAQBgVngQUCAhMHTlBDVDZ4eDAOBgVngQUCAxMFaWQ6MTMwDAYDVR0TAQH/BAIwADAQBgNVHSUECTAHBgVngQUIATAfBgNVHSMEGDAWgBSfu3mqD1JieL7RUJKacXHpajW+9zAOBgNVHQ8BAf8EBAMCBSAwcAYDVR0JBGkwZzAWBgVngQUCEDENMAsMAzIuMAIBAAIBdDBNBgVngQUCEjFEMEICAQABAf+gAwoBAaEDCgEAogMKAQCjFTATFgMzLjEKAQQKAQEBAf+gAwoBAqQPMA0WBTE0MC0yCgECAQEApQMBAQAwQQYDVR0gBDowODA2BgRVHSAAMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly93d3cubnV2b3Rvbi5jb20vc2VjdXJpdHkvMGgGCCsGAQUFBwEBBFwwWjBYBggrBgEFBQcwAoZMaHR0cDovL3d3dy5udXZvdG9uLmNvbS9zZWN1cml0eS9OVEMtVFBNLUVLLUNlcnQvTnV2b3RvbiBUUE0gUm9vdCBDQSAyMTEwLmNlcjAKBggqhkjOPQQDAgNIADBFAiEAtct+vD/l1Vv9TJOl6oRSI+IZk+k31YIqcscDZEGpZI0CIFFAsVKlFnQnXKTxo7sx9dGOio92Bschl0TQLQhVv0K7", t))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, sym, err := generateChallenge12(cert.PublicKey.(*rsa.PublicKey), []byte("pubkey yo"), []byte("secretz"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := len(sym), 36; got != want {
|
||||||
|
t.Errorf("len(sym) = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := sym[0:4], []byte{0, 0, 0, 2}; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("symmetric mode = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
@ -90,10 +90,11 @@ func (k *key12) Public() crypto.PublicKey {
|
|||||||
return k.publicKey
|
return k.publicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters returns information about the AIK.
|
// AttestationParameters returns information about the AIK.
|
||||||
func (k *key12) Parameters() AIKParameters {
|
func (k *key12) AttestationParameters() AttestationParameters {
|
||||||
return AIKParameters{
|
return AttestationParameters{
|
||||||
Public: k.public,
|
Public: k.public,
|
||||||
|
UseTCSDActivationFormat: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +188,9 @@ func (k *key20) Quote(t *TPM, nonce []byte, alg HashAlg) (*Quote, error) {
|
|||||||
return quote20(t.rwc, k.hnd, tpm2.Algorithm(alg), nonce)
|
return quote20(t.rwc, k.hnd, tpm2.Algorithm(alg), nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters returns information about the AIK.
|
// AttestationParameters returns information about the AIK.
|
||||||
func (k *key20) Parameters() AIKParameters {
|
func (k *key20) AttestationParameters() AttestationParameters {
|
||||||
return AIKParameters{
|
return AttestationParameters{
|
||||||
Public: k.public,
|
Public: k.public,
|
||||||
CreateData: k.createData,
|
CreateData: k.createData,
|
||||||
CreateAttestation: k.createAttestation,
|
CreateAttestation: k.createAttestation,
|
||||||
|
@ -111,9 +111,9 @@ func (k *key12) Close(tpm *TPM) error {
|
|||||||
return closeNCryptObject(k.hnd)
|
return closeNCryptObject(k.hnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters returns information about the AIK.
|
// AttestationParameters returns information about the AIK.
|
||||||
func (k *key12) Parameters() AIKParameters {
|
func (k *key12) AttestationParameters() AttestationParameters {
|
||||||
return AIKParameters{
|
return AttestationParameters{
|
||||||
Public: k.public,
|
Public: k.public,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,9 +202,9 @@ func (k *key20) Delete(tpm *TPM) error {
|
|||||||
return tpm.pcp.DeleteKey(k.hnd)
|
return tpm.pcp.DeleteKey(k.hnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters returns information about the AIK.
|
// AttestationParameters returns information about the AIK.
|
||||||
func (k *key20) Parameters() AIKParameters {
|
func (k *key20) AttestationParameters() AttestationParameters {
|
||||||
return AIKParameters{
|
return AttestationParameters{
|
||||||
Public: k.public,
|
Public: k.public,
|
||||||
CreateData: k.createData,
|
CreateData: k.createData,
|
||||||
CreateAttestation: k.createAttestation,
|
CreateAttestation: k.createAttestation,
|
||||||
|
@ -286,7 +286,7 @@ func (t *TPM) MintAIK(opts *MintOptions) (*AIK, error) {
|
|||||||
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", aikTemplate)
|
blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", aikTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("CreateKeyEx() failed: %v", err)
|
return nil, fmt.Errorf("CreateKeyEx() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
8
go.mod
8
go.mod
@ -5,9 +5,9 @@ go 1.12
|
|||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.3.1
|
github.com/golang/protobuf v1.3.1
|
||||||
github.com/google/certificate-transparency-go v1.0.22-0.20190605205155-41fc2ef3a2a8
|
github.com/google/certificate-transparency-go v1.0.22-0.20190605205155-41fc2ef3a2a8
|
||||||
github.com/google/go-tpm v0.1.2-0.20190430183152-dcb1ada1f875
|
github.com/google/go-tpm v0.1.2-0.20190720204220-b46f7071bbfd
|
||||||
github.com/google/go-tpm-tools v0.0.0-20190328013357-5d2fd7f4b3e5
|
github.com/google/go-tpm-tools v0.0.0-20190328013357-5d2fd7f4b3e5
|
||||||
github.com/google/go-tspi v0.2.0
|
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad
|
||||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd // indirect
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
|
||||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872
|
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7
|
||||||
)
|
)
|
||||||
|
19
go.sum
19
go.sum
@ -2,25 +2,22 @@ github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg
|
|||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
|
github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
|
||||||
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||||
github.com/google/certificate-transparency-go v1.0.22-0.20190403155334-84853901c6b8 h1:pZtGL2P6rU7wOnemTcvTgoH9s+QB646LB5dBcZ1w5yE=
|
|
||||||
github.com/google/certificate-transparency-go v1.0.22-0.20190403155334-84853901c6b8/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
|
||||||
github.com/google/certificate-transparency-go v1.0.22-0.20190605205155-41fc2ef3a2a8 h1:G3Wse9lGL7PmAl2jqdr0HgwhPkGA5KHu7guIPREa7DU=
|
github.com/google/certificate-transparency-go v1.0.22-0.20190605205155-41fc2ef3a2a8 h1:G3Wse9lGL7PmAl2jqdr0HgwhPkGA5KHu7guIPREa7DU=
|
||||||
github.com/google/certificate-transparency-go v1.0.22-0.20190605205155-41fc2ef3a2a8/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
github.com/google/certificate-transparency-go v1.0.22-0.20190605205155-41fc2ef3a2a8/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||||
github.com/google/go-tpm v0.1.2-0.20190430183152-dcb1ada1f875 h1:4+5g5+b2aKnnAXX1XiDcbkU/+daEu8T1HOGbRciBu08=
|
github.com/google/go-tpm v0.1.2-0.20190720204220-b46f7071bbfd h1:vdJl7SmJKhMKpc7XTDMjYCq/hvZT2u1YzABQD1VOqeA=
|
||||||
github.com/google/go-tpm v0.1.2-0.20190430183152-dcb1ada1f875/go.mod h1:70+xJCEPKoR1UFyG62ftF/qOTka+OVFVQpNcWmByY0g=
|
github.com/google/go-tpm v0.1.2-0.20190720204220-b46f7071bbfd/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
|
||||||
github.com/google/go-tpm-tools v0.0.0-20190328013357-5d2fd7f4b3e5 h1:/moKuMi+BJ+OEva3jTms88ruyRkxaZn+f9EIZoGpQeY=
|
github.com/google/go-tpm-tools v0.0.0-20190328013357-5d2fd7f4b3e5 h1:/moKuMi+BJ+OEva3jTms88ruyRkxaZn+f9EIZoGpQeY=
|
||||||
github.com/google/go-tpm-tools v0.0.0-20190328013357-5d2fd7f4b3e5/go.mod h1:ApmLTU8fd5JJJ4J67y9sV16nOTR00GW2OabMwk7kSnE=
|
github.com/google/go-tpm-tools v0.0.0-20190328013357-5d2fd7f4b3e5/go.mod h1:ApmLTU8fd5JJJ4J67y9sV16nOTR00GW2OabMwk7kSnE=
|
||||||
github.com/google/go-tspi v0.2.0 h1:PMrHThARFgHtsCF6B8YNjLlnnGMDdFjVHZnxaqkcbzQ=
|
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad h1:LnpS22S8V1HqbxjveESGAazHhi6BX9SwI2Rij7qZcXQ=
|
||||||
github.com/google/go-tspi v0.2.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd h1:sMHc2rZHuzQmrbVoSpt9HgerkXPyIeCSO6k0zUMGfFk=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190410170021-cc4d4f50624c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 h1:cGjJzUd8RgBw428LXP65YXni0aiGNA4Bl+ls8SmLOm8=
|
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI=
|
||||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user