mirror of
https://github.com/google/go-attestation.git
synced 2024-12-20 13:33:13 +00:00
f0e8d0fe7c
@brandonweeks detected another case of the "make([]T, untrustedValue)" pattern, which would allow an attacker to cause the parser to allocate an unbounded amount of memory. Fix this by reading one algorithm at a time instead of pre-allocating a slice of algorithms.
259 lines
6.2 KiB
Go
259 lines
6.2 KiB
Go
// Copyright 2019 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
package attest
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"testing"
|
|
|
|
"github.com/google/go-tpm/tpm2"
|
|
)
|
|
|
|
// Dump describes the layout of serialized information from the dump command.
|
|
type Dump struct {
|
|
Static struct {
|
|
TPMVersion TPMVersion
|
|
EKPem []byte
|
|
}
|
|
|
|
AK AttestationParameters
|
|
|
|
Quote struct {
|
|
Nonce []byte
|
|
Alg HashAlg
|
|
Quote []byte
|
|
Signature []byte
|
|
}
|
|
|
|
Log struct {
|
|
PCRs []PCR
|
|
PCRAlg tpm2.Algorithm
|
|
Raw []byte // The measured boot log in binary form.
|
|
}
|
|
}
|
|
|
|
func TestParseEventLogWindows(t *testing.T) {
|
|
testParseEventLog(t, "testdata/windows_gcp_shielded_vm.json")
|
|
}
|
|
|
|
func TestParseEventLogLinux(t *testing.T) {
|
|
testParseEventLog(t, "testdata/linux_tpm12.json")
|
|
}
|
|
|
|
func testParseEventLog(t *testing.T, testdata string) {
|
|
data, err := ioutil.ReadFile(testdata)
|
|
if err != nil {
|
|
t.Fatalf("reading test data: %v", err)
|
|
}
|
|
var dump Dump
|
|
if err := json.Unmarshal(data, &dump); err != nil {
|
|
t.Fatalf("parsing test data: %v", err)
|
|
}
|
|
if _, err := ParseEventLog(dump.Log.Raw); err != nil {
|
|
t.Fatalf("parsing event log: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseCryptoAgileEventLog(t *testing.T) {
|
|
data, err := ioutil.ReadFile("testdata/crypto_agile_eventlog")
|
|
if err != nil {
|
|
t.Fatalf("reading test data: %v", err)
|
|
}
|
|
if _, err := ParseEventLog(data); err != nil {
|
|
t.Fatalf("parsing event log: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEventLogLinux(t *testing.T) {
|
|
testEventLog(t, "testdata/linux_tpm12.json")
|
|
}
|
|
|
|
func TestEventLog(t *testing.T) {
|
|
testEventLog(t, "testdata/windows_gcp_shielded_vm.json")
|
|
}
|
|
|
|
func testEventLog(t *testing.T, testdata string) {
|
|
data, err := ioutil.ReadFile(testdata)
|
|
if err != nil {
|
|
t.Fatalf("reading test data: %v", err)
|
|
}
|
|
var dump Dump
|
|
if err := json.Unmarshal(data, &dump); err != nil {
|
|
t.Fatalf("parsing test data: %v", err)
|
|
}
|
|
|
|
ak, err := ParseAKPublic(dump.Static.TPMVersion, dump.AK.Public)
|
|
if err != nil {
|
|
t.Fatalf("parsing AK: %v", err)
|
|
}
|
|
if err := ak.Verify(Quote{
|
|
Version: dump.Static.TPMVersion,
|
|
Quote: dump.Quote.Quote,
|
|
Signature: dump.Quote.Signature,
|
|
}, dump.Log.PCRs, dump.Quote.Nonce); err != nil {
|
|
t.Fatalf("verifying quote: %v", err)
|
|
}
|
|
|
|
el, err := ParseEventLog(dump.Log.Raw)
|
|
if err != nil {
|
|
t.Fatalf("parsing event log: %v", err)
|
|
}
|
|
events, err := el.Verify(dump.Log.PCRs)
|
|
if err != nil {
|
|
t.Fatalf("validating event log: %v", err)
|
|
}
|
|
|
|
for i, e := range events {
|
|
if e.sequence != i {
|
|
t.Errorf("event out of order: events[%d].sequence = %d, want %d", i, e.sequence, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseEventLogEventSizeTooLarge(t *testing.T) {
|
|
data := []byte{
|
|
// PCR index
|
|
0x30, 0x34, 0x39, 0x33,
|
|
// type
|
|
0x36, 0x30, 0x30, 0x32,
|
|
|
|
// Digest
|
|
0x31, 0x39, 0x36, 0x33, 0x39, 0x34, 0x34, 0x37, 0x39, 0x32,
|
|
0x31, 0x32, 0x32, 0x37, 0x39, 0x30, 0x34, 0x30, 0x31, 0x6d,
|
|
|
|
// Even size (3.183 GB)
|
|
0xbd, 0xbf, 0xef, 0x47,
|
|
|
|
// "event data"
|
|
0x00, 0x00, 0x00, 0x00,
|
|
}
|
|
|
|
// If this doesn't panic, the test passed
|
|
// TODO(ericchiang): use errors.As once go-attestation switches to Go 1.13.
|
|
_, err := ParseEventLog(data)
|
|
if err == nil {
|
|
t.Fatalf("expected parsing invalid event log to fail")
|
|
}
|
|
}
|
|
|
|
func TestParseSpecIDEvent(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
want []uint16
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "sha1",
|
|
data: append(
|
|
[]byte("Spec ID Event03"), 0x0,
|
|
0x0, 0x0, 0x0, 0x0, // platform class
|
|
0x0, // verison minor
|
|
0x2, // version major
|
|
0x0, // errata
|
|
0x8, // uintn size
|
|
0x1, 0x0, 0x0, 0x0, // num algs
|
|
0x04, 0x0, // SHA1
|
|
0x14, 0x0, // size
|
|
0x2, // vendor info size
|
|
0x0, 0x0,
|
|
),
|
|
want: []uint16{0x0004},
|
|
},
|
|
{
|
|
name: "sha1_and_sha256",
|
|
data: append(
|
|
[]byte("Spec ID Event03"), 0x0,
|
|
0x0, 0x0, 0x0, 0x0, // platform class
|
|
0x0, // verison minor
|
|
0x2, // version major
|
|
0x0, // errata
|
|
0x8, // uintn size
|
|
0x2, 0x0, 0x0, 0x0, // num algs
|
|
0x04, 0x0, // SHA1
|
|
0x14, 0x0, // size
|
|
0x0B, 0x0, // SHA256
|
|
0x20, 0x0, // size
|
|
0x2, // vendor info size
|
|
0x0, 0x0,
|
|
),
|
|
want: []uint16{0x0004, 0x000B},
|
|
},
|
|
{
|
|
name: "invalid_version",
|
|
data: append(
|
|
[]byte("Spec ID Event03"), 0x0,
|
|
0x0, 0x0, 0x0, 0x0, // platform class
|
|
0x2, // verison minor
|
|
0x1, // version major
|
|
0x0, // errata
|
|
0x8, // uintn size
|
|
0x2, 0x0, 0x0, 0x0, // num algs
|
|
0x04, 0x0, // SHA1
|
|
0x14, 0x0, // size
|
|
0x0B, 0x0, // SHA256
|
|
0x20, 0x0, // size
|
|
0x2, // vendor info size
|
|
0x0, 0x0,
|
|
),
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "malicious_number_of_algs",
|
|
data: append(
|
|
[]byte("Spec ID Event03"), 0x0,
|
|
0x0, 0x0, 0x0, 0x0, // platform class
|
|
0x0, // verison minor
|
|
0x2, // version major
|
|
0x0, // errata
|
|
0x8, // uintn size
|
|
0xff, 0xff, 0xff, 0xff, // num algs
|
|
0x04, 0x0, // SHA1
|
|
0x14, 0x0, // size
|
|
0x2, // vendor info size
|
|
0x0, 0x0,
|
|
),
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
spec, err := parseSpecIDEvent(test.data)
|
|
if (err != nil) != test.wantErr {
|
|
t.Fatalf("parsing spec, wantErr=%t, got=%v", test.wantErr, err)
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
algsEq := func(got, want []uint16) bool {
|
|
if len(got) != len(want) {
|
|
return false
|
|
}
|
|
for i, alg := range got {
|
|
if want[i] != alg {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
if !algsEq(test.want, spec.algs) {
|
|
t.Errorf("algorithms, got=%x, want=%x", spec.algs, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|