Skip to content

Commit

Permalink
additional tests
Browse files Browse the repository at this point in the history
  • Loading branch information
woutslakhorst committed Dec 20, 2024
1 parent bcde56c commit 9d84824
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 25 deletions.
34 changes: 13 additions & 21 deletions vcr/credential/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ func (d x509CredentialValidator) Validate(credential vc.VerifiableCredential) er
if credential.Format() == vc.JWTCredentialProofFormat {
headers, err := crypto.ExtractProtectedHeaders(credential.Raw())
if err != nil {
// theoretically impossible, since the credential is already parsed
return fmt.Errorf("%w: invalid JWT headers: %w", errValidation, err)
}
resolveMetadata.JwtProtectedHeaders = headers
Expand All @@ -287,7 +288,7 @@ func (d x509CredentialValidator) Validate(credential vc.VerifiableCredential) er
return fmt.Errorf("%w: invalid issuer: %w", errValidation, err)
}

if err = validatePolicyAssertions(credential); err != nil {
if err = validatePolicyAssertions(*didX509Issuer, credential); err != nil {
return fmt.Errorf("%w: %w", errValidation, err)
}

Expand All @@ -296,14 +297,9 @@ func (d x509CredentialValidator) Validate(credential vc.VerifiableCredential) er
chain := make([]*x509.Certificate, chainHeader.Len())
for i := 0; i < chainHeader.Len(); i++ {
base64Cert, _ := chainHeader.Get(i)
der, err := base64.StdEncoding.DecodeString(string(base64Cert))
if err != nil {
return fmt.Errorf("%w: invalid certificate chain: %w", errValidation, err)
}
cert, err := x509.ParseCertificate(der)
if err != nil {
return fmt.Errorf("%w: invalid certificate chain: %w", errValidation, err)
}
// these two operations can't fail since the resolve earlier already succeeded
der, _ := base64.StdEncoding.DecodeString(string(base64Cert))
cert, _ := x509.ParseCertificate(der)
chain[i] = cert
}
if err = d.pkiValidator.CheckCRL(chain); err != nil {
Expand All @@ -314,27 +310,23 @@ func (d x509CredentialValidator) Validate(credential vc.VerifiableCredential) er
}

// validatePolicyAssertions checks if the credentialSubject claims match the did issuer policies
func validatePolicyAssertions(credential vc.VerifiableCredential) error {
func validatePolicyAssertions(issuer did.DID, credential vc.VerifiableCredential) error {
// get base form of all credentialSubject
var target = make([]map[string]interface{}, 1)
if err := credential.UnmarshalCredentialSubject(&target); err != nil {
return err
}

// we create a map of policyName to policyValue, then we split the policyValue into another map
// no checks required, this has been done by the did:x509 resolver
x509DID, _ := didx509.ParseX509Did(issuer)
policyMap := make(map[string]map[string]string)
policies := strings.Split(credential.Issuer.String(), "::")
if len(policies) < 2 {
return fmt.Errorf("invalid did:x509 policy")
}
for _, policy := range policies[1:] {
policySplit := strings.Split(policy, ":")
if len(policySplit)%2 != 1 { // policy name and 2*n key/value pairs
return fmt.Errorf("invalid did:x509 policy '%s'", policy)
}
policyName := policySplit[0]
for _, policy := range x509DID.Policies {
policySplit := strings.Split(policy.Value, ":")
policyName := string(policy.Name)
policyMap[policyName] = make(map[string]string)
for i := 1; i < len(policySplit); i += 2 {
// bounds checked by ParseX509Did
for i := 0; i < len(policySplit); i += 2 {
unscaped, _ := url.PathUnescape(policySplit[i+1])
policyMap[policyName][policySplit[i]] = unscaped
}
Expand Down
28 changes: 27 additions & 1 deletion vcr/credential/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,12 +529,31 @@ func TestX509CredentialValidator_Validate(t *testing.T) {
assert.ErrorIs(t, err, errValidation)
assert.ErrorIs(t, err, did.ErrInvalidDID)
})
t.Run("invalid format", func(t *testing.T) {
x509credential := vc.VerifiableCredential{Issuer: ssi.MustParseURI("did:example:123")}

err := ctx.validator.Validate(x509credential)

assert.ErrorIs(t, err, errValidation)
assert.ErrorContains(t, err, "unsupported credential format")
})
t.Run("invalid did:x509", func(t *testing.T) {
x509credential := test.ValidX509Credential(t, func(builder *jwt.Builder) *jwt.Builder {
builder.Issuer("did:example:123")
return builder
})

err := ctx.validator.Validate(x509credential)

assert.ErrorIs(t, err, errValidation)
assert.ErrorContains(t, err, "invalid issuer")
})

t.Run("failed validation", func(t *testing.T) {

testCases := []struct {
name string
claim map[string]interface{}
claim interface{}
expectedError string
}{
{
Expand All @@ -544,6 +563,13 @@ func TestX509CredentialValidator_Validate(t *testing.T) {
},
expectedError: "invalid assertion value 'A_BIG_STRIN' for 'san:otherName' did:x509 policy",
},
{
name: "invalid assertion name",
claim: map[string]interface{}{
"san": "A_BIG_STRING",
},
expectedError: "invalid credentialSubject assertion name 'san'",
},
{
name: "unknown assertion",
claim: map[string]interface{}{
Expand Down
6 changes: 3 additions & 3 deletions vdr/didx509/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (r Resolver) Resolve(id did.DID, metadata *resolver.ResolveMetadata) (*did.
if id.Method != MethodName {
return nil, nil, fmt.Errorf("unsupported DID method: %s", id.Method)
}
ref, err := parseX509Did(id)
ref, err := ParseX509Did(id)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -206,8 +206,8 @@ func createDidDocument(id did.DID, validationCert *x509.Certificate) (*did.Docum
return document, nil
}

// parseX509Did parses a DID (Decentralized Identifier) in the x509 format and returns a corresponding X509DidReference.
func parseX509Did(id did.DID) (*X509DidReference, error) {
// ParseX509Did parses a DID (Decentralized Identifier) in the x509 format and returns a corresponding X509DidReference.
func ParseX509Did(id did.DID) (*X509DidReference, error) {
ref := X509DidReference{}
fullDidString := id.ID
policyStrings := []string{}
Expand Down

0 comments on commit 9d84824

Please sign in to comment.