You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

certinfo.go 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package googletpm
  2. import (
  3. "bytes"
  4. "crypto/sha1"
  5. "crypto/sha256"
  6. "crypto/sha512"
  7. "fmt"
  8. "hash"
  9. )
  10. // DecodeAttestationData decode a TPMS_ATTEST message. No error is returned if
  11. // the input has extra trailing data.
  12. func DecodeAttestationData(in []byte) (*AttestationData, error) {
  13. buf := bytes.NewBuffer(in)
  14. var ad AttestationData
  15. if err := UnpackBuf(buf, &ad.Magic, &ad.Type); err != nil {
  16. return nil, fmt.Errorf("decoding Magic/Type: %v", err)
  17. }
  18. n, err := decodeName(buf)
  19. if err != nil {
  20. return nil, fmt.Errorf("decoding QualifiedSigner: %v", err)
  21. }
  22. ad.QualifiedSigner = *n
  23. if err := UnpackBuf(buf, &ad.ExtraData, &ad.ClockInfo, &ad.FirmwareVersion); err != nil {
  24. return nil, fmt.Errorf("decoding ExtraData/ClockInfo/FirmwareVersion: %v", err)
  25. }
  26. // The spec specifies several other types of attestation data. We only need
  27. // parsing of Certify & Creation attestation data for now. If you need
  28. // support for other attestation types, add them here.
  29. switch ad.Type {
  30. case TagAttestCertify:
  31. if ad.AttestedCertifyInfo, err = decodeCertifyInfo(buf); err != nil {
  32. return nil, fmt.Errorf("decoding AttestedCertifyInfo: %v", err)
  33. }
  34. case TagAttestCreation:
  35. if ad.AttestedCreationInfo, err = decodeCreationInfo(buf); err != nil {
  36. return nil, fmt.Errorf("decoding AttestedCreationInfo: %v", err)
  37. }
  38. case TagAttestQuote:
  39. if ad.AttestedQuoteInfo, err = decodeQuoteInfo(buf); err != nil {
  40. return nil, fmt.Errorf("decoding AttestedQuoteInfo: %v", err)
  41. }
  42. default:
  43. return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type)
  44. }
  45. return &ad, nil
  46. }
  47. // AttestationData contains data attested by TPM commands (like Certify).
  48. type AttestationData struct {
  49. Magic uint32
  50. Type Tag
  51. QualifiedSigner Name
  52. ExtraData []byte
  53. ClockInfo ClockInfo
  54. FirmwareVersion uint64
  55. AttestedCertifyInfo *CertifyInfo
  56. AttestedQuoteInfo *QuoteInfo
  57. AttestedCreationInfo *CreationInfo
  58. }
  59. // Tag is a command tag.
  60. type Tag uint16
  61. type Name struct {
  62. Handle *Handle
  63. Digest *HashValue
  64. }
  65. // A Handle is a reference to a TPM object.
  66. type Handle uint32
  67. type HashValue struct {
  68. Alg Algorithm
  69. Value []byte
  70. }
  71. // ClockInfo contains TPM state info included in AttestationData.
  72. type ClockInfo struct {
  73. Clock uint64
  74. ResetCount uint32
  75. RestartCount uint32
  76. Safe byte
  77. }
  78. // CertifyInfo contains Certify-specific data for TPMS_ATTEST.
  79. type CertifyInfo struct {
  80. Name Name
  81. QualifiedName Name
  82. }
  83. // QuoteInfo represents a TPMS_QUOTE_INFO structure.
  84. type QuoteInfo struct {
  85. PCRSelection PCRSelection
  86. PCRDigest []byte
  87. }
  88. // PCRSelection contains a slice of PCR indexes and a hash algorithm used in
  89. // them.
  90. type PCRSelection struct {
  91. Hash Algorithm
  92. PCRs []int
  93. }
  94. // CreationInfo contains Creation-specific data for TPMS_ATTEST.
  95. type CreationInfo struct {
  96. Name Name
  97. // Most TPM2B_Digest structures contain a TPMU_HA structure
  98. // and get parsed to HashValue. This is never the case for the
  99. // digest in TPMS_CREATION_INFO.
  100. OpaqueDigest []byte
  101. }
  102. func decodeName(in *bytes.Buffer) (*Name, error) {
  103. var nameBuf []byte
  104. if err := UnpackBuf(in, &nameBuf); err != nil {
  105. return nil, err
  106. }
  107. name := new(Name)
  108. switch len(nameBuf) {
  109. case 0:
  110. // No name is present.
  111. case 4:
  112. name.Handle = new(Handle)
  113. if err := UnpackBuf(bytes.NewBuffer(nameBuf), name.Handle); err != nil {
  114. return nil, fmt.Errorf("decoding Handle: %v", err)
  115. }
  116. default:
  117. var err error
  118. name.Digest, err = decodeHashValue(bytes.NewBuffer(nameBuf))
  119. if err != nil {
  120. return nil, fmt.Errorf("decoding Digest: %v", err)
  121. }
  122. }
  123. return name, nil
  124. }
  125. func decodeHashValue(in *bytes.Buffer) (*HashValue, error) {
  126. var hv HashValue
  127. if err := UnpackBuf(in, &hv.Alg); err != nil {
  128. return nil, fmt.Errorf("decoding Alg: %v", err)
  129. }
  130. hfn, ok := hashConstructors[hv.Alg]
  131. if !ok {
  132. return nil, fmt.Errorf("unsupported hash algorithm type 0x%x", hv.Alg)
  133. }
  134. hv.Value = make([]byte, hfn().Size())
  135. if _, err := in.Read(hv.Value); err != nil {
  136. return nil, fmt.Errorf("decoding Value: %v", err)
  137. }
  138. return &hv, nil
  139. }
  140. // HashConstructor returns a function that can be used to make a
  141. // hash.Hash using the specified algorithm. An error is returned
  142. // if the algorithm is not a hash algorithm.
  143. func (a Algorithm) HashConstructor() (func() hash.Hash, error) {
  144. c, ok := hashConstructors[a]
  145. if !ok {
  146. return nil, fmt.Errorf("algorithm not supported: 0x%x", a)
  147. }
  148. return c, nil
  149. }
  150. var hashConstructors = map[Algorithm]func() hash.Hash{
  151. AlgSHA1: sha1.New,
  152. AlgSHA256: sha256.New,
  153. AlgSHA384: sha512.New384,
  154. AlgSHA512: sha512.New,
  155. }
  156. // TPM Structure Tags. Tags are used to disambiguate structures, similar to Alg
  157. // values: tag value defines what kind of data lives in a nested field.
  158. const (
  159. TagNull Tag = 0x8000
  160. TagNoSessions Tag = 0x8001
  161. TagSessions Tag = 0x8002
  162. TagAttestCertify Tag = 0x8017
  163. TagAttestQuote Tag = 0x8018
  164. TagAttestCreation Tag = 0x801a
  165. TagHashCheck Tag = 0x8024
  166. )
  167. func decodeCertifyInfo(in *bytes.Buffer) (*CertifyInfo, error) {
  168. var ci CertifyInfo
  169. n, err := decodeName(in)
  170. if err != nil {
  171. return nil, fmt.Errorf("decoding Name: %v", err)
  172. }
  173. ci.Name = *n
  174. n, err = decodeName(in)
  175. if err != nil {
  176. return nil, fmt.Errorf("decoding QualifiedName: %v", err)
  177. }
  178. ci.QualifiedName = *n
  179. return &ci, nil
  180. }
  181. func decodeCreationInfo(in *bytes.Buffer) (*CreationInfo, error) {
  182. var ci CreationInfo
  183. n, err := decodeName(in)
  184. if err != nil {
  185. return nil, fmt.Errorf("decoding Name: %v", err)
  186. }
  187. ci.Name = *n
  188. if err := UnpackBuf(in, &ci.OpaqueDigest); err != nil {
  189. return nil, fmt.Errorf("decoding Digest: %v", err)
  190. }
  191. return &ci, nil
  192. }
  193. func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) {
  194. var out QuoteInfo
  195. sel, err := decodeTPMLPCRSelection(in)
  196. if err != nil {
  197. return nil, fmt.Errorf("decoding PCRSelection: %v", err)
  198. }
  199. out.PCRSelection = sel
  200. if err := UnpackBuf(in, &out.PCRDigest); err != nil {
  201. return nil, fmt.Errorf("decoding PCRDigest: %v", err)
  202. }
  203. return &out, nil
  204. }
  205. func decodeTPMLPCRSelection(buf *bytes.Buffer) (PCRSelection, error) {
  206. var count uint32
  207. var sel PCRSelection
  208. if err := UnpackBuf(buf, &count); err != nil {
  209. return sel, err
  210. }
  211. switch count {
  212. case 0:
  213. sel.Hash = AlgUnknown
  214. return sel, nil
  215. case 1: // We only support decoding of a single PCRSelection.
  216. default:
  217. return sel, fmt.Errorf("decoding TPML_PCR_SELECTION list longer than 1 is not supported (got length %d)", count)
  218. }
  219. // See comment in encodeTPMLPCRSelection for details on this format.
  220. var ts tpmsPCRSelection
  221. if err := UnpackBuf(buf, &ts.Hash, &ts.Size); err != nil {
  222. return sel, err
  223. }
  224. ts.PCRs = make([]byte, ts.Size)
  225. if _, err := buf.Read(ts.PCRs); err != nil {
  226. return sel, err
  227. }
  228. sel.Hash = ts.Hash
  229. for i := 0; i < int(ts.Size); i++ {
  230. for j := 0; j < 8; j++ {
  231. set := ts.PCRs[i] & byte(1<<byte(j))
  232. if set == 0 {
  233. continue
  234. }
  235. sel.PCRs = append(sel.PCRs, 8*i+j)
  236. }
  237. }
  238. return sel, nil
  239. }
  240. type tpmsPCRSelection struct {
  241. Hash Algorithm
  242. Size byte
  243. PCRs RawBytes
  244. }
  245. // RawBytes is for Pack and RunCommand arguments that are already encoded.
  246. // Compared to []byte, RawBytes will not be prepended with slice length during
  247. // encoding.
  248. type RawBytes []byte