Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: draft-ffm-rats-cca-token-00 support #32

Merged
merged 2 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions evidence.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
Expand All @@ -18,6 +19,7 @@
"github.com/veraison/ccatoken/platform"
"github.com/veraison/ccatoken/realm"
cose "github.com/veraison/go-cose"
"github.com/veraison/psatoken"
)

// CBORCollection is a wrapper containing the CBOR data for both platform and
Expand Down Expand Up @@ -299,9 +301,24 @@
return fmt.Errorf("extracting RAK from the realm token: %w", err)
}

rak, err := ecdsaPublicKeyFromRaw(rawRAK)
var rak *ecdsa.PublicKey

_, err = e.RealmClaims.GetProfile()
if err != nil {
return fmt.Errorf("decoding RAK: %w", err)
switch err {
case psatoken.ErrOptionalClaimMissing:
rak, err = realm.ECDSAPublicKeyFromRaw(rawRAK)
if err != nil {
return fmt.Errorf("decoding RAK: %w", err)
}
default:
return fmt.Errorf("extracting realm profile: %w", err)
}
} else {
rak, err = realm.ECDSAPublicKeyFromCOSEKey(rawRAK)
if err != nil {
return fmt.Errorf("decoding RAK: %w", err)
}
}

// Next verify the realm token
Expand Down Expand Up @@ -347,7 +364,7 @@
return &pubKey
}

func (e *Evidence) doUnmarshalJSON(data []byte) (platform.IClaims, realm.IClaims, error) {

Check failure on line 367 in evidence.go

View workflow job for this annotation

GitHub Actions / Lint

unnamedResult: consider giving a name to these results (gocritic)

Check failure on line 367 in evidence.go

View workflow job for this annotation

GitHub Actions / Lint

unnamedResult: consider giving a name to these results (gocritic)
var c map[string]json.RawMessage
var err error

Expand Down
48 changes: 42 additions & 6 deletions evidence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
err = c.SetHashAlgID(testHashAlgID)
require.NoError(t, err)

err = c.SetPubKey(testRAKPubRaw)
err = c.SetPubKey(testRAKPubCOSE)
require.NoError(t, err)

err = c.SetPubKeyHashAlgID(testPubKeyHashAlgID)
Expand Down Expand Up @@ -164,7 +164,7 @@

// now set a different key from the one which is going to be used for
// signing
err = EvidenceIn.RealmClaims.SetPubKey(testAltRAKPubRaw)
err = EvidenceIn.RealmClaims.SetPubKey(realm.TestAltRAKPubCOSE)
assert.NoError(t, err)

ccaToken, err := EvidenceIn.ValidateAndSign(pSigner, rSigner)
Expand Down Expand Up @@ -260,7 +260,7 @@
)
require.NoError(t, err)

expected := &testRAKPubRaw
expected := &testRAKPubCOSE

actual := e.GetRealmPublicKey()
assert.Equal(t, expected, actual)
Expand Down Expand Up @@ -428,7 +428,7 @@
incompleteRealmClaims := &realm.Claims{}

// just set the bare minimum to compute the binder
err := incompleteRealmClaims.SetPubKey(testRAKPubRaw)
err := incompleteRealmClaims.SetPubKey(realm.TestRAKPubRaw)
require.NoError(t, err)

err = incompleteRealmClaims.SetPubKeyHashAlgID("sha-256")
Expand Down Expand Up @@ -485,8 +485,10 @@
assert.EqualError(t, err, "no message found")
}

func TestEvidence_Verify_RMM(t *testing.T) {
b := mustHexDecode(t, testRMMEvidence)
func TestEvidence_Verify_RMM_Legacy(t *testing.T) {
b := mustHexDecode(t, testRMMLegacyEvidence)

fmt.Printf("%x\n", b)

e, err := DecodeAndValidateEvidenceFromCBOR(b)
require.NoError(t, err)
Expand Down Expand Up @@ -572,3 +574,37 @@
assert.Contains(t, err.Error(), "realm challenge claim: wrong syntax")

}

func Test_UnmarshalCBOR_InvalidEntries_MissingSign1Tag(t *testing.T) {
tv := []byte{
0xd9, 0x01, 0x8f, // tag(399)
0xa2, // map(2)
0x19, 0xac, 0xca, // unsigned(44234)

Check failure on line 582 in evidence_test.go

View workflow job for this annotation

GitHub Actions / Lint

commentedOutCode: may want to remove commented-out code (gocritic)

Check failure on line 582 in evidence_test.go

View workflow job for this annotation

GitHub Actions / Lint

commentedOutCode: may want to remove commented-out code (gocritic)
0x42, // bytes(2)
0xde, 0xad, // h'dead'
0x19, 0xac, 0xd1, // unsigned(44241)

Check failure on line 585 in evidence_test.go

View workflow job for this annotation

GitHub Actions / Lint

commentedOutCode: may want to remove commented-out code (gocritic)

Check failure on line 585 in evidence_test.go

View workflow job for this annotation

GitHub Actions / Lint

commentedOutCode: may want to remove commented-out code (gocritic)
0x42, // bytes(2)
0xbe, 0xef, // h'beef'
}
e := Evidence{}
err := e.UnmarshalCBOR(tv)
assert.ErrorContains(t, err, "decoding of CCA evidence failed")
}

func Test_UnmarshalCBOR_InvalidEntries_EmptySign1(t *testing.T) {
tv := []byte{
0xd9, 0x01, 0x8f,
0xa2,
0x19, 0xac, 0xca,
0x4e,
// invalid platform token
0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x22, 0xa0, 0x42, 0xde, 0xad, 0x42, 0xbe, 0xef,
0x19, 0xac, 0xd1,
0x4e,
// invalid realm token
0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x22, 0xa0, 0x42, 0xde, 0xad, 0x42, 0xbe, 0xef,
}
e := Evidence{}
err := e.UnmarshalCBOR(tv)
assert.ErrorContains(t, err, "decoding of CCA evidence failed")
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/lestrrat-go/jwx/v2 v2.0.8
github.com/stretchr/testify v1.8.1
github.com/veraison/eat v0.0.0-20220117140849-ddaf59d69f53
github.com/veraison/go-cose v1.1.0
github.com/veraison/go-cose v1.2.1
github.com/veraison/psatoken v1.2.1-0.20240719122628-26fe500fd5d4
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/veraison/eat v0.0.0-20220117140849-ddaf59d69f53 h1:5gnX2TrGd/Xz8DOp2OaLtg/jLoIubSUTrgz6iZ58pJ4=
github.com/veraison/eat v0.0.0-20220117140849-ddaf59d69f53/go.mod h1:+kxt8iuFiVvKRs2VQ1Ho7bbAScXAB/kHFFuP5Biw19I=
github.com/veraison/go-cose v1.1.0 h1:AalPS4VGiKavpAzIlBjrn7bhqXiXi4jbMYY/2+UC+4o=
github.com/veraison/go-cose v1.1.0/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4=
github.com/veraison/go-cose v1.2.1 h1:Gj4x20D0YP79J2+cK3anjGEMwIkg2xX+TKVVGUXwNAc=
github.com/veraison/go-cose v1.2.1/go.mod h1:t6V8WJzHm1PD5HNsuDjW3KLv577uWb6UTzbZGvdQHD8=
github.com/veraison/psatoken v1.2.1-0.20240719122628-26fe500fd5d4 h1:N7qg7vDF2mUg7I+8AoU+ieJ20cgcShwFHXHkV5b2YAA=
github.com/veraison/psatoken v1.2.1-0.20240719122628-26fe500fd5d4/go.mod h1:6+WZzXr0ACXYiUAJJqTaCxW43gY2+gEaCoVNdDv3+Bw=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
Expand Down
31 changes: 27 additions & 4 deletions platform/claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"github.com/veraison/psatoken"
)

const ProfileName = "http://arm.com/CCA-SSD/1.0.0"
const LegacyProfileName = "http://arm.com/CCA-SSD/1.0.0"
const ProfileName = "tag:arm.com,2023:cca_platform#1.0.0"

// Profile is the psatoken.IProfile implementation for CCA claims. It is
// registered to associate the claims with the profile name, so that it can be
Expand All @@ -26,6 +27,16 @@
return NewClaims()
}

type LegacyProfile struct{}

func (o LegacyProfile) GetName() string {
return LegacyProfileName
}

func (o LegacyProfile) GetClaims() psatoken.IClaims {
return NewLegacyClaims()
}

// Claims contains the CCA platform claims. It implements IClaims, which is an
// extension of psatoken.IClaims.
type Claims struct {
Expand All @@ -45,16 +56,24 @@

// NewClaims claims returns a new instance of Claims.
func NewClaims() IClaims {
return newClaims(ProfileName)
}

func NewLegacyClaims() IClaims {
return newClaims(LegacyProfileName)
}

func newClaims(profileName string) IClaims {
p := eat.Profile{}
if err := p.Set(ProfileName); err != nil {
if err := p.Set(profileName); err != nil {
// should never get here as using known good constant as input
panic(err)
}

return &Claims{
Profile: &p,
SwComponents: &psatoken.SwComponents[*psatoken.SwComponent]{},
CanonicalProfile: ProfileName,
CanonicalProfile: profileName,
}
}

Expand All @@ -76,7 +95,7 @@
}

// UnmarshalCBOR decodes the claims from CBOR
func (c Claims) MarshalCBOR() ([]byte, error) {

Check failure on line 98 in platform/claims.go

View workflow job for this annotation

GitHub Actions / Lint

hugeParam: c is heavy (96 bytes); consider passing it by pointer (gocritic)

Check failure on line 98 in platform/claims.go

View workflow job for this annotation

GitHub Actions / Lint

hugeParam: c is heavy (96 bytes); consider passing it by pointer (gocritic)
if c.SwComponents != nil && c.SwComponents.IsEmpty() {
c.SwComponents = nil
}
Expand All @@ -92,7 +111,7 @@
}

// MarshalJSON encodes the claims into JSON
func (c Claims) MarsahlJSON() ([]byte, error) {

Check failure on line 114 in platform/claims.go

View workflow job for this annotation

GitHub Actions / Lint

hugeParam: c is heavy (96 bytes); consider passing it by pointer (gocritic)

Check failure on line 114 in platform/claims.go

View workflow job for this annotation

GitHub Actions / Lint

hugeParam: c is heavy (96 bytes); consider passing it by pointer (gocritic)
if c.SwComponents != nil && c.SwComponents.IsEmpty() {
c.SwComponents = nil
}
Expand Down Expand Up @@ -217,7 +236,7 @@
psatoken.ErrWrongProfile, c.CanonicalProfile, profileString)
}

return c.Profile.Get()
return profileString, nil
}

func (c *Claims) GetClientID() (int32, error) {
Expand Down Expand Up @@ -336,4 +355,8 @@
if err := psatoken.RegisterProfile(Profile{}); err != nil {
panic(err)
}

if err := psatoken.RegisterProfile(LegacyProfile{}); err != nil {
panic(err)
}
}
17 changes: 7 additions & 10 deletions platform/claims_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ func Test_CCAPlatform_UnmarshalCBOR_ok_mandatory_only(t *testing.T) {
actualSwComp, err := c.GetSoftwareComponents()
assert.NoError(t, err)
assert.Equal(t, expectedSwComp, actualSwComp)

}

func Test_CCAPlatform_Claims_UnmarshalCBOR_bad_input(t *testing.T) {
Expand Down Expand Up @@ -216,7 +215,7 @@ func Test_CCAPlatform_MarshalJSON_ok(t *testing.T) {
c := mustBuildValidClaims(t, true)

expected := `{
"cca-platform-profile": "http://arm.com/CCA-SSD/1.0.0",
"cca-platform-profile": "tag:arm.com,2023:cca_platform#1.0.0",
"cca-platform-challenge": "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=",
"cca-platform-implementation-id":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"cca-platform-instance-id": "AQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC",
Expand Down Expand Up @@ -294,6 +293,7 @@ func Test_CCAPlatform_UnmarshalJSON_negatives(t *testing.T) {
/* 12 */ "testvectors/json/test-instance-id-invalid.json",
/* 13 */ "testvectors/json/test-config-missing.json",
/* 14 */ "testvectors/json/test-hash-algid-missing.json",
/* 15 */ "testvectors/json/test-invalid-psa-claims.json",
}

for i, fn := range tvs {
Expand All @@ -309,18 +309,16 @@ func Test_CCAPlatform_UnmarshalJSON_negatives(t *testing.T) {
func Test_DecodeClaims_CCAPlatform_ok(t *testing.T) {
tvs := []string{
testEncodedCcaPlatformClaimsAll,
testEncodedCcaPlatformLegacyClaimsAll,
testEncodedCcaPlatformClaimsMandatoryOnly,
testEncodedCcaPlatformLegacyClaimsMandatoryOnly,
}

for _, tv := range tvs {
buf := mustHexDecode(t, tv)
c, err := DecodeAndValidateClaimsFromCBOR(buf)

assert.NoError(t, err)
_, err := DecodeAndValidateClaimsFromCBOR(buf)

actualProfile, err := c.GetProfile()
assert.NoError(t, err)
assert.Equal(t, ProfileName, actualProfile)
}
}

Expand Down Expand Up @@ -374,7 +372,7 @@ func Test_DecodeJSONClaims_CcaPlatform(t *testing.T) {
assert.NoError(t, err)
actualProfile, err := c.GetProfile()
assert.NoError(t, err)
assert.Equal(t, ProfileName, actualProfile)
assert.Equal(t, LegacyProfileName, actualProfile)
}

func Test_DecodeUnvalidatedJSONCCAClaims(t *testing.T) {
Expand All @@ -388,7 +386,6 @@ func Test_DecodeUnvalidatedJSONCCAClaims(t *testing.T) {

// invalid
{"testvectors/json/test-no-sw-components.json", &Claims{}},
{"testvectors/json/test-invalid-profile.json", &Claims{}},
{"testvectors/json/test-invalid-psa-claims.json", &Claims{}},
}

Expand All @@ -398,7 +395,7 @@ func Test_DecodeUnvalidatedJSONCCAClaims(t *testing.T) {

v, err := DecodeClaimsFromJSON(buf)

assert.NoError(t, err)
require.NoError(t, err)
assert.IsType(t, tv.Expected, v)
}
}
Expand Down
25 changes: 17 additions & 8 deletions platform/iclaims.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package platform

import (
"encoding/json"
"errors"
"fmt"

"github.com/veraison/psatoken"
Expand Down Expand Up @@ -56,13 +57,17 @@ func DecodeAndValidateClaimsFromCBOR(buf []byte) (IClaims, error) {

// DecodeClaimsFromCBOR unmarshals CCA platform claims from provided CBOR buf.
func DecodeClaimsFromCBOR(buf []byte) (IClaims, error) {
cl := NewClaims()

if err := dm.Unmarshal(buf, cl); err != nil {
i, err := psatoken.DecodeClaimsFromCBOR(buf)
if err != nil {
return nil, err
}

return cl, nil
ic, ok := i.(IClaims)
if !ok {
return nil, errors.New("not a CCA platform token")
}

return ic, nil
}

// DecodeAndValidateClaimsFromJSON unmarshals and validates CCA platform claims
Expand All @@ -82,13 +87,17 @@ func DecodeAndValidateClaimsFromJSON(buf []byte) (IClaims, error) {

// DecodeClaimsFromJSON unmarshals CCA platform claims from provided JSON buf.
func DecodeClaimsFromJSON(buf []byte) (IClaims, error) {
cl := NewClaims()

if err := json.Unmarshal(buf, cl); err != nil {
i, err := psatoken.DecodeClaimsFromJSON(buf)
if err != nil {
return nil, err
}

return cl, nil
ic, ok := i.(IClaims)
if !ok {
return nil, errors.New("not a (JSON-encoded) CCA platform token")
}

return ic, nil
}

// ValidateAndEncodeClaimsToCBOR validates and then marshals CCA platform claims
Expand Down
Loading
Loading