mirror of
https://github.com/google/go-attestation.git
synced 2025-01-30 23:53:51 +00:00
Merge pull request #104 from ericchiang/measurement-hash
attest: expose algorithms used in measurement log
This commit is contained in:
commit
6fb354c252
@ -62,18 +62,12 @@ type Event struct {
|
|||||||
// match their data to their digest.
|
// match their data to their digest.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseEventLog parses an unverified measurement log.
|
|
||||||
func ParseEventLog(measurementLog []byte) (*EventLog, error) {
|
|
||||||
rawEvents, err := parseEventLog(measurementLog)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("parsing measurement log: %v", err)
|
|
||||||
}
|
|
||||||
return &EventLog{rawEvents}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EventLog is a parsed measurement log. This contains unverified data representing
|
// EventLog is a parsed measurement log. This contains unverified data representing
|
||||||
// boot events that must be replayed against PCR values to determine authenticity.
|
// boot events that must be replayed against PCR values to determine authenticity.
|
||||||
type EventLog struct {
|
type EventLog struct {
|
||||||
|
// Algs holds the set of algorithms that the event log uses.
|
||||||
|
Algs []HashAlg
|
||||||
|
|
||||||
rawEvents []rawEvent
|
rawEvents []rawEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,36 +275,122 @@ func replayEvents(rawEvents []rawEvent, pcrs []PCR) ([]Event, error) {
|
|||||||
// https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf#page=110
|
// https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf#page=110
|
||||||
const eventTypeNoAction = 0x03
|
const eventTypeNoAction = 0x03
|
||||||
|
|
||||||
func parseEventLog(b []byte) ([]rawEvent, error) {
|
// ParseEventLog parses an unverified measurement log.
|
||||||
r := bytes.NewBuffer(b)
|
func ParseEventLog(measurementLog []byte) (*EventLog, error) {
|
||||||
|
r := bytes.NewBuffer(measurementLog)
|
||||||
parseFn := parseRawEvent
|
parseFn := parseRawEvent
|
||||||
|
var el EventLog
|
||||||
e, err := parseFn(r)
|
e, err := parseFn(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse first event: %v", err)
|
return nil, fmt.Errorf("parse first event: %v", err)
|
||||||
}
|
}
|
||||||
var events []rawEvent
|
|
||||||
if e.typ == eventTypeNoAction {
|
if e.typ == eventTypeNoAction {
|
||||||
|
specID, err := parseSpecIDEvent(e.data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse spec ID event: %v", err)
|
||||||
|
}
|
||||||
|
for _, alg := range specID.algs {
|
||||||
|
switch tpm2.Algorithm(alg) {
|
||||||
|
case tpm2.AlgSHA1:
|
||||||
|
el.Algs = append(el.Algs, HashSHA1)
|
||||||
|
case tpm2.AlgSHA256:
|
||||||
|
el.Algs = append(el.Algs, HashSHA256)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(el.Algs) == 0 {
|
||||||
|
return nil, fmt.Errorf("measurement log didn't use sha1 or sha256 digests")
|
||||||
|
}
|
||||||
// Switch to parsing crypto agile events. Don't include this in the
|
// Switch to parsing crypto agile events. Don't include this in the
|
||||||
// replayed events since it's intentionally switching from SHA1 to
|
// replayed events since it intentionally doesn't extend the PCRs.
|
||||||
// SHA256 and will fail to extend a SHA256 PCR value.
|
|
||||||
//
|
//
|
||||||
// NOTE(ericchiang): to be strict, we could parse the event data as a
|
// Note that this doesn't actually guarentee that events have SHA256
|
||||||
// TCG_EfiSpecIDEventStruct and validate the algorithms. But for now,
|
// digests.
|
||||||
// assume this indicates a switch from SHA1 format to SHA1/SHA256.
|
|
||||||
//
|
|
||||||
// https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=18
|
|
||||||
parseFn = parseRawEvent2
|
parseFn = parseRawEvent2
|
||||||
} else {
|
} else {
|
||||||
events = append(events, e)
|
el.Algs = []HashAlg{HashSHA1}
|
||||||
|
el.rawEvents = append(el.rawEvents, e)
|
||||||
}
|
}
|
||||||
for r.Len() != 0 {
|
for r.Len() != 0 {
|
||||||
e, err := parseFn(r)
|
e, err := parseFn(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
events = append(events, e)
|
el.rawEvents = append(el.rawEvents, e)
|
||||||
}
|
}
|
||||||
return events, nil
|
return &el, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type specIDEvent struct {
|
||||||
|
algs []uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type specAlgSize struct {
|
||||||
|
ID uint16
|
||||||
|
Size uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Expected values for various Spec ID Event fields.
|
||||||
|
// https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=19
|
||||||
|
wantSignature = [16]byte{0x53, 0x70,
|
||||||
|
0x65, 0x63, 0x20, 0x49,
|
||||||
|
0x44, 0x20, 0x45, 0x76,
|
||||||
|
0x65, 0x6e, 0x74, 0x30,
|
||||||
|
0x33, 0x00} // "Spec ID Event03\0"
|
||||||
|
wantMajor uint8 = 2
|
||||||
|
wantMinor uint8 = 0
|
||||||
|
wantErrata = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseSpecIDEvent parses a TCG_EfiSpecIDEventStruct structure from the reader.
|
||||||
|
//
|
||||||
|
// https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=18
|
||||||
|
func parseSpecIDEvent(b []byte) (*specIDEvent, error) {
|
||||||
|
r := bytes.NewReader(b)
|
||||||
|
var header struct {
|
||||||
|
Signature [16]byte
|
||||||
|
PlatformClass uint32
|
||||||
|
VersionMinor uint8
|
||||||
|
VersionMajor uint8
|
||||||
|
Errata uint8
|
||||||
|
UintnSize uint8
|
||||||
|
NumAlgs uint32
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
|
||||||
|
return nil, fmt.Errorf("reading event header: %v", err)
|
||||||
|
}
|
||||||
|
if header.Signature != wantSignature {
|
||||||
|
return nil, fmt.Errorf("invalid spec id signature: %x", header.Signature)
|
||||||
|
}
|
||||||
|
if header.VersionMajor != wantMajor {
|
||||||
|
return nil, fmt.Errorf("invalid spec major version, got %02x, wanted %02x",
|
||||||
|
header.VersionMajor, wantMajor)
|
||||||
|
}
|
||||||
|
if header.VersionMinor != wantMinor {
|
||||||
|
return nil, fmt.Errorf("invalid spec minor version, got %02x, wanted %02x",
|
||||||
|
header.VersionMajor, wantMinor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ericchiang): Check errata? Or do we expect that to change in ways
|
||||||
|
// we're okay with?
|
||||||
|
|
||||||
|
algs := make([]specAlgSize, header.NumAlgs)
|
||||||
|
if err := binary.Read(r, binary.LittleEndian, &algs); err != nil {
|
||||||
|
return nil, fmt.Errorf("reading algorithms: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var vendorInfoSize uint8
|
||||||
|
if err := binary.Read(r, binary.LittleEndian, &vendorInfoSize); err != nil {
|
||||||
|
return nil, fmt.Errorf("reading vender info size: %v", err)
|
||||||
|
}
|
||||||
|
if r.Len() != int(vendorInfoSize) {
|
||||||
|
return nil, fmt.Errorf("reading vendor info, expected %d remaining bytes, got %d", vendorInfoSize, r.Len())
|
||||||
|
}
|
||||||
|
var e specIDEvent
|
||||||
|
for _, alg := range algs {
|
||||||
|
e.algs = append(e.algs, alg.ID)
|
||||||
|
}
|
||||||
|
return &e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type rawEvent struct {
|
type rawEvent struct {
|
||||||
|
@ -62,7 +62,7 @@ func testParseEventLog(t *testing.T, testdata string) {
|
|||||||
if err := json.Unmarshal(data, &dump); err != nil {
|
if err := json.Unmarshal(data, &dump); err != nil {
|
||||||
t.Fatalf("parsing test data: %v", err)
|
t.Fatalf("parsing test data: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := parseEventLog(dump.Log.Raw); err != nil {
|
if _, err := ParseEventLog(dump.Log.Raw); err != nil {
|
||||||
t.Fatalf("parsing event log: %v", err)
|
t.Fatalf("parsing event log: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ func TestParseCryptoAgileEventLog(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("reading test data: %v", err)
|
t.Fatalf("reading test data: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := parseEventLog(data); err != nil {
|
if _, err := ParseEventLog(data); err != nil {
|
||||||
t.Fatalf("parsing event log: %v", err)
|
t.Fatalf("parsing event log: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +307,12 @@ func (t *TPM) NewAIK(opts *AIKConfig) (*AIK, error) {
|
|||||||
return t.tpm.newAIK(opts)
|
return t.tpm.newAIK(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PCRs returns the present value of Platform Configuration Registers with the given digest algorithm.
|
// PCRs returns the present value of Platform Configuration Registers with
|
||||||
|
// the given digest algorithm.
|
||||||
|
//
|
||||||
|
// Use ParseEventLog to determine which algorithm to use to match the values
|
||||||
|
// present in the event log. It's not always guarenteed that a system with TPM
|
||||||
|
// 2.0 will extend PCRs with SHA256 digests.
|
||||||
func (t *TPM) PCRs(alg HashAlg) ([]PCR, error) {
|
func (t *TPM) PCRs(alg HashAlg) ([]PCR, error) {
|
||||||
return t.tpm.pcrs(alg)
|
return t.tpm.pcrs(alg)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user