diff --git a/headers.go b/headers.go index 1daaaaa..2999207 100644 --- a/headers.go +++ b/headers.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "math/big" + "strings" "github.com/fxamacker/cbor/v2" ) @@ -471,9 +472,24 @@ func validateHeaderParameters(h map[any]any, protected bool) error { return fmt.Errorf("header parameter: crit: %w", err) } case HeaderLabelContentType: - if !canTstr(value) && !canUint(value) { + is_tstr := canTstr(value) + if !is_tstr && !canUint(value) { return errors.New("header parameter: content type: require tstr / uint type") } + if is_tstr { + v := value.(string) + if len(v) == 0 { + return errors.New("header parameter: content type: require non-empty string") + } + if v[0] == ' ' || v[len(v)-1] == ' ' { + return errors.New("header parameter: content type: require no leading/trailing whitespace") + } + // Basic check that the content type is of form type/subtype. + // We don't check the precise definition though (RFC 6838 Section 4.2). + if strings.Count(v, "/") != 1 { + return errors.New("header parameter: content type: require text of form type/subtype") + } + } case HeaderLabelKeyID: if !canBstr(value) { return errors.New("header parameter: kid: require bstr type") diff --git a/headers_test.go b/headers_test.go index fcac4a4..efb11f9 100644 --- a/headers_test.go +++ b/headers_test.go @@ -210,6 +210,41 @@ func TestProtectedHeader_MarshalCBOR(t *testing.T) { }, wantErr: "protected header: header parameter: Countersignature version 2: not allowed", }, + { + name: "content type empty", + h: ProtectedHeader{ + HeaderLabelContentType: "", + }, + wantErr: "protected header: header parameter: content type: require non-empty string", + }, + { + name: "content type leading space", + h: ProtectedHeader{ + HeaderLabelContentType: " a/b", + }, + wantErr: "protected header: header parameter: content type: require no leading/trailing whitespace", + }, + { + name: "content type trailing space", + h: ProtectedHeader{ + HeaderLabelContentType: "a/b ", + }, + wantErr: "protected header: header parameter: content type: require no leading/trailing whitespace", + }, + { + name: "content type no slash", + h: ProtectedHeader{ + HeaderLabelContentType: "ab", + }, + wantErr: "protected header: header parameter: content type: require text of form type/subtype", + }, + { + name: "content type too many slashes", + h: ProtectedHeader{ + HeaderLabelContentType: "a/b/c", + }, + wantErr: "protected header: header parameter: content type: require text of form type/subtype", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {