Skip to content

Commit 627ddb3

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 627ddb3

3 files changed

Lines changed: 116 additions & 91 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: 112 additions & 87 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,71 @@ 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)
356+
}
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)
362+
}
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+
if measurement.Val.RawValue == nil {
372+
return fmt.Errorf("raw-value not set for %s",
373+
cca.CCARealmPersonalizationMkey)
356374
}
357375

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
376+
refVal.PersonalizationValue, err = measurement.Val.RawValue.GetBytes()
377+
if err != nil {
378+
return fmt.Errorf("%s: %w", cca.CCARealmPersonalizationMkey, err)
368379
}
380+
default:
381+
logger.Debugw("skipping non-realm measurement", "mkey", mkey)
369382
}
370383

384+
}
385+
386+
if refVal.InitialMeasurement != nil {
371387
referenceValues = append(referenceValues, refVal)
372388
}
373389
}
390+
logger.Debug("collected realm reference values", "values", referenceValues)
374391

375392
for _, refVal := range referenceValues {
376393
if !bytes.Equal(refVal.InitialMeasurement, evidenceRIM) {
@@ -428,6 +445,38 @@ func convertToPlatformClaims(v any) (platform.IClaims, error) {
428445
return platform.DecodeClaimsFromJSON(encoded)
429446
}
430447

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

488+
logger.Debug("building platform reference values map...")
439489
referenceValues := make(map[string][2]string)
440490
for _, triple := range endorsements {
441-
// set Instance indicates realm endorsements
442-
if triple.Environment.Instance != nil {
443-
continue
444-
}
445-
446491
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")
492+
mkey, err := readMeasurementKey(&measurement)
493+
if err != nil {
494+
return false, false, err
449495
}
450496

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-
)
456-
}
457-
458-
mkey := measurement.Key.Value.String()
459-
460497
// Check if this is a platform config measurement.
461-
if mkey == cca.CCAPlatformConfigMkey {
462-
498+
switch mkey {
499+
case cca.CCAPlatformConfigMkey:
463500
if measurement.Val.RawValue == nil {
464501
return false, false,
465502
errors.New("no raw value in platform config measurement")
@@ -471,42 +508,30 @@ func matchPlatformClaimsToReferenceValues(
471508
}
472509

473510
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-
}
482-
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-
}
511+
case cca.CCASoftwareComponentMkey:
512+
digest, err := readMeasurementDigestBytes(&measurement)
513+
if err != nil {
514+
return false, false, err
515+
}
487516

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-
}
517+
encoded := base64.StdEncoding.EncodeToString(digest)
518+
// Extract label (mtype) and version from measurement value
519+
var label, version string
495520

496-
encoded := base64.StdEncoding.EncodeToString((*measurement.Val.Digests)[0].HashValue)
497-
// Extract label (mtype) and version from measurement value
498-
var label, version string
521+
if measurement.Val.Name != nil {
522+
label = *measurement.Val.Name
523+
}
524+
if measurement.Val.Ver != nil {
525+
version = measurement.Val.Ver.Version
526+
}
499527

500-
if measurement.Val.Name != nil {
501-
label = *measurement.Val.Name
528+
referenceValues[encoded] = [2]string{label, version}
529+
default:
530+
logger.Debugw("skipping non-platform measurement", "mkey", mkey)
502531
}
503-
if measurement.Val.Ver != nil {
504-
version = measurement.Val.Ver.Version
505-
}
506-
507-
referenceValues[encoded] = [2]string{label, version}
508532
}
509533
}
534+
logger.Debugw("platform reference values", "map", referenceValues)
510535

511536
evidenceConfigValue, err := claims.GetConfig()
512537
if err != nil {
@@ -539,7 +564,7 @@ func matchPlatformClaimsToReferenceValues(
539564
}
540565

541566
mversion, err := swComp.GetVersion()
542-
if err != nil {
567+
if err != nil && !errors.Is(err, psatoken.ErrOptionalFieldMissing) {
543568
return false, false, handler.BadEvidence(fmt.Errorf("S/W comp. %d version: %w", i, err))
544569
}
545570

@@ -571,7 +596,7 @@ func allMatch(lhs, rhs [][]byte) bool {
571596
}
572597

573598
for i, lhsV := range lhs {
574-
if !bytes.Equal(lhsV, rhs[i]) {
599+
if len(lhsV) > 0 && !bytes.Equal(lhsV, rhs[i]) {
575600
return false
576601
}
577602
}

0 commit comments

Comments
 (0)