Skip to content

Commit a78f5b7

Browse files
committed
fix(scheme): update CCA scheme AppraiseClaims
Update AppraiseClaims to expect the new endorsements format introduced in d4c39f7. Also update expected results in integration tests to expect "affirming" for realm. They were originally "warning" because all schemes were tested using the same end-to-end test that could only provision one CoRIM, and so only platform endorsements were provisioned. We have since switched CCA to use its own flow that provisions both platform and realm endorsements. The fact that we were still expecting "warning" partially obscured the other issue being fixed here. Signed-off-by: Sergei Trofimov <sergei.trofimov@arm.com>
1 parent dfbb77e commit a78f5b7

3 files changed

Lines changed: 112 additions & 92 deletions

File tree

integration-tests/data/results/cca.good.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@
5151
},
5252
"CCA_REALM": {
5353
"ear.appraisal-policy-id": "policy:ARM_CCA",
54-
"ear.status": "warning",
54+
"ear.status": "affirming",
5555
"ear.trustworthiness-vector": {
5656
"configuration": 0,
57-
"executables": 33,
57+
"executables": 2,
5858
"file-system": 0,
5959
"hardware": 0,
6060
"instance-identity": 2,

integration-tests/data/results/cca.verify-challenge.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
}
5050
},
5151
"CCA_REALM": {
52-
"ear.status": "warning",
52+
"ear.status": "affirming",
5353
"ear.trustworthiness-vector": {
5454
"configuration": 0,
55-
"executables": 33,
55+
"executables": 2,
5656
"file-system": 0,
5757
"hardware": 0,
5858
"instance-identity": 2,

scheme/arm-cca/scheme.go

Lines changed: 108 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@ import (
99
"encoding/json"
1010
"errors"
1111
"fmt"
12-
"strconv"
13-
"strings"
1412

1513
"github.com/veraison/ccatoken"
1614
"github.com/veraison/ccatoken/platform"
1715
"github.com/veraison/ccatoken/realm"
1816
"github.com/veraison/corim/comid"
1917
"github.com/veraison/corim/profiles/cca"
2018
"github.com/veraison/ear"
19+
"github.com/veraison/psatoken"
2120
"github.com/veraison/services/handler"
2221
"github.com/veraison/services/log"
2322
"github.com/veraison/services/scheme/common"
2423
"github.com/veraison/services/vts/appraisal"
2524
"go.uber.org/zap"
2625
)
2726

27+
const NUM_REMS = 4
28+
2829
var Descriptor = handler.SchemeDescriptor{
2930
Name: "ARM_CCA",
3031
VersionMajor: 1,
@@ -113,7 +114,9 @@ func (o *Implementation) GetReferenceValueIDs(
113114
Class: trustAnchors[0].Environment.Class,
114115
},
115116
{
116-
Instance: comid.MustNewBytesInstance(rimValue),
117+
Class: &comid.Class{
118+
ClassID: comid.MustNewBytesClassID(rimValue),
119+
},
117120
},
118121
}, nil
119122
}
@@ -320,57 +323,66 @@ func AppraiseRealm(
320323
appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim
321324
appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim
322325

326+
logger.Debug("collecting realm reference values...")
323327
referenceValues := make([]realmReference, 0, len(endorsements))
324328
for _, triple := range endorsements {
325-
// unset Instance indicates platform endorsements
326-
if triple.Environment.Instance == nil {
327-
continue
329+
refVal := realmReference{
330+
ExtensibleMeasurements: make([][]byte, NUM_REMS),
328331
}
329332

330333
for _, measurement := range triple.Measurements.Values {
331-
refVal := realmReference{}
334+
mkey, err := readMeasurementKey(&measurement)
335+
if err != nil {
336+
return err
337+
}
332338

333-
if measurement.Val.RawValue != nil {
334-
refVal.PersonalizationValue, err = measurement.Val.RawValue.GetBytes()
339+
switch mkey {
340+
case cca.CCARealmInitialMeasurementMkey:
341+
digest, err := readMeasurementDigestBytes(&measurement)
335342
if err != nil {
336-
return fmt.Errorf("personalization value: %w", err)
343+
return fmt.Errorf("%s: %w", cca.CCARealmInitialMeasurementMkey, err)
337344
}
338-
}
339-
340-
if measurement.Val.IntegrityRegisters == nil {
341-
return errors.New("integrity registers not set in realm reference")
342-
}
343-
344-
numREMs := len(measurement.Val.IntegrityRegisters.IndexMap) - 1
345-
refVal.ExtensibleMeasurements = make([][]byte, numREMs)
346-
347-
for key, digests := range measurement.Val.IntegrityRegisters.IndexMap {
348-
dLen := len(digests)
349-
if dLen != 1 {
350-
return fmt.Errorf("expected 1 digest for integ. reg.; found %d", dLen)
345+
refVal.InitialMeasurement = digest
346+
case cca.CCARealmExtendedMeasurement0Mkey:
347+
digest, err := readMeasurementDigestBytes(&measurement)
348+
if err != nil {
349+
return fmt.Errorf("%s: %w", cca.CCARealmExtendedMeasurement0Mkey, err)
351350
}
352-
353-
keyText, ok := key.(string)
354-
if !ok {
355-
return fmt.Errorf("non-string integ. reg. key: %v", key)
351+
refVal.ExtensibleMeasurements[0] = digest
352+
case cca.CCARealmExtendedMeasurement1Mkey:
353+
digest, err := readMeasurementDigestBytes(&measurement)
354+
if err != nil {
355+
return fmt.Errorf("%s: %w", cca.CCARealmExtendedMeasurement1Mkey, err)
356356
}
357-
358-
if keyText == "rim" {
359-
refVal.InitialMeasurement = digests[0].HashValue
360-
} else {
361-
idxText := strings.Replace(keyText, "rem", "", 1)
362-
idx, err := strconv.Atoi(idxText)
363-
if err != nil {
364-
return fmt.Errorf("bad REM key: %s", keyText)
365-
}
366-
367-
refVal.ExtensibleMeasurements[idx] = digests[0].HashValue
357+
refVal.ExtensibleMeasurements[1] = digest
358+
case cca.CCARealmExtendedMeasurement2Mkey:
359+
digest, err := readMeasurementDigestBytes(&measurement)
360+
if err != nil {
361+
return fmt.Errorf("%s: %w", cca.CCARealmExtendedMeasurement2Mkey, err)
368362
}
363+
refVal.ExtensibleMeasurements[2] = digest
364+
case cca.CCARealmExtendedMeasurement3Mkey:
365+
digest, err := readMeasurementDigestBytes(&measurement)
366+
if err != nil {
367+
return fmt.Errorf("%s: %w", cca.CCARealmExtendedMeasurement3Mkey, err)
368+
}
369+
refVal.ExtensibleMeasurements[3] = digest
370+
case cca.CCARealmPersonalizationMkey:
371+
refVal.PersonalizationValue, err = measurement.Val.RawValue.GetBytes()
372+
if err != nil {
373+
return fmt.Errorf("%s: %w", cca.CCARealmPersonalizationMkey, err)
374+
}
375+
default:
376+
logger.Debugw("skipping non-realm measurement", "mkey", mkey)
369377
}
370378

379+
}
380+
381+
if refVal.InitialMeasurement != nil {
371382
referenceValues = append(referenceValues, refVal)
372383
}
373384
}
385+
logger.Debug("collected realm reference values", "values", referenceValues)
374386

375387
for _, refVal := range referenceValues {
376388
if !bytes.Equal(refVal.InitialMeasurement, evidenceRIM) {
@@ -428,6 +440,38 @@ func convertToPlatformClaims(v any) (platform.IClaims, error) {
428440
return platform.DecodeClaimsFromJSON(encoded)
429441
}
430442

443+
func readMeasurementKey(measurement *comid.Measurement) (string, error) {
444+
if measurement.Key == nil || !measurement.Key.IsSet() {
445+
return "", errors.New(" measurement missing mkey")
446+
}
447+
448+
if measurement.Key.Type() != comid.StringType {
449+
return "", fmt.Errorf(
450+
"measurement mkey must be string, got %s",
451+
measurement.Key.Type(),
452+
)
453+
}
454+
455+
return measurement.Key.Value.String(), nil
456+
}
457+
458+
func readMeasurementDigestBytes(measurement *comid.Measurement) ([]byte, error) {
459+
// Not a platform-config entry: this must be a platform software component.
460+
if measurement.Val.Digests == nil {
461+
return nil, errors.New("no digests in reference value measurement")
462+
}
463+
464+
numDigests := len(*measurement.Val.Digests)
465+
if numDigests != 1 {
466+
return nil, fmt.Errorf(
467+
"expected exactly 1 digest in measurement; found %d",
468+
numDigests,
469+
)
470+
}
471+
472+
return (*measurement.Val.Digests)[0].HashValue, nil
473+
}
474+
431475
func matchPlatformClaimsToReferenceValues(
432476
logger *zap.SugaredLogger,
433477
claims platform.IClaims,
@@ -436,30 +480,18 @@ func matchPlatformClaimsToReferenceValues(
436480
var err error
437481
var referenceConfigValue []byte
438482

483+
logger.Debug("building platform reference values map...")
439484
referenceValues := make(map[string][2]string)
440485
for _, triple := range endorsements {
441-
// set Instance indicates realm endorsements
442-
if triple.Environment.Instance != nil {
443-
continue
444-
}
445-
446486
for _, measurement := range triple.Measurements.Values {
447-
if measurement.Key == nil || !measurement.Key.IsSet() {
448-
return false, false, errors.New("platform reference value measurement missing mkey")
449-
}
450-
451-
if measurement.Key.Type() != comid.StringType {
452-
return false, false, fmt.Errorf(
453-
"platform reference value measurement mkey must be string, got %s",
454-
measurement.Key.Type(),
455-
)
487+
mkey, err := readMeasurementKey(&measurement)
488+
if err != nil {
489+
return false, false, err
456490
}
457491

458-
mkey := measurement.Key.Value.String()
459-
460492
// Check if this is a platform config measurement.
461-
if mkey == cca.CCAPlatformConfigMkey {
462-
493+
switch mkey {
494+
case cca.CCAPlatformConfigMkey:
463495
if measurement.Val.RawValue == nil {
464496
return false, false,
465497
errors.New("no raw value in platform config measurement")
@@ -471,42 +503,30 @@ func matchPlatformClaimsToReferenceValues(
471503
}
472504

473505
continue
474-
}
475-
476-
if mkey != "cca.software-component" {
477-
return false, false, fmt.Errorf(
478-
"invalid mkey %q in platform reference value measurement",
479-
mkey,
480-
)
481-
}
506+
case cca.CCASoftwareComponentMkey:
507+
digest, err := readMeasurementDigestBytes(&measurement)
508+
if err != nil {
509+
return false, false, err
510+
}
482511

483-
// Not a platform-config entry: this must be a platform software component.
484-
if measurement.Val.Digests == nil {
485-
return false, false, errors.New("no digests in reference value measurement")
486-
}
512+
encoded := base64.StdEncoding.EncodeToString(digest)
513+
// Extract label (mtype) and version from measurement value
514+
var label, version string
487515

488-
numDigests := len(*measurement.Val.Digests)
489-
if numDigests != 1 {
490-
return false, false, fmt.Errorf(
491-
"expected exactly 1 digest in measurement; found %d",
492-
numDigests,
493-
)
494-
}
495-
496-
encoded := base64.StdEncoding.EncodeToString((*measurement.Val.Digests)[0].HashValue)
497-
// Extract label (mtype) and version from measurement value
498-
var label, version string
516+
if measurement.Val.Name != nil {
517+
label = *measurement.Val.Name
518+
}
519+
if measurement.Val.Ver != nil {
520+
version = measurement.Val.Ver.Version
521+
}
499522

500-
if measurement.Val.Name != nil {
501-
label = *measurement.Val.Name
523+
referenceValues[encoded] = [2]string{label, version}
524+
default:
525+
logger.Debugw("skipping non-platform measurement", "mkey", mkey)
502526
}
503-
if measurement.Val.Ver != nil {
504-
version = measurement.Val.Ver.Version
505-
}
506-
507-
referenceValues[encoded] = [2]string{label, version}
508527
}
509528
}
529+
logger.Debugw("platform reference values", "map", referenceValues)
510530

511531
evidenceConfigValue, err := claims.GetConfig()
512532
if err != nil {
@@ -539,7 +559,7 @@ func matchPlatformClaimsToReferenceValues(
539559
}
540560

541561
mversion, err := swComp.GetVersion()
542-
if err != nil {
562+
if err != nil && ! errors.Is(err, psatoken.ErrOptionalFieldMissing) {
543563
return false, false, handler.BadEvidence(fmt.Errorf("S/W comp. %d version: %w", i, err))
544564
}
545565

@@ -571,7 +591,7 @@ func allMatch(lhs, rhs [][]byte) bool {
571591
}
572592

573593
for i, lhsV := range lhs {
574-
if !bytes.Equal(lhsV, rhs[i]) {
594+
if len(lhsV) > 0 && !bytes.Equal(lhsV, rhs[i]) {
575595
return false
576596
}
577597
}

0 commit comments

Comments
 (0)