Skip to content

Commit

Permalink
Merge pull request trustbloc#1633 from aholovko/validate_nonce_attest…
Browse files Browse the repository at this point in the history
…ation_vp

feat: validate nonce and aud in attestation vp
  • Loading branch information
fqutishat authored Mar 8, 2024
2 parents b775057 + d8b93aa commit 89333c7
Show file tree
Hide file tree
Showing 16 changed files with 539 additions and 460 deletions.
4 changes: 2 additions & 2 deletions cmd/vc-rest/startcmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ func buildEchoHandler(
KMSRegistry: kmsRegistry,
CryptoJWTSigner: vcCrypto,
JSONSchemaValidator: jsonSchemaValidator,
TrustRegistryService: trustRegistryService,
TrustRegistry: trustRegistryService,
AckService: ackService,
})
if err != nil {
Expand Down Expand Up @@ -952,7 +952,7 @@ func buildEchoHandler(
DocumentLoader: documentLoader,
ProfileService: verifierProfileSvc,
PresentationVerifier: verifyPresentationSvc,
TrustRegistryService: trustRegistryService,
TrustRegistry: trustRegistryService,
RedirectURL: conf.StartupParameters.apiGatewayURL + oidc4VPCheckEndpoint,
TokenLifetime: 15 * time.Minute,
Metrics: metrics,
Expand Down
2 changes: 1 addition & 1 deletion component/wallet-cli/cmd/attest_wallet_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func NewAttestWalletCommand() *cobra.Command {
return fmt.Errorf("create attestation service: %w", err)
}

if _, err = attestationService.GetAttestation(context.Background()); err != nil {
if _, err = attestationService.GetAttestation(context.Background(), "", ""); err != nil {
return fmt.Errorf("get attestation: %w", err)
}

Expand Down
16 changes: 14 additions & 2 deletions component/wallet-cli/pkg/attestation/attestation_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func NewService(
}, nil
}

func (s *Service) GetAttestation(ctx context.Context) (string, error) {
func (s *Service) GetAttestation(ctx context.Context, audience, nonce string) (string, error) {
b, err := s.store.Get(attestationVCKey)
if err != nil {
if errors.Is(err, storageapi.ErrDataNotFound) {
Expand Down Expand Up @@ -135,7 +135,19 @@ func (s *Service) GetAttestation(ctx context.Context) (string, error) {

attestationVP.ID = uuid.New().String()

claims, err := attestationVP.JWTClaims([]string{}, false)
if nonce != "" {
attestationVP.CustomFields = map[string]interface{}{
"nonce": nonce,
}
}

var aud []string

if audience != "" {
aud = []string{audience}
}

claims, err := attestationVP.JWTClaims(aud, false)
if err != nil {
return "", fmt.Errorf("get attestation claims: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions component/wallet-cli/pkg/oidc4vci/oidc4vci_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const (
)

type AttestationService interface {
GetAttestation(ctx context.Context) (string, error)
GetAttestation(ctx context.Context, audience, nonce string) (string, error)
}

type TrustRegistry interface {
Expand Down Expand Up @@ -365,7 +365,7 @@ func (f *Flow) Run(ctx context.Context) (*verifiable.Credential, error) {
if attestationRequired {
var jwtVP string

jwtVP, err = f.attestationService.GetAttestation(ctx)
jwtVP, err = f.attestationService.GetAttestation(ctx, issuerDID, preAuthorizationGrant.PreAuthorizedCode)
if err != nil {
return nil, fmt.Errorf("get attestation: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions component/wallet-cli/pkg/oidc4vp/oidc4vp_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const (
)

type AttestationService interface {
GetAttestation(ctx context.Context) (string, error)
GetAttestation(ctx context.Context, audience, nonce string) (string, error)
}

type TrustRegistry interface {
Expand Down Expand Up @@ -620,7 +620,7 @@ func (f *Flow) createIDToken(
if attestationRequired {
var jwtVP string

jwtVP, err = f.attestationService.GetAttestation(ctx)
jwtVP, err = f.attestationService.GetAttestation(ctx, "", "")
if err != nil {
return "", fmt.Errorf("get attestation: %w", err)
}
Expand Down
97 changes: 73 additions & 24 deletions pkg/service/oidc4ci/oidc4ci_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

//go:generate mockgen -destination oidc4ci_service_mocks_test.go -self_package mocks -package oidc4ci_test -source=oidc4ci_service.go -mock_names transactionStore=MockTransactionStore,wellKnownService=MockWellKnownService,eventService=MockEventService,pinGenerator=MockPinGenerator,credentialOfferReferenceStore=MockCredentialOfferReferenceStore,claimDataStore=MockClaimDataStore,profileService=MockProfileService,dataProtector=MockDataProtector,kmsRegistry=MockKMSRegistry,cryptoJWTSigner=MockCryptoJWTSigner,jsonSchemaValidator=MockJSONSchemaValidator,trustRegistryService=MockTrustRegistryService,ackStore=MockAckStore,ackService=MockAckService
//go:generate mockgen -destination oidc4ci_service_mocks_test.go -self_package mocks -package oidc4ci_test -source=oidc4ci_service.go -mock_names transactionStore=MockTransactionStore,wellKnownService=MockWellKnownService,eventService=MockEventService,pinGenerator=MockPinGenerator,credentialOfferReferenceStore=MockCredentialOfferReferenceStore,claimDataStore=MockClaimDataStore,profileService=MockProfileService,dataProtector=MockDataProtector,kmsRegistry=MockKMSRegistry,cryptoJWTSigner=MockCryptoJWTSigner,jsonSchemaValidator=MockJSONSchemaValidator,trustRegistry=MockTrustRegistry,ackStore=MockAckStore,ackService=MockAckService

package oidc4ci

Expand All @@ -31,12 +31,14 @@ import (
profileapi "github.com/trustbloc/vcs/pkg/profile"
"github.com/trustbloc/vcs/pkg/restapi/resterr"
"github.com/trustbloc/vcs/pkg/restapi/v1/common"
"github.com/trustbloc/vcs/pkg/service/trustregistry"
)

const (
defaultGrantType = "authorization_code"
defaultResponseType = "token"
defaultCtx = "https://www.w3.org/2018/credentials/v1"
defaultGrantType = "authorization_code"
defaultResponseType = "token"
defaultCtx = "https://www.w3.org/2018/credentials/v1"
attestJWTClientAuthType = "attest_jwt_client_auth"
)

var _ ServiceInterface = (*Service)(nil)
Expand Down Expand Up @@ -119,13 +121,8 @@ type jsonSchemaValidator interface {
Validate(data interface{}, schemaID string, schema []byte) error
}

type trustRegistryService interface {
ValidateIssuance(
ctx context.Context,
profile *profileapi.Issuer,
attestationVP string,
credentialTypes []string,
) error
type trustRegistry interface {
trustregistry.ValidateIssuance
}

type ackStore interface {
Expand Down Expand Up @@ -162,7 +159,7 @@ type Config struct {
KMSRegistry kmsRegistry
CryptoJWTSigner cryptoJWTSigner
JSONSchemaValidator jsonSchemaValidator
TrustRegistryService trustRegistryService
TrustRegistry trustRegistry
AckService ackService
}

Expand All @@ -183,7 +180,7 @@ type Service struct {
kmsRegistry kmsRegistry
cryptoJWTSigner cryptoJWTSigner
schemaValidator jsonSchemaValidator
trustRegistryService trustRegistryService
trustRegistry trustRegistry
ackService ackService
}

Expand All @@ -205,7 +202,7 @@ func NewService(config *Config) (*Service, error) {
kmsRegistry: config.KMSRegistry,
cryptoJWTSigner: config.CryptoJWTSigner,
schemaValidator: config.JSONSchemaValidator,
trustRegistryService: config.TrustRegistryService,
trustRegistry: config.TrustRegistry,
ackService: config.AckService,
}, nil
}
Expand Down Expand Up @@ -558,16 +555,6 @@ func (s *Service) ValidatePreAuthorizedCodeRequest( //nolint:gocognit,nolintlint
}
}

var credentialTypes []string

if tx.CredentialTemplate != nil {
credentialTypes = append(credentialTypes, tx.CredentialTemplate.Type)
}

if err = s.CheckPolicies(ctx, profile, clientAssertionType, clientAssertion, credentialTypes); err != nil {
return nil, resterr.NewCustomError(resterr.OIDCClientAuthenticationFailed, err)
}

newState := TransactionStatePreAuthCodeValidated
if err = s.validateStateTransition(tx.State, newState); err != nil {
return nil, err
Expand All @@ -586,6 +573,10 @@ func (s *Service) ValidatePreAuthorizedCodeRequest( //nolint:gocognit,nolintlint
return nil, resterr.NewCustomError(resterr.OIDCPreAuthorizeInvalidPin, fmt.Errorf("invalid pin"))
}

if err = s.checkPolicy(ctx, profile, tx, clientAssertionType, clientAssertion); err != nil {
return nil, resterr.NewCustomError(resterr.OIDCClientAuthenticationFailed, err)
}

if err = s.store.Update(ctx, tx); err != nil {
return nil, err
}
Expand All @@ -597,6 +588,64 @@ func (s *Service) ValidatePreAuthorizedCodeRequest( //nolint:gocognit,nolintlint
return tx, nil
}

func (s *Service) checkPolicy(
ctx context.Context,
profile *profileapi.Issuer,
tx *Transaction,
clientAssertionType,
clientAssertion string,
) error {
if profile.OIDCConfig == nil ||
!lo.Contains(profile.OIDCConfig.TokenEndpointAuthMethodsSupported, attestJWTClientAuthType) {
return nil
}

if err := s.validateClientAssertionParams(clientAssertionType, clientAssertion); err != nil {
return err
}

if profile.Checks.Policy.PolicyURL != "" {
var credentialTypes []string

if tx.CredentialTemplate != nil {
credentialTypes = []string{tx.CredentialTemplate.Type}
}

if err := s.trustRegistry.ValidateIssuance(
ctx,
profile,
&trustregistry.ValidateIssuanceData{
AttestationVP: clientAssertion,
CredentialTypes: credentialTypes,
Nonce: tx.PreAuthCode,
},
); err != nil {
return resterr.NewCustomError(resterr.OIDCClientAuthenticationFailed, err)
}
}

return nil
}

func (s *Service) validateClientAssertionParams(clientAssertionType, clientAssertion string) error {
if clientAssertionType == "" {
return resterr.NewCustomError(resterr.OIDCClientAuthenticationFailed,
errors.New("no client assertion type specified"))
}

if clientAssertionType != attestJWTClientAuthType {
return resterr.NewCustomError(resterr.OIDCClientAuthenticationFailed,
errors.New("only supported client assertion type is attest_jwt_client_auth"))
}

if clientAssertion == "" {
return resterr.NewCustomError(resterr.OIDCClientAuthenticationFailed,
errors.New("client_assertion is required"))
}

return nil
}

func (s *Service) PrepareCredential( //nolint:funlen
ctx context.Context,
req *PrepareCredential,
Expand Down
70 changes: 0 additions & 70 deletions pkg/service/oidc4ci/oidc4ci_service_check_policies.go

This file was deleted.

Loading

0 comments on commit 89333c7

Please sign in to comment.