123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- package googletpm
-
- import (
- "bytes"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/sha512"
- "fmt"
- "hash"
- )
-
- // DecodeAttestationData decode a TPMS_ATTEST message. No error is returned if
- // the input has extra trailing data.
- func DecodeAttestationData(in []byte) (*AttestationData, error) {
- buf := bytes.NewBuffer(in)
-
- var ad AttestationData
- if err := UnpackBuf(buf, &ad.Magic, &ad.Type); err != nil {
- return nil, fmt.Errorf("decoding Magic/Type: %v", err)
- }
- n, err := decodeName(buf)
- if err != nil {
- return nil, fmt.Errorf("decoding QualifiedSigner: %v", err)
- }
- ad.QualifiedSigner = *n
- if err := UnpackBuf(buf, &ad.ExtraData, &ad.ClockInfo, &ad.FirmwareVersion); err != nil {
- return nil, fmt.Errorf("decoding ExtraData/ClockInfo/FirmwareVersion: %v", err)
- }
-
- // The spec specifies several other types of attestation data. We only need
- // parsing of Certify & Creation attestation data for now. If you need
- // support for other attestation types, add them here.
- switch ad.Type {
- case TagAttestCertify:
- if ad.AttestedCertifyInfo, err = decodeCertifyInfo(buf); err != nil {
- return nil, fmt.Errorf("decoding AttestedCertifyInfo: %v", err)
- }
- case TagAttestCreation:
- if ad.AttestedCreationInfo, err = decodeCreationInfo(buf); err != nil {
- return nil, fmt.Errorf("decoding AttestedCreationInfo: %v", err)
- }
- case TagAttestQuote:
- if ad.AttestedQuoteInfo, err = decodeQuoteInfo(buf); err != nil {
- 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 &ad, nil
- }
-
- // AttestationData contains data attested by TPM commands (like Certify).
- type AttestationData struct {
- Magic uint32
- Type Tag
- QualifiedSigner Name
- ExtraData []byte
- ClockInfo ClockInfo
- FirmwareVersion uint64
- AttestedCertifyInfo *CertifyInfo
- AttestedQuoteInfo *QuoteInfo
- AttestedCreationInfo *CreationInfo
- }
-
- // Tag is a command tag.
- type Tag uint16
-
- type Name struct {
- Handle *Handle
- Digest *HashValue
- }
-
- // A Handle is a reference to a TPM object.
- type Handle uint32
- type HashValue struct {
- Alg Algorithm
- Value []byte
- }
-
- // ClockInfo contains TPM state info included in AttestationData.
- type ClockInfo struct {
- Clock uint64
- ResetCount uint32
- RestartCount uint32
- Safe byte
- }
-
- // CertifyInfo contains Certify-specific data for TPMS_ATTEST.
- type CertifyInfo struct {
- Name Name
- QualifiedName Name
- }
-
- // QuoteInfo represents a TPMS_QUOTE_INFO structure.
- type QuoteInfo struct {
- PCRSelection PCRSelection
- PCRDigest []byte
- }
-
- // PCRSelection contains a slice of PCR indexes and a hash algorithm used in
- // them.
- type PCRSelection struct {
- Hash Algorithm
- PCRs []int
- }
-
- // CreationInfo contains Creation-specific data for TPMS_ATTEST.
- type CreationInfo struct {
- Name Name
- // Most TPM2B_Digest structures contain a TPMU_HA structure
- // and get parsed to HashValue. This is never the case for the
- // digest in TPMS_CREATION_INFO.
- OpaqueDigest []byte
- }
-
- func decodeName(in *bytes.Buffer) (*Name, error) {
- var nameBuf []byte
- if err := UnpackBuf(in, &nameBuf); err != nil {
- return nil, err
- }
-
- name := new(Name)
- switch len(nameBuf) {
- case 0:
- // No name is present.
- case 4:
- name.Handle = new(Handle)
- if err := UnpackBuf(bytes.NewBuffer(nameBuf), name.Handle); err != nil {
- return nil, fmt.Errorf("decoding Handle: %v", err)
- }
- default:
- var err error
- name.Digest, err = decodeHashValue(bytes.NewBuffer(nameBuf))
- if err != nil {
- return nil, fmt.Errorf("decoding Digest: %v", err)
- }
- }
- return name, nil
- }
-
- func decodeHashValue(in *bytes.Buffer) (*HashValue, error) {
- var hv HashValue
- if err := UnpackBuf(in, &hv.Alg); err != nil {
- return nil, fmt.Errorf("decoding Alg: %v", err)
- }
- hfn, ok := hashConstructors[hv.Alg]
- if !ok {
- return nil, fmt.Errorf("unsupported hash algorithm type 0x%x", hv.Alg)
- }
- hv.Value = make([]byte, hfn().Size())
- if _, err := in.Read(hv.Value); err != nil {
- return nil, fmt.Errorf("decoding Value: %v", err)
- }
- return &hv, nil
- }
-
- // HashConstructor returns a function that can be used to make a
- // hash.Hash using the specified algorithm. An error is returned
- // if the algorithm is not a hash algorithm.
- func (a Algorithm) HashConstructor() (func() hash.Hash, error) {
- c, ok := hashConstructors[a]
- if !ok {
- return nil, fmt.Errorf("algorithm not supported: 0x%x", a)
- }
- return c, nil
- }
-
- var hashConstructors = map[Algorithm]func() hash.Hash{
- AlgSHA1: sha1.New,
- AlgSHA256: sha256.New,
- AlgSHA384: sha512.New384,
- AlgSHA512: sha512.New,
- }
-
- // TPM Structure Tags. Tags are used to disambiguate structures, similar to Alg
- // values: tag value defines what kind of data lives in a nested field.
- const (
- TagNull Tag = 0x8000
- TagNoSessions Tag = 0x8001
- TagSessions Tag = 0x8002
- TagAttestCertify Tag = 0x8017
- TagAttestQuote Tag = 0x8018
- TagAttestCreation Tag = 0x801a
- TagHashCheck Tag = 0x8024
- )
-
- func decodeCertifyInfo(in *bytes.Buffer) (*CertifyInfo, error) {
- var ci CertifyInfo
-
- n, err := decodeName(in)
- if err != nil {
- return nil, fmt.Errorf("decoding Name: %v", err)
- }
- ci.Name = *n
-
- n, err = decodeName(in)
- if err != nil {
- return nil, fmt.Errorf("decoding QualifiedName: %v", err)
- }
- ci.QualifiedName = *n
-
- return &ci, nil
- }
-
- func decodeCreationInfo(in *bytes.Buffer) (*CreationInfo, error) {
- var ci CreationInfo
-
- n, err := decodeName(in)
- if err != nil {
- return nil, fmt.Errorf("decoding Name: %v", err)
- }
- ci.Name = *n
-
- if err := UnpackBuf(in, &ci.OpaqueDigest); err != nil {
- return nil, fmt.Errorf("decoding Digest: %v", err)
- }
-
- return &ci, nil
- }
-
- func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
- var out QuoteInfo
- sel, err := decodeTPMLPCRSelection(in)
- if err != nil {
- return nil, fmt.Errorf("decoding PCRSelection: %v", err)
- }
- out.PCRSelection = sel
- if err := UnpackBuf(in, &out.PCRDigest); err != nil {
- return nil, fmt.Errorf("decoding PCRDigest: %v", err)
- }
- return &out, nil
- }
-
- func decodeTPMLPCRSelection(buf *bytes.Buffer) (PCRSelection, error) {
- var count uint32
- var sel PCRSelection
- if err := UnpackBuf(buf, &count); err != nil {
- return sel, err
- }
- switch count {
- case 0:
- sel.Hash = AlgUnknown
- return sel, nil
- case 1: // We only support decoding of a single PCRSelection.
- default:
- return sel, fmt.Errorf("decoding TPML_PCR_SELECTION list longer than 1 is not supported (got length %d)", count)
- }
-
- // See comment in encodeTPMLPCRSelection for details on this format.
- var ts tpmsPCRSelection
- if err := UnpackBuf(buf, &ts.Hash, &ts.Size); err != nil {
- return sel, err
- }
- ts.PCRs = make([]byte, ts.Size)
- if _, err := buf.Read(ts.PCRs); err != nil {
- return sel, err
- }
-
- sel.Hash = ts.Hash
- for i := 0; i < int(ts.Size); i++ {
- for j := 0; j < 8; j++ {
- set := ts.PCRs[i] & byte(1<<byte(j))
- if set == 0 {
- continue
- }
- sel.PCRs = append(sel.PCRs, 8*i+j)
- }
- }
- return sel, nil
- }
-
- type tpmsPCRSelection struct {
- Hash Algorithm
- Size byte
- PCRs RawBytes
- }
-
- // RawBytes is for Pack and RunCommand arguments that are already encoded.
- // Compared to []byte, RawBytes will not be prepended with slice length during
- // encoding.
- type RawBytes []byte
|