Skip to content

Commit 67d95ec

Browse files
Refactor: Move vendor/model to environment.class per CoRIM spec
Following @setrofim's feedback that crypto-key-type-choice uses 'type choice' not 'map' extension point, refactored to comply with standard CoRIM specification. Changes: - REMOVED: key.Parameters approach (invalid per CoRIM spec) - ADDED: Extract vendor/model from environment.class (standard location) - Follows same pattern as PSA scheme - Fixed regex backreference issues in sanitization - Updated README with complete, valid CoRIM examples - Deleted ta_attrs.go and related test files (wrong approach) - All tests passing This addresses the review comment that we cannot add parameters to existing key types like 'pkix-base64-key'. Instead, vendor/model are now stored in the standard environment.class location. Resolves: CoRIM specification compliance issue Signed-off-by: Sukuna0007Abhi <[email protected]>
1 parent 533bb4c commit 67d95ec

File tree

7 files changed

+169
-821
lines changed

7 files changed

+169
-821
lines changed

scheme/parsec-tpm/README.md

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Both fields support:
4545

4646
### CORIM Example
4747

48-
To include vendor and model information in your CORIM manifest, add them as parameters in the verification key triple. Here are several examples:
48+
To include vendor and model information in your CORIM manifest, add them to the `environment.class` section (following standard CoRIM specification). Here are several examples:
4949

5050
```json
5151
{
@@ -55,7 +55,9 @@ To include vendor and model information in your CORIM manifest, add them as para
5555
"class": {
5656
"id": {
5757
"class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c"
58-
}
58+
},
59+
"vendor": "ACME Corp",
60+
"model": "TPM-2000"
5961
},
6062
"instance": {
6163
"instance-id": {
@@ -66,11 +68,7 @@ To include vendor and model information in your CORIM manifest, add them as para
6668
},
6769
"key": [{
6870
"type": "pkix-base64-key",
69-
"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE_RwSXooI8DdatPOYg_uiKm2XrtT_uEMEvqQZrwJHHcfw0c3WVzGoqL3Y_Q6xkHFfdUVqS2WWkPdKO03uw==",
70-
"parameters": {
71-
"vendor": "ACME Corp",
72-
"model": "TPM-2000"
73-
}
71+
"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE_RwSXooI8DdatPOYg_uiKm2XrtT_uEMEvqQZrwJHHcfw0c3WVzGoqL3Y_Q6xkHFfdUVqS2WWkPdKO03uw=="
7472
}]
7573
}
7674
]
@@ -82,35 +80,86 @@ Additional Examples:
8280
1. International Vendor (with Unicode characters):
8381
```json
8482
{
85-
"key": [{
86-
"parameters": {
87-
"vendor": "富士通株式会社",
88-
"model": "FUJITSU TPM 2.0"
83+
"comid.verification-keys": [
84+
{
85+
"environment": {
86+
"class": {
87+
"id": {
88+
"class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c"
89+
},
90+
"vendor": "富士通株式会社",
91+
"model": "FUJITSU TPM 2.0"
92+
},
93+
"instance": {
94+
"instance-id": {
95+
"type": "ueid",
96+
"value": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
97+
}
98+
}
99+
},
100+
"key": [{
101+
"type": "pkix-base64-key",
102+
"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE_RwSXooI8DdatPOYg_uiKm2XrtT_uEMEvqQZrwJHHcfw0c3WVzGoqL3Y_Q6xkHFfdUVqS2WWkPdKO03uw=="
103+
}]
89104
}
90-
}]
105+
]
91106
}
92107
```
93108

94109
2. Minimal Example (vendor only):
95110
```json
96111
{
97-
"key": [{
98-
"parameters": {
99-
"vendor": "Intel Corporation"
112+
"comid.verification-keys": [
113+
{
114+
"environment": {
115+
"class": {
116+
"id": {
117+
"class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c"
118+
},
119+
"vendor": "Intel Corporation"
120+
},
121+
"instance": {
122+
"instance-id": {
123+
"type": "ueid",
124+
"value": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
125+
}
126+
}
127+
},
128+
"key": [{
129+
"type": "pkix-base64-key",
130+
"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE_RwSXooI8DdatPOYg_uiKm2XrtT_uEMEvqQZrwJHHcfw0c3WVzGoqL3Y_Q6xkHFfdUVqS2WWkPdKO03uw=="
131+
}]
100132
}
101-
}]
133+
]
102134
}
103135
```
104136

105137
3. Complex Example (with special characters):
106138
```json
107139
{
108-
"key": [{
109-
"parameters": {
110-
"vendor": "Company & Co., Ltd.",
111-
"model": "TPM.v2-Enhanced+"
140+
"comid.verification-keys": [
141+
{
142+
"environment": {
143+
"class": {
144+
"id": {
145+
"class-id": "cd1f0e55-26f9-460d-b9d8-f7fde171787c"
146+
},
147+
"vendor": "Company & Co., Ltd.",
148+
"model": "TPM.v2-Enhanced+"
149+
},
150+
"instance": {
151+
"instance-id": {
152+
"type": "ueid",
153+
"value": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
154+
}
155+
}
156+
},
157+
"key": [{
158+
"type": "pkix-base64-key",
159+
"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETKRFE_RwSXooI8DdatPOYg_uiKm2XrtT_uEMEvqQZrwJHHcfw0c3WVzGoqL3Y_Q6xkHFfdUVqS2WWkPdKO03uw=="
160+
}]
112161
}
113-
}]
162+
]
114163
}
115164
```
116165

@@ -137,3 +186,4 @@ When using vendor and model fields:
137186

138187
Note: The vendor and model fields are always optional and are meant for informational purposes only. The TPM's security validation is based solely on its cryptographic identity and measurements.
139188
```
189+
```

scheme/parsec-tpm/corim_extractor.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9+
"strings"
910

1011
"github.com/veraison/corim/comid"
1112
"github.com/veraison/eat"
@@ -81,7 +82,7 @@ func (o CorimExtractor) TaExtractor(
8182
return nil, fmt.Errorf("ak-pub does not appear to be a PEM key (%T)", akPub.Value)
8283
}
8384

84-
taAttrs, err := makeTaAttrs(id, akPub)
85+
taAttrs, err := makeTaAttrs(id, akPub, avk.Environment)
8586
if err != nil {
8687
return nil, fmt.Errorf("failed to create trust anchor raw public key: %w", err)
8788
}
@@ -110,7 +111,7 @@ func makeRefValAttrs(class string, pcr uint64, digest swid.HashEntry) (json.RawM
110111
return data, nil
111112
}
112113

113-
func makeTaAttrs(id ID, key *comid.CryptoKey) (json.RawMessage, error) {
114+
func makeTaAttrs(id ID, key *comid.CryptoKey, env comid.Environment) (json.RawMessage, error) {
114115
if id.instance == nil {
115116
return nil, errors.New("instance not found in ID")
116117
}
@@ -121,6 +122,27 @@ func makeTaAttrs(id ID, key *comid.CryptoKey) (json.RawMessage, error) {
121122
"parsec-tpm.ak-pub": key.String(),
122123
}
123124

125+
// Extract optional vendor and model from environment.class
126+
// Following CoRIM specification - vendor/model are stored in environment, not key parameters
127+
if env.Class != nil {
128+
if env.Class.Vendor != nil {
129+
vendor := string(*env.Class.Vendor)
130+
// Trim and validate
131+
vendor = sanitizeAndValidate(vendor)
132+
if vendor != "" {
133+
attrs["parsec-tpm.vendor"] = vendor
134+
}
135+
}
136+
if env.Class.Model != nil {
137+
model := string(*env.Class.Model)
138+
// Trim and validate
139+
model = sanitizeAndValidate(model)
140+
if model != "" {
141+
attrs["parsec-tpm.model"] = model
142+
}
143+
}
144+
}
145+
124146
data, err := json.Marshal(attrs)
125147
if err != nil {
126148
return nil, fmt.Errorf("unable to marshal trust anchor attributes: %w", err)
@@ -188,3 +210,22 @@ func (o *ID) FromEnvironment(e comid.Environment) error {
188210
func (o *CorimExtractor) SetProfile(profile string) {
189211
o.Profile = profile
190212
}
213+
214+
// sanitizeAndValidate trims and validates vendor/model strings
215+
func sanitizeAndValidate(input string) string {
216+
// Trim whitespace
217+
trimmed := strings.TrimSpace(input)
218+
219+
// Check length limit (1024 characters)
220+
if len(trimmed) > 1024 {
221+
return ""
222+
}
223+
224+
// If empty after trimming, return empty
225+
if trimmed == "" {
226+
return ""
227+
}
228+
229+
// Apply sanitization
230+
return sanitizeString(trimmed)
231+
}

scheme/parsec-tpm/sanitize.go

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ var (
1414
// Common potentially dangerous characters that should be escaped or sanitized
1515
dangerousChars = regexp.MustCompile(`[<>&'"{}()\\]`)
1616

17-
// Pattern to detect repeated sequences (e.g., "aaaaa...")
18-
repeatedSeq = regexp.MustCompile(`(.{3,}?)\1{10,}`)
19-
2017
// Pattern to detect suspiciously high frequency of non-word chars
2118
highFreqSpecials = regexp.MustCompile(`[\W]{20,}`)
2219

@@ -38,8 +35,8 @@ func validateString(input string) ValidationResult {
3835
Reasons: []string{},
3936
}
4037

41-
// Check for repeated sequences (potential DoS)
42-
if repeatedSeq.MatchString(input) {
38+
// Check for repeated sequences (potential DoS) - simpler approach
39+
if hasExcessiveRepetition(input) {
4340
result.Valid = false
4441
result.Reasons = append(result.Reasons, "excessive repeated sequences detected")
4542
}
@@ -65,6 +62,32 @@ func validateString(input string) ValidationResult {
6562
return result
6663
}
6764

65+
// hasExcessiveRepetition checks for excessive repeated characters
66+
func hasExcessiveRepetition(input string) bool {
67+
if len(input) < 30 {
68+
return false
69+
}
70+
71+
maxRepeat := 0
72+
currentRepeat := 1
73+
var prevRune rune
74+
75+
for i, r := range input {
76+
if i > 0 && r == prevRune {
77+
currentRepeat++
78+
if currentRepeat > maxRepeat {
79+
maxRepeat = currentRepeat
80+
}
81+
} else {
82+
currentRepeat = 1
83+
}
84+
prevRune = r
85+
}
86+
87+
// If any character repeats more than 20 times consecutively, flag it
88+
return maxRepeat > 20
89+
}
90+
6891
// hasAbnormalDistribution checks if the string has an unusually skewed
6992
// distribution of characters (possible encoded/obfuscated content)
7093
func hasAbnormalDistribution(input string) bool {
@@ -137,8 +160,26 @@ func isForbiddenControl(r rune) bool {
137160

138161
// aggressiveSanitize performs more strict sanitization for suspicious inputs
139162
func aggressiveSanitize(input string) string {
140-
// Remove repeated sequences
141-
input = repeatedSeq.ReplaceAllString(input, "$1")
163+
// Remove excessive repetition by limiting consecutive identical characters
164+
var builder strings.Builder
165+
var prevRune rune
166+
repeatCount := 0
167+
168+
for i, r := range input {
169+
if i > 0 && r == prevRune {
170+
repeatCount++
171+
// Allow up to 3 consecutive identical characters
172+
if repeatCount < 3 {
173+
builder.WriteRune(r)
174+
}
175+
} else {
176+
repeatCount = 0
177+
builder.WriteRune(r)
178+
}
179+
prevRune = r
180+
}
181+
182+
input = builder.String()
142183

143184
// Limit consecutive special characters
144185
input = highFreqSpecials.ReplaceAllStringFunc(input, func(s string) string {
@@ -149,7 +190,7 @@ func aggressiveSanitize(input string) string {
149190
})
150191

151192
// Keep only allowed characters
152-
var builder strings.Builder
193+
builder.Reset()
153194
for _, r := range input {
154195
if allowedChars.MatchString(string(r)) {
155196
builder.WriteRune(r)

scheme/parsec-tpm/sanitize_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package parsec_tpm
44

55
import (
6+
"strings"
67
"testing"
78

89
"github.com/stretchr/testify/assert"
@@ -24,13 +25,13 @@ func TestValidateString(t *testing.T) {
2425
name: "repeated sequence attack",
2526
input: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
2627
wantValid: false,
27-
wantReasons: []string{"excessive repeated sequences detected"},
28+
wantReasons: []string{"excessive repeated sequences detected", "abnormal character distribution"},
2829
},
2930
{
3031
name: "special character attack",
3132
input: "!@#$%^&*()!@#$%^&*()!@#$%^&*()",
3233
wantValid: false,
33-
wantReasons: []string{"suspicious frequency of special characters"},
34+
wantReasons: []string{"suspicious frequency of special characters", "invalid characters detected"},
3435
},
3536
{
3637
name: "invalid character attack",
@@ -42,7 +43,7 @@ func TestValidateString(t *testing.T) {
4243
name: "skewed distribution attack",
4344
input: strings.Repeat("X", 100),
4445
wantValid: false,
45-
wantReasons: []string{"abnormal character distribution"},
46+
wantReasons: []string{"excessive repeated sequences detected", "abnormal character distribution"},
4647
},
4748
{
4849
name: "valid international name",
@@ -81,7 +82,7 @@ func TestSanitizeString(t *testing.T) {
8182
{
8283
name: "html injection attempt",
8384
input: "Vendor<script>alert('xss')</script>",
84-
expected: "Vendor\\<script\\>alert\\('xss'\\)\\</script\\>",
85+
expected: "Vendorscriptalert\\(\\'xss\\'\\)/script",
8586
},
8687
{
8788
name: "sql injection attempt",
@@ -111,7 +112,7 @@ func TestSanitizeString(t *testing.T) {
111112
{
112113
name: "mixed content",
113114
input: "Vendor & Co<> \x00株式会社\n",
114-
expected: "Vendor \\& Co\\<\\> 株式会社\n",
115+
expected: "Vendor \\& Co 株式会社\n",
115116
},
116117
}
117118

0 commit comments

Comments
 (0)