mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-22 21:31:14 -05:00
AB#1770 (semi)automatic PCR updates (#7)
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
752571bbf8
commit
1f843d4593
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@ build
|
||||
admin.conf
|
||||
coordinatorConfig.json
|
||||
coordinator-*
|
||||
util/pcr-reader/pcrs/
|
||||
|
||||
# VS Code configuration folder
|
||||
.vscode
|
||||
|
89
util/pcr-reader/README.md
Normal file
89
util/pcr-reader/README.md
Normal file
@ -0,0 +1,89 @@
|
||||
# PCR-updater
|
||||
|
||||
New images result in different PCR values for the image.
|
||||
This utility program makes it simple to update the expected PCR values of the CLI.
|
||||
|
||||
## Usage
|
||||
|
||||
### Script
|
||||
|
||||
Run `fetch_pcrs.sh` to create Constellations on all supported cloud providers and read their PCR states.
|
||||
```shell
|
||||
./fetch_pcrs.sh
|
||||
```
|
||||
|
||||
The result is printed to screen and written as Go code to files in `./pcrs`.
|
||||
```bash
|
||||
+ main
|
||||
+ command -v constellation
|
||||
+ command -v go
|
||||
+ mkdir -p ./pcrs
|
||||
+ constellation create azure 2 Standard_D4s_v3 --name pcr-fetch -y
|
||||
Your Constellation was created successfully.
|
||||
++ jq '.azurecoordinators | to_entries[] | select(.key|startswith("")) | .value.PublicIP' -rcM constellation-state.json
|
||||
+ coord_ip=192.0.2.1
|
||||
+ go run ../main.go -coord-ip 192.0.2.1 -o ./pcrs/azure_pcrs.go
|
||||
connecting to Coordinator at 192.0.2.1:9000
|
||||
PCRs:
|
||||
{
|
||||
"0": "q27iAZeXGAiCPdu1bqRA2gAoyMO2KrXWY4YkTCQowc4=",
|
||||
...
|
||||
"9": "dEGJtQe3h+SI0z42yO7TklzwPixtM3iMCUeJPGRozvg="
|
||||
}
|
||||
+ constellation terminate
|
||||
Your Constellation was terminated successfully.
|
||||
+ constellation create gcp 2 n2d-standard-2 --name pcr-fetch -y
|
||||
Your Constellation was created successfully.
|
||||
++ jq '.gcpcoordinators | to_entries[] | select(.key|startswith("")) | .value.PublicIP' -rcM constellation-state.json
|
||||
+ coord_ip=192.0.2.2
|
||||
+ go run ../main.go -coord-ip 192.0.2.2 -o ./pcrs/gcp_pcrs.go
|
||||
connecting to Coordinator at 192.0.2.2:9000
|
||||
PCRs:
|
||||
{
|
||||
"0": "DzXCFGCNk8em5ornNZtKi+Wg6Z7qkQfs5CfE3qTkOc8=",
|
||||
...
|
||||
"9": "gse53SjsqREEdOpImJH4KAb0b8PqIgwI+Ps/XSiFnN4="
|
||||
}
|
||||
+ constellation terminate
|
||||
Your Constellation was terminated successfully.
|
||||
```
|
||||
|
||||
### Manual
|
||||
|
||||
To read the PCR state of any running Constellation node, run the following:
|
||||
```shell
|
||||
go run main.go -coord-ip <NODE_IP> -coord-port <COORDINATOR_PORT>
|
||||
```
|
||||
|
||||
The output is similar to the following:
|
||||
```shell
|
||||
$ go run main.go -coord-ip 192.0.2.3 -coord-port 12345
|
||||
connecting to Coordinator at 192.0.2.3:12345
|
||||
PCRs:
|
||||
{
|
||||
"0": "DzXCFGCNk8em5ornNZtKi+Wg6Z7qkQfs5CfE3qTkOc8=",
|
||||
"1": "XBoRlWuQx6nIDr5vgUL0DlJHy6H6u1dPU3qK2NyToc8=",
|
||||
"10": "WLmYFRmDft/ajZJ056CAhpheU6Vbt73aR8eIQpLRGq0=",
|
||||
"11": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"12": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"13": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"14": "4tPyJd6A5g09KduV3+nWZQCiEzHAiRT5DulmAqlvpZU=",
|
||||
"15": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"16": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"17": "//////////////////////////////////////////8=",
|
||||
"18": "//////////////////////////////////////////8=",
|
||||
"19": "//////////////////////////////////////////8=",
|
||||
"2": "PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=",
|
||||
"20": "//////////////////////////////////////////8=",
|
||||
"21": "//////////////////////////////////////////8=",
|
||||
"22": "//////////////////////////////////////////8=",
|
||||
"23": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||||
"3": "PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=",
|
||||
"4": "MmkueFj1rP2seH+bjeIRsO4dUnLnMdl7QgtGoAtQH7M=",
|
||||
"5": "ExaiapuIfo0KMBo8wj6kPDORLocgnH1C0G/KY8DcV3A=",
|
||||
"6": "PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=",
|
||||
"7": "UZcW+fhFRMpFkgU+EfKG2s3KdmgEA+TD2quLmthQHbo=",
|
||||
"8": "KLSMootYaHBjysWKq9CAYXkXpeYx9PUBimlSEZGJqUM=",
|
||||
"9": "gse53SjsqREEdOpImJH4KAb0b8PqIgwI+Ps/XSiFnN4="
|
||||
}
|
||||
```
|
41
util/pcr-reader/fetch_pcrs.sh
Executable file
41
util/pcr-reader/fetch_pcrs.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o xtrace
|
||||
trap 'terminate $?' ERR
|
||||
|
||||
terminate() {
|
||||
echo "error: $1"
|
||||
constellation terminate
|
||||
popd || exit 1
|
||||
exit 1
|
||||
}
|
||||
|
||||
main() {
|
||||
if ! command -v constellation &> /dev/null
|
||||
then
|
||||
echo "constellation is not in path"
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v go &> /dev/null
|
||||
then
|
||||
echo "go is not in path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ./pcrs
|
||||
|
||||
# Fetch Azure PCRs
|
||||
# TODO: Switch to confidential VMs
|
||||
constellation create azure 2 Standard_D4s_v3 --name pcr-fetch -y
|
||||
coord_ip=$(jq '.azurecoordinators | to_entries[] | select(.key|startswith("")) | .value.PublicIP' -rcM constellation-state.json)
|
||||
go run main.go -coord-ip "${coord_ip}" -o ./pcrs/azure_pcrs.go
|
||||
constellation terminate
|
||||
|
||||
# Fetch GCP PCRs
|
||||
constellation create gcp 2 n2d-standard-2 --name pcr-fetch -y
|
||||
coord_ip=$(jq '.gcpcoordinators | to_entries[] | select(.key|startswith("")) | .value.PublicIP' -rcM constellation-state.json)
|
||||
go run main.go -coord-ip "${coord_ip}" -o ./pcrs/gcp_pcrs.go
|
||||
constellation terminate
|
||||
}
|
||||
|
||||
main
|
167
util/pcr-reader/main.go
Normal file
167
util/pcr-reader/main.go
Normal file
@ -0,0 +1,167 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/cli/status"
|
||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/oid"
|
||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||
coordinatorstate "github.com/edgelesssys/constellation/coordinator/state"
|
||||
"github.com/spf13/afero"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
var (
|
||||
coordIP = flag.String("coord-ip", "", "IP of the VM the Coordinator is running on")
|
||||
coordinatorPort = flag.String("coord-port", "9000", "Port of the Coordinator's pub API")
|
||||
export = flag.String("o", "", "Write PCRs, formatted as Go code, to file")
|
||||
quiet = flag.Bool("q", false, "Set to disable output")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
fmt.Printf("connecting to Coordinator at %s:%s\n", *coordIP, *coordinatorPort)
|
||||
addr := net.JoinHostPort(*coordIP, *coordinatorPort)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// wait for coordinator to come online
|
||||
waiter := status.NewWaiter(map[uint32][]byte{})
|
||||
if err := waiter.WaitFor(ctx, coordinatorstate.AcceptingInit, addr); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
attDocRaw := &[]byte{}
|
||||
tlsConfig, err := atls.CreateUnverifiedClientTLSConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
tlsConfig.VerifyPeerCertificate = getVerifyPeerCertificateFunc(attDocRaw)
|
||||
if err := connectToCoordinator(ctx, addr, tlsConfig); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pcrs, err := validatePCRAttDoc(*attDocRaw)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !*quiet {
|
||||
if err := printPCRs(os.Stdout, pcrs); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
if *export != "" {
|
||||
if err := exportToFile(*export, pcrs, &afero.Afero{Fs: afero.NewOsFs()}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// connectToCoordinator connects to the Constellation Coordinator and returns its attestation document.
|
||||
func connectToCoordinator(ctx context.Context, addr string, tlsConfig *tls.Config) error {
|
||||
conn, err := grpc.DialContext(
|
||||
ctx, addr, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := pubproto.NewAPIClient(conn)
|
||||
_, err = client.GetState(ctx, &pubproto.GetStateRequest{})
|
||||
return err
|
||||
}
|
||||
|
||||
// getVerifyPeerCertificateFunc returns a VerifyPeerCertificate function, which writes the attestation document extension to the given byte slice pointer.
|
||||
func getVerifyPeerCertificateFunc(attDoc *[]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
if len(rawCerts) == 0 {
|
||||
return errors.New("rawCerts is empty")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(rawCerts[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ex := range cert.Extensions {
|
||||
if ex.Id.Equal(oid.Azure{}.OID()) || ex.Id.Equal(oid.GCP{}.OID()) || ex.Id.Equal(oid.GCPNonCVM{}.OID()) {
|
||||
if err := json.Unmarshal(ex.Value, attDoc); err != nil {
|
||||
*attDoc = ex.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(*attDoc) == 0 {
|
||||
return errors.New("did not receive attestation document in certificate extension")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// validatePCRAttDoc parses and validates PCRs of an attestation document.
|
||||
func validatePCRAttDoc(attDocRaw []byte) (map[uint32][]byte, error) {
|
||||
attDoc := vtpm.AttestationDocument{}
|
||||
if err := json.Unmarshal(attDocRaw, &attDoc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if attDoc.Attestation == nil {
|
||||
return nil, errors.New("empty attestation")
|
||||
}
|
||||
qIdx, err := vtpm.GetSHA256QuoteIndex(attDoc.Attestation.Quotes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for idx, pcr := range attDoc.Attestation.Quotes[qIdx].Pcrs.Pcrs {
|
||||
if len(pcr) != 32 {
|
||||
return nil, fmt.Errorf("incomplete PCR at index: %d", idx)
|
||||
}
|
||||
}
|
||||
return attDoc.Attestation.Quotes[qIdx].Pcrs.Pcrs, nil
|
||||
}
|
||||
|
||||
// printPCRs formates and prints PCRs to the given writer.
|
||||
func printPCRs(w io.Writer, pcrs map[uint32][]byte) error {
|
||||
pcrJSON, err := json.MarshalIndent(pcrs, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(w, "PCRs:\n%s\n", string(pcrJSON))
|
||||
return nil
|
||||
}
|
||||
|
||||
// exportToFile writes pcrs to a file, formatted to be valid Go code.
|
||||
// Validity of the PCR map is not checked, and should be handled by the caller.
|
||||
func exportToFile(path string, pcrs map[uint32][]byte, fs *afero.Afero) error {
|
||||
goCode := `package pcrs
|
||||
|
||||
var pcrs = map[uint32][]byte{%s
|
||||
}
|
||||
`
|
||||
pcrsFormatted := ""
|
||||
for i := 0; i < len(pcrs); i++ {
|
||||
pcrHex := fmt.Sprintf("%#02X", pcrs[uint32(i)][0])
|
||||
for j := 1; j < len(pcrs[uint32(i)]); j++ {
|
||||
pcrHex = fmt.Sprintf("%s, %#02X", pcrHex, pcrs[uint32(i)][j])
|
||||
}
|
||||
|
||||
pcrsFormatted = pcrsFormatted + fmt.Sprintf("\n\t%d: {%s},", i, pcrHex)
|
||||
}
|
||||
|
||||
return fs.WriteFile(path, []byte(fmt.Sprintf(goCode, pcrsFormatted)), 0o644)
|
||||
}
|
246
util/pcr-reader/main_test.go
Normal file
246
util/pcr-reader/main_test.go
Normal file
@ -0,0 +1,246 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/coordinator/oid"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetVerifyPeerCertificateFunc(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
rawCerts [][]byte
|
||||
errExpected bool
|
||||
}{
|
||||
"no certificates": {
|
||||
rawCerts: nil,
|
||||
errExpected: true,
|
||||
},
|
||||
"invalid certificate": {
|
||||
rawCerts: [][]byte{
|
||||
{0x1, 0x2, 0x3},
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
"no extension": {
|
||||
rawCerts: [][]byte{
|
||||
mustGenerateTestCert(t, &x509.Certificate{
|
||||
SerialNumber: big.NewInt(123),
|
||||
}),
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
"certificate with attestation": {
|
||||
rawCerts: [][]byte{
|
||||
mustGenerateTestCert(t, &x509.Certificate{
|
||||
SerialNumber: big.NewInt(123),
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: oid.GCP{}.OID(),
|
||||
Value: []byte{0x1, 0x2, 0x3},
|
||||
Critical: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
errExpected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
attDoc := &[]byte{}
|
||||
verify := getVerifyPeerCertificateFunc(attDoc)
|
||||
|
||||
err := verify(tc.rawCerts, nil)
|
||||
if tc.errExpected {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
require.NoError(err)
|
||||
|
||||
assert.NotNil(attDoc)
|
||||
cert, err := x509.ParseCertificate(tc.rawCerts[0])
|
||||
require.NoError(err)
|
||||
assert.Equal(cert.Extensions[0].Value, *attDoc)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mustGenerateTestCert(t *testing.T, template *x509.Certificate) []byte {
|
||||
require := require.New(t)
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
require.NoError(err)
|
||||
cert, err := x509.CreateCertificate(rand.Reader, template, template, priv.Public(), priv)
|
||||
require.NoError(err)
|
||||
return cert
|
||||
}
|
||||
|
||||
func TestExportToFile(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
pcrs map[uint32][]byte
|
||||
fs *afero.Afero
|
||||
errExpected bool
|
||||
}{
|
||||
"file not writeable": {
|
||||
pcrs: map[uint32][]byte{
|
||||
0: {0x1, 0x2, 0x3},
|
||||
1: {0x1, 0x2, 0x3},
|
||||
2: {0x1, 0x2, 0x3},
|
||||
},
|
||||
fs: &afero.Afero{Fs: afero.NewReadOnlyFs(afero.NewMemMapFs())},
|
||||
errExpected: true,
|
||||
},
|
||||
"file writeable": {
|
||||
pcrs: map[uint32][]byte{
|
||||
0: {0x1, 0x2, 0x3},
|
||||
1: {0x1, 0x2, 0x3},
|
||||
2: {0x1, 0x2, 0x3},
|
||||
},
|
||||
fs: &afero.Afero{Fs: afero.NewMemMapFs()},
|
||||
errExpected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
path := "test-file"
|
||||
err := exportToFile(path, tc.pcrs, tc.fs)
|
||||
if tc.errExpected {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
content, err := tc.fs.ReadFile(path)
|
||||
require.NoError(err)
|
||||
|
||||
for _, pcr := range tc.pcrs {
|
||||
for _, register := range pcr {
|
||||
assert.Contains(string(content), fmt.Sprintf("%#02X", register))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePCRAttDoc(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
attDocRaw []byte
|
||||
errExpected bool
|
||||
}{
|
||||
"invalid attestation document": {
|
||||
attDocRaw: []byte{0x1, 0x2, 0x3},
|
||||
errExpected: true,
|
||||
},
|
||||
"nil attestation": {
|
||||
attDocRaw: mustMarshalAttDoc(t, vtpm.AttestationDocument{}),
|
||||
errExpected: true,
|
||||
},
|
||||
"nil quotes": {
|
||||
attDocRaw: mustMarshalAttDoc(t, vtpm.AttestationDocument{
|
||||
Attestation: &attest.Attestation{},
|
||||
}),
|
||||
errExpected: true,
|
||||
},
|
||||
"invalid PCRs": {
|
||||
attDocRaw: mustMarshalAttDoc(t, vtpm.AttestationDocument{
|
||||
Attestation: &attest.Attestation{
|
||||
Quotes: []*tpm.Quote{
|
||||
{
|
||||
Pcrs: &tpm.PCRs{
|
||||
Hash: tpm.HashAlgo_SHA256,
|
||||
Pcrs: map[uint32][]byte{
|
||||
0: {0x1, 0x2, 0x3},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
errExpected: true,
|
||||
},
|
||||
"valid PCRs": {
|
||||
attDocRaw: mustMarshalAttDoc(t, vtpm.AttestationDocument{
|
||||
Attestation: &attest.Attestation{
|
||||
Quotes: []*tpm.Quote{
|
||||
{
|
||||
Pcrs: &tpm.PCRs{
|
||||
Hash: tpm.HashAlgo_SHA256,
|
||||
Pcrs: map[uint32][]byte{
|
||||
0: []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
errExpected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
pcrs, err := validatePCRAttDoc(tc.attDocRaw)
|
||||
if tc.errExpected {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
require.NoError(err)
|
||||
|
||||
attDoc := vtpm.AttestationDocument{}
|
||||
require.NoError(json.Unmarshal(tc.attDocRaw, &attDoc))
|
||||
qIdx, err := vtpm.GetSHA256QuoteIndex(attDoc.Attestation.Quotes)
|
||||
require.NoError(err)
|
||||
assert.EqualValues(attDoc.Attestation.Quotes[qIdx].Pcrs.Pcrs, pcrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mustMarshalAttDoc(t *testing.T, attDoc vtpm.AttestationDocument) []byte {
|
||||
attDocRaw, err := json.Marshal(attDoc)
|
||||
require.NoError(t, err)
|
||||
return attDocRaw
|
||||
}
|
||||
|
||||
func TestPrintPCRs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
pcrs := map[uint32][]byte{
|
||||
0: {0x1, 0x2, 0x3},
|
||||
1: {0x1, 0x2, 0x3},
|
||||
2: {0x1, 0x2, 0x3},
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
err := printPCRs(&out, pcrs)
|
||||
assert.NoError(err)
|
||||
|
||||
for idx, pcr := range pcrs {
|
||||
assert.Contains(out.String(), fmt.Sprintf("\"%d\": ", idx))
|
||||
assert.Contains(out.String(), fmt.Sprintf(": \"%s\"", base64.StdEncoding.EncodeToString(pcr)))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user