Skip to content

Commit

Permalink
Make EncodeCreationData accessible, introduce CreateKey labels
Browse files Browse the repository at this point in the history
Signed-off-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
  • Loading branch information
Philipp Deppenwiese authored and zaolin committed Feb 27, 2021
1 parent 1ff48da commit 0bbd3af
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 55 deletions.
4 changes: 2 additions & 2 deletions tpm2/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestEncodeDecodeCreationData(t *testing.T) {
OutsideInfo: []byte{7, 8, 9},
}

encoded, err := cd.encode()
encoded, err := cd.EncodeCreationData()
if err != nil {
t.Fatalf("error encoding CreationData: %v", err)
}
Expand Down Expand Up @@ -188,7 +188,7 @@ func TestEncodeCreate(t *testing.T) {
},
}
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession}
cmdBytes, err := encodeCreate(HandleOwner, pcrSelection7, auth, defaultPassword, []byte{255} /*sensitiveData*/, params)
cmdBytes, err := encodeCreate(HandleOwner, pcrSelection7, auth, defaultPassword, []byte{255} /*sensitiveData*/, params, []byte("TEST"))
if err != nil {
t.Fatal(err)
}
Expand Down
23 changes: 21 additions & 2 deletions tpm2/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ func DecodeAttestationData(in []byte) (*AttestationData, error) {
return nil, fmt.Errorf("decoding AttestedQuoteInfo: %v", err)
}
default:
return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
return nil, fmt.Errorf("only Ouote, Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
}

return &ad, nil
Expand Down Expand Up @@ -705,6 +705,10 @@ func (ad AttestationData) Encode() ([]byte, error) {
if info, err = ad.AttestedCreationInfo.encode(); err != nil {
return nil, fmt.Errorf("encoding AttestedCreationInfo: %v", err)
}
case TagAttestQuote:
if info, err = ad.AttestedQuoteInfo.encode(); err != nil {
return nil, fmt.Errorf("encoding AttestedQuoteInfo: %v", err)
}
default:
return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
}
Expand Down Expand Up @@ -807,6 +811,20 @@ func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
return &out, nil
}

func (qi QuoteInfo) encode() ([]byte, error) {
sel, err := encodeTPMLPCRSelection(qi.PCRSelection)
if err != nil {
return nil, fmt.Errorf("encoding Name: %v", err)
}

digest, err := tpmutil.Pack(qi.PCRDigest)
if err != nil {
return nil, fmt.Errorf("encoding PCRDigest: %v", err)
}

return concat(sel, digest)
}

// IDObject represents an encrypted credential bound to a TPM object.
type IDObject struct {
IntegrityHMAC tpmutil.U16Bytes
Expand All @@ -827,7 +845,8 @@ type CreationData struct {
OutsideInfo tpmutil.U16Bytes
}

func (cd *CreationData) encode() ([]byte, error) {
// EncodeCreationData encodes byte array to TPMS_CREATION_DATA message.
func (cd *CreationData) EncodeCreationData() ([]byte, error) {
sel, err := encodeTPMLPCRSelection(cd.PCRSelection)
if err != nil {
return nil, fmt.Errorf("encoding PCRSelection: %v", err)
Expand Down
51 changes: 20 additions & 31 deletions tpm2/tpm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func encodeSensitiveArea(s tpmsSensitiveCreate) ([]byte, error) {
}

// encodeCreate works for both TPM2_Create and TPM2_CreatePrimary.
func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, ownerPassword string, sensitiveData []byte, pub Public) ([]byte, error) {
func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, ownerPassword string, sensitiveData []byte, pub Public, outsideInfo []byte) ([]byte, error) {
parent, err := tpmutil.Pack(owner)
if err != nil {
return nil, err
Expand All @@ -399,7 +399,7 @@ func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, owne
if err != nil {
return nil, err
}
outsideInfo, err := tpmutil.Pack(tpmutil.U16Bytes(nil))
outsideInfoBlob, err := tpmutil.Pack(tpmutil.U16Bytes(outsideInfo))
if err != nil {
return nil, err
}
Expand All @@ -412,7 +412,7 @@ func encodeCreate(owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, owne
encodedAuth,
inSensitive,
publicBlob,
outsideInfo,
outsideInfoBlob,
creationPCR,
)
}
Expand Down Expand Up @@ -462,7 +462,7 @@ func CreatePrimary(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, par
// are returned, and they are returned in relatively raw form.
func CreatePrimaryEx(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public) (keyHandle tpmutil.Handle, public, creationData, creationHash []byte, ticket Ticket, creationName []byte, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
Cmd, err := encodeCreate(owner, sel, auth, ownerPassword, nil /*inSensitive*/, pub)
Cmd, err := encodeCreate(owner, sel, auth, ownerPassword, nil /*inSensitive*/, pub, nil /*OutsideInfo*/)
if err != nil {
return 0, nil, nil, nil, Ticket{}, nil, err
}
Expand Down Expand Up @@ -527,8 +527,8 @@ func decodeCreate(in []byte) (private, public, creationData, creationHash tpmuti
return private, public, creationData, creationHash, creationTicket, nil
}

func create(rw io.ReadWriter, parentHandle tpmutil.Handle, auth AuthCommand, objectPassword string, sensitiveData []byte, pub Public, pcrSelection PCRSelection) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
cmd, err := encodeCreate(parentHandle, pcrSelection, auth, objectPassword, sensitiveData, pub)
func create(rw io.ReadWriter, parentHandle tpmutil.Handle, auth AuthCommand, objectPassword string, sensitiveData []byte, pub Public, pcrSelection PCRSelection, outsideInfo []byte) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
cmd, err := encodeCreate(parentHandle, pcrSelection, auth, objectPassword, sensitiveData, pub, outsideInfo)
if err != nil {
return nil, nil, nil, nil, Ticket{}, err
}
Expand All @@ -544,21 +544,28 @@ func create(rw io.ReadWriter, parentHandle tpmutil.Handle, auth AuthCommand, obj
// creation data, a hash of said data and the creation ticket.
func CreateKey(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel)
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel, nil /*OutsideInfo*/)
}

// CreateKeyUsingAuth creates a new key pair under the owner handle using the
// provided AuthCommand. Returns private key and public key blobs as well as
// the creation data, a hash of said data, and the creation ticket.
func CreateKeyUsingAuth(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, auth AuthCommand, ownerPassword string, pub Public) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel)
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel, nil /*OutsideInfo*/)
}

// CreateKeyWithSensitive is very similar to CreateKey, except
// that it can take in a piece of sensitive data.
func CreateKeyWithSensitive(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public, sensitive []byte) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
return create(rw, owner, auth, ownerPassword, sensitive, pub, sel)
return create(rw, owner, auth, ownerPassword, sensitive, pub, sel, nil /*OutsideInfo*/)
}

// CreateKeyWithOutsideInfo is very similar to CreateKey, except
// that it returns the outside information.
func CreateKeyWithOutsideInfo(rw io.ReadWriter, owner tpmutil.Handle, sel PCRSelection, parentPassword, ownerPassword string, pub Public, outsideInfo []byte) (private, public, creationData, creationHash []byte, creationTicket Ticket, err error) {
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
return create(rw, owner, auth, ownerPassword, nil /*inSensitive*/, pub, sel, outsideInfo)
}

// Seal creates a data blob object that seals the sensitive data under a parent and with a
Expand All @@ -572,7 +579,7 @@ func Seal(rw io.ReadWriter, parentHandle tpmutil.Handle, parentPassword, objectP
AuthPolicy: objectAuthPolicy,
}
auth := AuthCommand{Session: HandlePasswordSession, Attributes: AttrContinueSession, Auth: []byte(parentPassword)}
private, public, _, _, _, err := create(rw, parentHandle, auth, objectPassword, sensitiveData, inPublic, PCRSelection{})
private, public, _, _, _, err := create(rw, parentHandle, auth, objectPassword, sensitiveData, inPublic, PCRSelection{}, nil /*OutsideInfo*/)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -1746,35 +1753,17 @@ func encodeCertifyEx(objectAuth, signerAuth string, object, signer tpmutil.Handl

func decodeCertify(resp []byte) ([]byte, []byte, error) {
var paramSize uint32
var attest, signature tpmutil.U16Bytes
var sigAlg, hashAlg Algorithm
var attest tpmutil.U16Bytes

buf := bytes.NewBuffer(resp)
if err := tpmutil.UnpackBuf(buf, &paramSize); err != nil {
return nil, nil, err
}
buf.Truncate(int(paramSize))
if err := tpmutil.UnpackBuf(buf, &attest, &sigAlg); err != nil {
if err := tpmutil.UnpackBuf(buf, &attest); err != nil {
return nil, nil, err
}
// If sigAlg is AlgNull, there will be no hashAlg or signature.
// This will happen if AlgNull was passed in the Certify() as
// the signing key (no need to sign the response).
// See TPM2 spec part4 pg227 SignAttestInfo()
if sigAlg != AlgNull {
if sigAlg == AlgECDSA {
var r, s tpmutil.U16Bytes
if err := tpmutil.UnpackBuf(buf, &hashAlg, &r, &s); err != nil {
return nil, nil, err
}
signature = append(r, s...)
} else {
if err := tpmutil.UnpackBuf(buf, &hashAlg, &signature); err != nil {
return nil, nil, err
}
}
}
return attest, signature, nil
return attest, buf.Bytes(), nil
}

// Certify generates a signature of a loaded TPM object with a signing key
Expand Down
60 changes: 40 additions & 20 deletions tpmutil/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"errors"
"io"
"os"
"time"
)

// maxTPMResponse is the largest possible response from the TPM. We need to know
Expand All @@ -41,32 +42,51 @@ func RunCommand(rw io.ReadWriter, tag Tag, cmd Command, in ...interface{}) ([]by
return nil, 0, err
}

if _, err := rw.Write(inb); err != nil {
return nil, 0, err
}
// f(t) = (2^t)ms, up to 2s
var backoffFac uint = 0
var rh responseHeader
var outb []byte

// If the TPM is a real device, it may not be ready for reading immediately after writing
// the command. Wait until the file descriptor is ready to be read from.
if f, ok := rw.(*os.File); ok {
if err = poll(f); err != nil {
for {
if _, err := rw.Write(inb); err != nil {
return nil, 0, err
}
}

outb := make([]byte, maxTPMResponse)
outlen, err := rw.Read(outb)
if err != nil {
return nil, 0, err
}
// Resize the buffer to match the amount read from the TPM.
outb = outb[:outlen]
// If the TPM is a real device, it may not be ready for reading immediately after writing
// the command. Wait until the file descriptor is ready to be read from.
if f, ok := rw.(*os.File); ok {
if err = poll(f); err != nil {
return nil, 0, err
}
}

var rh responseHeader
read, err := Unpack(outb, &rh)
if err != nil {
return nil, 0, err
outb = make([]byte, maxTPMResponse)
outlen, err := rw.Read(outb)
if err != nil {
return nil, 0, err
}
// Resize the buffer to match the amount read from the TPM.
outb = outb[:outlen]

read, err := Unpack(outb, &rh)
if err != nil {
return nil, 0, err
}
outb = outb[read:]

// In case TPM is busy retry the command after waiting a few miliseconds
if rh.Res == RCRetry {
if backoffFac < 11 {
dur := (1 << backoffFac) * time.Millisecond
time.Sleep(dur)
backoffFac++
} else {
return nil, 0, err
}
} else {
break
}
}
outb = outb[read:]

if rh.Res != RCSuccess {
return nil, rh.Res, nil
Expand Down
3 changes: 3 additions & 0 deletions tpmutil/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ type ResponseCode uint32
// 2.0.
const RCSuccess ResponseCode = 0x000

// RCRetry is response code for TPM is busy.
const RCRetry ResponseCode = 0x922

// A responseHeader is a header for TPM responses.
type responseHeader struct {
Tag Tag
Expand Down

0 comments on commit 0bbd3af

Please sign in to comment.