Skip to content
Open
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
1 change: 1 addition & 0 deletions comid/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
ExtCondEndorseSeriesValueFlags extensions.Point = "CondEndorseSeriesValueFlags"
ExtMval extensions.Point = "Mval"
ExtFlags extensions.Point = "Flags"
ExtPSASwRelTriples extensions.Point = "PSASwRelTriples"
)

type IComidConstrainer interface {
Expand Down
169 changes: 169 additions & 0 deletions comid/psa/example_psa_profile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright 2025 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package psa

import (
"fmt"

"github.com/veraison/corim/comid"
"github.com/veraison/eat"
)

// Example demonstrates the PSA profile functionality
// according to draft-fdb-rats-psa-endorsements-08
func Example() {
// The PSA profile should be automatically registered via init()
profileID, err := eat.NewProfile(PSAProfileURI)
if err != nil {
panic(err)
}

profileURI, err := profileID.Get()
if err != nil {
panic(err)
}

fmt.Printf("PSA Profile ID: %s\n", profileURI)
fmt.Println("PSA Profile registered successfully")

// Output:
// PSA Profile ID: tag:arm.com,2025:psa#1.0.0
// PSA Profile registered successfully
}

// ExamplePSASwComponentMeasurementValues demonstrates PSA software component validation
func ExamplePSASwComponentMeasurementValues() {
// Create a valid PSA software component measurement
values := PSASwComponentMeasurementValues{
Digests: []PSADigest{
{
Algorithm: "sha-256",
Value: make([]byte, 32), // 32-byte digest
},
},
CryptoKeys: [][]byte{make([]byte, 32)}, // 32-byte signer ID
}

err := values.Valid()
if err != nil {
panic(err)
}

fmt.Println("PSA software component measurement is valid")

// Output:
// PSA software component measurement is valid
}

// ExamplePSASoftwareComponentKeyType demonstrates using PSA software component keys
func ExamplePSASoftwareComponentKeyType() {
// Create a PSA software component key
key, err := comid.NewMkey(PSASoftwareComponentType, PSASoftwareComponentType)
if err != nil {
panic(err)
}

fmt.Printf("PSA software component key type: %s\n", key.Value.Type())

// Output:
// PSA software component key type: psa.software-component
}

// ExamplePSASwRelationship demonstrates PSA software relationships
func ExamplePSASwRelationship() {
// Create simple measurements using uint keys
oldMeasurement, err := comid.NewUintMeasurement(uint64(1))
if err != nil {
panic(err)
}

newMeasurement, err := comid.NewUintMeasurement(uint64(2))
if err != nil {
panic(err)
}

// Create update relationship
updateRel, err := NewPSAUpdateRelationship(newMeasurement, oldMeasurement, true)
if err != nil {
panic(err)
}

err = updateRel.Valid()
if err != nil {
panic(err)
}

fmt.Printf("PSA update relationship type: %d\n", updateRel.Relation.Type)
fmt.Printf("Security critical: %t\n", updateRel.Relation.SecurityCritical)

// Output:
// PSA update relationship type: 1
// Security critical: true
}

// ExamplePSACertNumType demonstrates PSA certificate number validation
func ExamplePSACertNumType() {
// Create a valid PSA certificate number
certNum := PSACertNumType("1234567890123 - 56789")

err := certNum.Valid()
if err != nil {
panic(err)
}

fmt.Printf("PSA certificate number is valid: %s\n", string(certNum))

// Output:
// PSA certificate number is valid: 1234567890123 - 56789
}

// ExamplePSASwRelTriples demonstrates PSA software relationship triples
func ExamplePSASwRelTriples() {
// Create simple measurements using uint keys
oldMeasurement, err := comid.NewUintMeasurement(uint64(1))
if err != nil {
panic(err)
}

newMeasurement, err := comid.NewUintMeasurement(uint64(2))
if err != nil {
panic(err)
}

// Create patch relationship
patchRel, err := NewPSAPatchRelationship(newMeasurement, oldMeasurement, false)
if err != nil {
panic(err)
}

// Create environment with minimal content
vendor := "PSA Example Vendor"
env := comid.Environment{
Class: &comid.Class{
Vendor: &vendor,
},
}

// Create triple
triple := PSASwRelTriple{
Environment: env,
Relationship: patchRel,
}

// Create triples collection
triples := NewPSASwRelTriples()
triples.Add(triple)

err = triples.Valid()
if err != nil {
panic(err)
}

fmt.Printf("PSA software relationship triples count: %d\n", len(triples.Values))
fmt.Printf("Relationship type: %d (patches)\n", triples.Values[0].Relationship.Relation.Type)

// Output:
// PSA software relationship triples count: 1
// Relationship type: 2 (patches)
}
60 changes: 60 additions & 0 deletions comid/psa/psa_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2025 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package psa

import (
"fmt"

"github.com/veraison/corim/comid"
"github.com/veraison/corim/corim"
"github.com/veraison/corim/extensions"
"github.com/veraison/eat"
)

var ProfileID *eat.Profile

// PSAProfile defines the PSA endorsements profile as specified in
// draft-fdb-rats-psa-endorsements-08
const PSAProfileURI = "tag:arm.com,2025:psa#1.0.0"

// PSA certification number key for measurement values map extension
const PSACertNumKey = 100

// PSA software component key CBOR tag
const PSASoftwareComponentKeyTag = 800

// PSA software relations triple key
const PSASoftwareRelationsKey = 50

// PSACertNum represents a PSA Certified Security Assurance Certificate number
type PSACertNum struct {
CertNumber string `cbor:"100,keyasint" json:"psa-cert-num"`
}

// Registering the PSA profile inside init() ensures that the profile will
// always be available and you don't need to remember to register it when
// you want to use it.
func init() {
var err error
ProfileID, err = eat.NewProfile(PSAProfileURI)
if err != nil {
panic(err) // will not error, as the profile URI is valid
}

// Create extensions map for PSA profile
extMap := extensions.NewMap().
Add(comid.ExtMval, &PSACertNum{}).
Add(comid.ExtPSASwRelTriples, &PSASwRelTriples{})

if err := corim.RegisterProfile(ProfileID, extMap); err != nil {
// will not error, assuming our profile ID is unique and we've
// correctly set up the extensions Map above
panic(err)
}

// Register PSA measurement key types
if err := comid.RegisterMkeyType(PSASoftwareComponentKeyTag, newMkeyPSASoftwareComponent); err != nil {
panic(fmt.Sprintf("failed to register PSA software component key type: %v", err))
}
}
Loading