458 lines
14 KiB
Go
Vendored
458 lines
14 KiB
Go
Vendored
package metadata
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestPayloadJSON_Parse(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have PayloadJSON
|
|
err string
|
|
}{
|
|
{
|
|
name: "ShouldFailInvalidNextUpdate",
|
|
have: PayloadJSON{
|
|
NextUpdate: "not-a-date",
|
|
},
|
|
err: "error occurred parsing next update value 'not-a-date': parsing time \"not-a-date\" as \"2006-01-02\": cannot parse \"not-a-date\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidEntry",
|
|
have: PayloadJSON{
|
|
NextUpdate: "2025-01-01",
|
|
Entries: []EntryJSON{
|
|
{
|
|
TimeOfLastStatusChange: "not-a-date",
|
|
},
|
|
},
|
|
},
|
|
err: "error occurred parsing entry 0: error occurred parsing metadata entry with AAGUID '': error occurred parsing time of last status change value: parsing time \"not-a-date\" as \"2006-01-02\": cannot parse \"not-a-date\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldSucceedEmptyEntries",
|
|
have: PayloadJSON{
|
|
NextUpdate: "2025-01-01",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.have.Parse()
|
|
|
|
if tc.err == "" {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEntryJSON_Parse(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have EntryJSON
|
|
err string
|
|
}{
|
|
{
|
|
name: "ShouldFailInvalidAAGUID",
|
|
have: EntryJSON{
|
|
AaGUID: "not-a-uuid",
|
|
TimeOfLastStatusChange: "2025-01-01",
|
|
},
|
|
err: "error occurred parsing metadata entry with AAGUID 'not-a-uuid': error parsing AAGUID: invalid UUID length: 10",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidTimeOfLastStatusChange",
|
|
have: EntryJSON{
|
|
TimeOfLastStatusChange: "not-a-date",
|
|
},
|
|
err: "error occurred parsing metadata entry with AAGUID '': error occurred parsing time of last status change value: parsing time \"not-a-date\" as \"2006-01-02\": cannot parse \"not-a-date\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidBiometricStatusReport",
|
|
have: EntryJSON{
|
|
TimeOfLastStatusChange: "2025-01-01",
|
|
BiometricStatusReports: []BiometricStatusReportJSON{
|
|
{
|
|
EffectiveDate: "bad",
|
|
},
|
|
},
|
|
},
|
|
err: "error occurred parsing metadata entry with AAGUID '': error occurred parsing biometric status report 0: error occurred parsing effective date value: parsing time \"bad\" as \"2006-01-02\": cannot parse \"bad\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidStatusReport",
|
|
have: EntryJSON{
|
|
TimeOfLastStatusChange: "2025-01-01",
|
|
StatusReports: []StatusReportJSON{
|
|
{
|
|
EffectiveDate: "bad",
|
|
},
|
|
},
|
|
},
|
|
err: "error occurred parsing metadata entry with AAGUID '': error occurred parsing status report 0: error occurred parsing effective date value: parsing time \"bad\" as \"2006-01-02\": cannot parse \"bad\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidRogueListURL",
|
|
have: EntryJSON{
|
|
TimeOfLastStatusChange: "2025-01-01",
|
|
StatusReports: []StatusReportJSON{
|
|
{
|
|
EffectiveDate: "2025-01-01",
|
|
},
|
|
},
|
|
RogueListURL: "://bad-url",
|
|
},
|
|
err: "error occurred parsing metadata entry with AAGUID '': error occurred parsing rogue list URL value: parse \"://bad-url\": missing protocol scheme",
|
|
},
|
|
{
|
|
name: "ShouldFailRogueListURLWithoutHash",
|
|
have: EntryJSON{
|
|
TimeOfLastStatusChange: "2025-01-01",
|
|
StatusReports: []StatusReportJSON{
|
|
{
|
|
EffectiveDate: "2025-01-01",
|
|
},
|
|
},
|
|
RogueListURL: "https://example.com/rogues",
|
|
},
|
|
err: "error occurred parsing metadata entry with AAGUID '': error occurred validating rogue list URL value: the rogue list hash was absent",
|
|
},
|
|
{
|
|
name: "ShouldSucceedMinimal",
|
|
have: EntryJSON{
|
|
TimeOfLastStatusChange: "2025-01-01",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.have.Parse()
|
|
|
|
if tc.err == "" {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStatementJSON_Parse(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have StatementJSON
|
|
err string
|
|
}{
|
|
{
|
|
name: "ShouldFailInvalidAAGUID",
|
|
have: StatementJSON{
|
|
AaGUID: "not-a-uuid",
|
|
Description: "test",
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing AAGUID value: invalid UUID length: 10",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidAttestationRootCertificate",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
AttestationRootCertificates: []string{"not-base64-cert"},
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing attestation root certificate 0 value: error occurred parsing *x509.certificate: error occurred decoding base64 data: illegal base64 data at input byte 3",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidIcon",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
Icon: "://bad",
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing icon value: parse \"://bad\": missing protocol scheme",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidIconDark",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
IconDark: "://bad",
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing icon dark value: parse \"://bad\": missing protocol scheme",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidProviderLogoLight",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
ProviderLogoLight: "://bad",
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing provider logo light value: parse \"://bad\": missing protocol scheme",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidProviderLogoDark",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
ProviderLogoDark: "://bad",
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing provider logo dark value: parse \"://bad\": missing protocol scheme",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidCxpConfigURL",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
CredentialExportProtocolConfigURL: "://bad",
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing cxp config url value: parse \"://bad\": missing protocol scheme",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidAuthenticatorGetInfo",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
AuthenticatorGetInfo: AuthenticatorGetInfoJSON{
|
|
AaGUID: "not-a-uuid",
|
|
},
|
|
},
|
|
err: "error occurred parsing statement with description 'test': error occurred parsing authenticator get info value: error occurred parsing AAGUID value: invalid UUID length: 10",
|
|
},
|
|
{
|
|
name: "ShouldSucceedMinimal",
|
|
have: StatementJSON{
|
|
Description: "test",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.have.Parse()
|
|
|
|
if tc.err == "" {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBiometricStatusReportJSON_Parse(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have BiometricStatusReportJSON
|
|
err string
|
|
}{
|
|
{
|
|
name: "ShouldFailInvalidEffectiveDate",
|
|
have: BiometricStatusReportJSON{
|
|
EffectiveDate: "not-a-date",
|
|
},
|
|
err: "error occurred parsing effective date value: parsing time \"not-a-date\" as \"2006-01-02\": cannot parse \"not-a-date\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldSucceed",
|
|
have: BiometricStatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
CertLevel: 1,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.have.Parse()
|
|
|
|
if tc.err == "" {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStatusReportJSON_Parse(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have StatusReportJSON
|
|
expected StatusReport
|
|
expectedURL string
|
|
err string
|
|
}{
|
|
{
|
|
name: "ShouldFailInvalidEffectiveDate",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "not-a-date",
|
|
},
|
|
err: "error occurred parsing effective date value: parsing time \"not-a-date\" as \"2006-01-02\": cannot parse \"not-a-date\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidCertificate",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
Certificate: "not-base64",
|
|
},
|
|
err: "error occurred parsing certificate value: error occurred parsing *x509.certificate: error occurred decoding base64 data: illegal base64 data at input byte 3",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidBatchCertificate",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
BatchCertificate: "not-base64",
|
|
},
|
|
err: "error occurred parsing batch certificate value: error occurred parsing *x509.certificate: error occurred decoding base64 data: illegal base64 data at input byte 3",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidSunsetDate",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
SunsetDate: "bad",
|
|
},
|
|
err: "error occurred parsing sunset date value: parsing time \"bad\" as \"2006-01-02\": cannot parse \"bad\" as \"2006\"",
|
|
},
|
|
{
|
|
name: "ShouldFailInvalidURL",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
URL: string([]byte{0x7f}),
|
|
},
|
|
err: "error occurred parsing URL value: parse \"\\x7f\": net/url: invalid control character in URL",
|
|
},
|
|
{
|
|
name: "ShouldSucceedMinimal",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
},
|
|
expected: StatusReport{
|
|
Status: "",
|
|
EffectiveDate: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
},
|
|
{
|
|
name: "ShouldSucceedWithSunsetDate",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
SunsetDate: "2026-06-01",
|
|
},
|
|
expected: StatusReport{
|
|
EffectiveDate: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
SunsetDate: timePtr(time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
{
|
|
name: "ShouldPreserveAllFields",
|
|
have: StatusReportJSON{
|
|
Status: FidoCertifiedL1,
|
|
EffectiveDate: "2025-03-15",
|
|
AuthenticatorVersion: 42,
|
|
URL: "https://example.com/update",
|
|
CertificationDescriptor: "SecurityKey based on CC EAL 5 certified chip",
|
|
CertificateNumber: "FIDO2-CERT-001",
|
|
CertificationPolicyVersion: "1.4.0",
|
|
CertificationProfiles: []string{"consumer", "enterprise"},
|
|
CertificationRequirementsVersion: "1.2.0",
|
|
SunsetDate: "2030-12-31",
|
|
FIPSRevision: 3,
|
|
FIPSPhysicalSecurityLevel: 2,
|
|
},
|
|
expected: StatusReport{
|
|
Status: FidoCertifiedL1,
|
|
EffectiveDate: time.Date(2025, 3, 15, 0, 0, 0, 0, time.UTC),
|
|
AuthenticatorVersion: 42,
|
|
CertificationDescriptor: "SecurityKey based on CC EAL 5 certified chip",
|
|
CertificateNumber: "FIDO2-CERT-001",
|
|
CertificationPolicyVersion: "1.4.0",
|
|
CertificationProfiles: []string{"consumer", "enterprise"},
|
|
CertificationRequirementsVersion: "1.2.0",
|
|
SunsetDate: timePtr(time.Date(2030, 12, 31, 0, 0, 0, 0, time.UTC)),
|
|
FIPSRevision: 3,
|
|
FIPSPhysicalSecurityLevel: 2,
|
|
},
|
|
expectedURL: "https://example.com/update",
|
|
},
|
|
{
|
|
name: "ShouldSucceedURLWithoutScheme",
|
|
have: StatusReportJSON{
|
|
EffectiveDate: "2025-01-01",
|
|
URL: "example.com/update",
|
|
},
|
|
expected: StatusReport{
|
|
EffectiveDate: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
expectedURL: "https://example.com/update",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
result, err := tc.have.Parse()
|
|
|
|
if tc.err == "" {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.expected.Status, result.Status)
|
|
assert.Equal(t, tc.expected.EffectiveDate, result.EffectiveDate)
|
|
assert.Equal(t, tc.expected.AuthenticatorVersion, result.AuthenticatorVersion)
|
|
assert.Equal(t, tc.expected.CertificationDescriptor, result.CertificationDescriptor)
|
|
assert.Equal(t, tc.expected.CertificateNumber, result.CertificateNumber)
|
|
assert.Equal(t, tc.expected.CertificationPolicyVersion, result.CertificationPolicyVersion)
|
|
assert.Equal(t, tc.expected.CertificationProfiles, result.CertificationProfiles)
|
|
assert.Equal(t, tc.expected.CertificationRequirementsVersion, result.CertificationRequirementsVersion)
|
|
assert.Equal(t, tc.expected.SunsetDate, result.SunsetDate)
|
|
assert.Equal(t, tc.expected.FIPSRevision, result.FIPSRevision)
|
|
assert.Equal(t, tc.expected.FIPSPhysicalSecurityLevel, result.FIPSPhysicalSecurityLevel)
|
|
|
|
if tc.expectedURL != "" {
|
|
assert.NotNil(t, result.URL)
|
|
assert.Equal(t, tc.expectedURL, result.URL.String())
|
|
}
|
|
} else {
|
|
assert.EqualError(t, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuthenticatorGetInfoJSON_Parse(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
have AuthenticatorGetInfoJSON
|
|
err string
|
|
}{
|
|
{
|
|
name: "ShouldFailInvalidAAGUID",
|
|
have: AuthenticatorGetInfoJSON{
|
|
AaGUID: "not-a-uuid",
|
|
},
|
|
err: "error occurred parsing AAGUID value: invalid UUID length: 10",
|
|
},
|
|
{
|
|
name: "ShouldSucceedMinimal",
|
|
have: AuthenticatorGetInfoJSON{},
|
|
},
|
|
{
|
|
name: "ShouldSucceedWithAAGUID",
|
|
have: AuthenticatorGetInfoJSON{
|
|
AaGUID: "2369d4d0-13ce-48cb-9f26-f7ed8c9a6068",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := tc.have.Parse()
|
|
|
|
if tc.err == "" {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.EqualError(t, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func timePtr(t time.Time) *time.Time {
|
|
return &t
|
|
}
|