Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: merge main #1599

Merged
16 changes: 8 additions & 8 deletions cmd/vc-rest/startcmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ import (
oidc4vpv1 "github.com/trustbloc/vcs/pkg/restapi/v1/oidc4vp"
verifierv1 "github.com/trustbloc/vcs/pkg/restapi/v1/verifier"
"github.com/trustbloc/vcs/pkg/restapi/v1/version"
"github.com/trustbloc/vcs/pkg/service/clientattestation"
"github.com/trustbloc/vcs/pkg/service/clientidscheme"
clientmanagersvc "github.com/trustbloc/vcs/pkg/service/clientmanager"
credentialstatustypes "github.com/trustbloc/vcs/pkg/service/credentialstatus"
Expand All @@ -92,6 +91,7 @@ import (
"github.com/trustbloc/vcs/pkg/service/oidc4ci"
"github.com/trustbloc/vcs/pkg/service/oidc4vp"
"github.com/trustbloc/vcs/pkg/service/requestobject"
"github.com/trustbloc/vcs/pkg/service/trustregistry"
"github.com/trustbloc/vcs/pkg/service/verifycredential"
"github.com/trustbloc/vcs/pkg/service/verifypresentation"
wellknownfetcher "github.com/trustbloc/vcs/pkg/service/wellknown/fetcher"
Expand Down Expand Up @@ -687,8 +687,8 @@ func buildEchoHandler(

proofChecker := defaults.NewDefaultProofChecker(vermethod.NewVDRResolver(conf.VDR))

clientAttestationService := clientattestation.NewService(
&clientattestation.Config{
trustRegistryService := trustregistry.NewService(
&trustregistry.Config{
HTTPClient: getHTTPClient(metricsProvider.ClientAttestationService),
DocumentLoader: documentLoader,
ProofChecker: proofChecker,
Expand Down Expand Up @@ -719,7 +719,7 @@ func buildEchoHandler(
KMSRegistry: kmsRegistry,
CryptoJWTSigner: vcCrypto,
JSONSchemaValidator: jsonSchemaValidator,
ClientAttestationService: clientAttestationService,
TrustRegistryService: trustRegistryService,
AckService: ackService,
})
if err != nil {
Expand Down Expand Up @@ -880,10 +880,10 @@ func buildEchoHandler(
var verifyPresentationSvc verifypresentation.ServiceInterface

verifyPresentationSvc = verifypresentation.New(&verifypresentation.Config{
VcVerifier: verifyCredentialSvc,
DocumentLoader: documentLoader,
VDR: conf.VDR,
ClientAttestationService: clientAttestationService,
VcVerifier: verifyCredentialSvc,
DocumentLoader: documentLoader,
VDR: conf.VDR,
TrustRegistryService: trustRegistryService,
})

if conf.IsTraceEnabled {
Expand Down
46 changes: 33 additions & 13 deletions component/wallet-cli/pkg/attestation/attestation_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,28 @@ func NewClient(config *Config) *Client {
}
}

func (c *Client) GetAttestationVC(ctx context.Context) (*verifiable.Credential, error) {
type options struct {
attestationRequest *AttestWalletInitRequest
}

type Opt func(*options)

func WithAttestationRequest(value *AttestWalletInitRequest) Opt {
return func(o *options) {
o.attestationRequest = value
}
}

func (c *Client) GetAttestationVC(ctx context.Context, opts ...Opt) (*verifiable.Credential, error) {
logger.Debug("get attestation vc", zap.String("walletDID", c.walletDID))

initResp, err := c.attestationInit(ctx)
options := &options{}

for _, opt := range opts {
opt(options)
}

initResp, err := c.attestationInit(ctx, options.attestationRequest)
if err != nil {
return nil, fmt.Errorf("attestation init: %w", err)
}
Expand All @@ -80,19 +98,21 @@ func (c *Client) GetAttestationVC(ctx context.Context) (*verifiable.Credential,
return attestationVC, nil
}

func (c *Client) attestationInit(ctx context.Context) (*AttestWalletInitResponse, error) {
func (c *Client) attestationInit(ctx context.Context, req *AttestWalletInitRequest) (*AttestWalletInitResponse, error) {
logger.Debug("attestation init started", zap.String("walletDID", c.walletDID))

req := &AttestWalletInitRequest{
Assertions: []string{
"wallet_authentication",
},
WalletAuthentication: map[string]interface{}{
"wallet_id": c.walletDID,
},
WalletMetadata: map[string]interface{}{
"wallet_name": "wallet-cli",
},
if req == nil {
req = &AttestWalletInitRequest{
Assertions: []string{
"wallet_authentication",
},
WalletAuthentication: map[string]interface{}{
"wallet_id": c.walletDID,
},
WalletMetadata: map[string]interface{}{
"wallet_name": "wallet-cli",
},
}
}

body, err := json.Marshal(req)
Expand Down
35 changes: 31 additions & 4 deletions component/wallet-cli/pkg/oidc4vci/oidc4vci_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ const (
FlowTypePreAuthorizedCode = "pre-authorized_code"
)

type trustRegistry interface {
ValidateIssuer(issuerDID, issuerDomain, credentialType, credentialFormat string, clientAttestationRequested bool) error
}

type Flow struct {
httpClient *http.Client
documentLoader ld.DocumentLoader
Expand All @@ -75,6 +79,7 @@ type Flow struct {
wallet *wallet.Wallet
wellKnownService *wellknown.Service
trustRegistryURL string
trustRegistryClient trustRegistry
flowType FlowType
credentialOffer string
credentialType string
Expand Down Expand Up @@ -173,6 +178,14 @@ func NewFlow(p provider, opts ...Opt) (*Flow, error) {
proofBuilder = NewJWTProofBuilder()
}

var trustRegistry trustRegistry

if o.trustRegistry != nil {
trustRegistry = o.trustRegistry
} else if o.trustRegistryURL != "" {
trustRegistry = trustregistry.NewClient(p.HTTPClient(), o.trustRegistryURL)
}

return &Flow{
httpClient: p.HTTPClient(),
documentLoader: p.DocumentLoader(),
Expand All @@ -197,6 +210,7 @@ func NewFlow(p provider, opts ...Opt) (*Flow, error) {
issuerState: o.issuerState,
pin: o.pin,
trustRegistryURL: o.trustRegistryURL,
trustRegistryClient: trustRegistry,
perfInfo: &PerfInfo{},
}, nil
}
Expand Down Expand Up @@ -251,12 +265,18 @@ func (f *Flow) Run(ctx context.Context) (*verifiable.Credential, error) {
tokenEndpointAuthMethodsSupported := lo.FromPtr(openIDConfig.TokenEndpointAuthMethodsSupported)
requireWalletAttestation := lo.Contains(tokenEndpointAuthMethodsSupported, attestJWTClientAuthType)

if f.trustRegistryURL != "" {
if f.trustRegistryClient != nil {
if credentialOfferResponse == nil || len(credentialOfferResponse.CredentialConfigurationIDs) == 0 {
return nil, fmt.Errorf("credential offer is empty")
}

slog.Info("Validating issuer", "url", f.trustRegistryURL)
issuerDID := f.wellKnownService.GetIssuerDID()

if issuerDID == "" {
slog.Warn("Issuer DID is empty. Does '/.well-known/openid-credential-issuer' return jwt?")
}

slog.Info("Validating issuer", "did", issuerDID, "url", f.trustRegistryURL)

configurationID := credentialOfferResponse.CredentialConfigurationIDs[0]
credentialConfiguration := openIDConfig.CredentialConfigurationsSupported.AdditionalProperties[configurationID]
Expand All @@ -270,9 +290,9 @@ func (f *Flow) Run(ctx context.Context) (*verifiable.Credential, error) {
}
}

if err = trustregistry.NewClient(f.httpClient, f.trustRegistryURL).
if err = f.trustRegistryClient.
ValidateIssuer(
credentialOfferResponse.CredentialIssuer,
issuerDID,
"",
credentialType,
credentialConfiguration.Format,
Expand Down Expand Up @@ -1019,6 +1039,7 @@ type options struct {
issuerState string
pin string
trustRegistryURL string
trustRegistry trustRegistry
walletDIDIndex int
}

Expand Down Expand Up @@ -1108,6 +1129,12 @@ func WithTrustRegistryURL(url string) Opt {
}
}

func WithTrustRegistry(value trustRegistry) Opt {
return func(opts *options) {
opts.trustRegistry = value
}
}

func WithWalletDIDIndex(idx int) Opt {
return func(opts *options) {
opts.walletDIDIndex = idx
Expand Down
26 changes: 23 additions & 3 deletions component/wallet-cli/pkg/oidc4vp/oidc4vp_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ const (
customScopeWalletDetails = "walletdetails"
)

type trustRegistry interface {
ValidateVerifier(verifierDID, verifierDomain string, credentials []*verifiable.Credential) error
}

type Flow struct {
httpClient *http.Client
documentLoader ld.DocumentLoader
Expand All @@ -67,6 +71,7 @@ type Flow struct {
disableSchemaValidation bool
trustRegistryURL string
perfInfo *PerfInfo
trustRegistryClient trustRegistry
}

type provider interface {
Expand Down Expand Up @@ -119,6 +124,14 @@ func NewFlow(p provider, opts ...Opt) (*Flow, error) {
kmssigner.NewKMSSigner(signer, signatureType, nil),
)

var trustRegistry trustRegistry

if o.trustRegistry != nil {
trustRegistry = o.trustRegistry
} else if o.trustRegistryURL != "" {
trustRegistry = trustregistry.NewClient(p.HTTPClient(), o.trustRegistryURL)
}

return &Flow{
httpClient: p.HTTPClient(),
documentLoader: p.DocumentLoader(),
Expand All @@ -131,7 +144,7 @@ func NewFlow(p provider, opts ...Opt) (*Flow, error) {
enableLinkedDomainVerification: o.enableLinkedDomainVerification,
disableDomainMatching: o.disableDomainMatching,
disableSchemaValidation: o.disableSchemaValidation,
trustRegistryURL: o.trustRegistryURL,
trustRegistryClient: trustRegistry,
perfInfo: &PerfInfo{},
}, nil
}
Expand Down Expand Up @@ -177,10 +190,10 @@ func (f *Flow) Run(ctx context.Context) error {
return fmt.Errorf("query wallet: %w", err)
}

if f.trustRegistryURL != "" {
if f.trustRegistryClient != nil {
slog.Info("validate verifier", "url", f.trustRegistryURL)

if err = trustregistry.NewClient(f.httpClient, f.trustRegistryURL).
if err = f.trustRegistryClient.
ValidateVerifier(
requestObject.ClientID,
"",
Expand Down Expand Up @@ -703,6 +716,7 @@ type options struct {
disableDomainMatching bool
disableSchemaValidation bool
trustRegistryURL string
trustRegistry trustRegistry
}

type Opt func(opts *options)
Expand Down Expand Up @@ -742,3 +756,9 @@ func WithTrustRegistryURL(url string) Opt {
opts.trustRegistryURL = url
}
}

func WithTrustRegistry(value trustRegistry) Opt {
return func(opts *options) {
opts.trustRegistry = value
}
}
21 changes: 15 additions & 6 deletions component/wallet-cli/pkg/wellknown/wellknown.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
type Service struct {
HTTPClient *http.Client
VDRRegistry vdrapi.Registry
issuerDID string
}

// GetWellKnownOpenIDConfiguration returns OIDC Configuration.
Expand Down Expand Up @@ -66,12 +67,16 @@ func (s *Service) GetWellKnownOpenIDConfiguration(
return &oidcConfigUnsigned, nil
}

wellKnownOpenIDIssuerConfigurationPayload, err = getWellKnownOpenIDConfigurationJWTPayload(
var issuerDID []byte

wellKnownOpenIDIssuerConfigurationPayload, issuerDID, err = getWellKnownOpenIDConfigurationJWTPayload(
signedMetadata, s.VDRRegistry)
if err != nil {
return nil, err
}

s.issuerDID = string(issuerDID)

var oidcConfig issuerv1.WellKnownOpenIDIssuerConfiguration

if err = json.Unmarshal(wellKnownOpenIDIssuerConfigurationPayload, &oidcConfig); err != nil {
Expand All @@ -81,7 +86,7 @@ func (s *Service) GetWellKnownOpenIDConfiguration(
return &oidcConfig, nil
}

func getWellKnownOpenIDConfigurationJWTPayload(rawResponse string, vdrRegistry vdrapi.Registry) ([]byte, error) {
func getWellKnownOpenIDConfigurationJWTPayload(rawResponse string, vdrRegistry vdrapi.Registry) ([]byte, []byte, error) {
jwtVerifier := defaults.NewDefaultProofChecker(vermethod.NewVDRResolver(vdrRegistry))

_, credentialOfferPayload, err := jwt.ParseAndCheckProof(
Expand All @@ -90,19 +95,23 @@ func getWellKnownOpenIDConfigurationJWTPayload(rawResponse string, vdrRegistry v
jwt.WithIgnoreClaimsMapDecoding(true),
)
if err != nil {
return nil, fmt.Errorf("parse issuer configuration JWT: %w", err)
return nil, nil, fmt.Errorf("parse issuer configuration JWT: %w", err)
}

var fastParser fastjson.Parser
v, err := fastParser.ParseBytes(credentialOfferPayload)
if err != nil {
return nil, fmt.Errorf("decode claims: %w", err)
return nil, nil, fmt.Errorf("decode claims: %w", err)
}

sb, err := v.Get("well_known_openid_issuer_configuration").Object()
if err != nil {
return nil, fmt.Errorf("fastjson.Parser Get well_known_openid_issuer_configuration: %w", err)
return nil, nil, fmt.Errorf("fastjson.Parser Get well_known_openid_issuer_configuration: %w", err)
}

return sb.MarshalTo([]byte{}), nil
return sb.MarshalTo([]byte{}), v.GetStringBytes("iss"), nil
}

func (s *Service) GetIssuerDID() string {
return s.issuerDID
}
9 changes: 8 additions & 1 deletion pkg/profile/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,17 +220,24 @@ type OIDC4VPConfig struct {
type VerificationChecks struct {
Credential CredentialChecks `json:"credential,omitempty"`
Presentation *PresentationChecks `json:"presentation,omitempty"`
Policy PolicyCheck `json:"policy,omitempty"`
ClientAttestationCheck ClientAttestationCheck `json:"clientAttestationCheck,omitempty"`
}

// IssuanceChecks are checks to be performed for issuance credentials and presentations.
type IssuanceChecks struct {
Policy PolicyCheck `json:"policy,omitempty"`
ClientAttestationCheck ClientAttestationCheck `json:"clientAttestationCheck,omitempty"`
}

// PolicyCheck stores policy check configuration.
type PolicyCheck struct {
PolicyURL string `json:"policyUrl"`
}

// ClientAttestationCheck stores Client Attestation check configuration.
type ClientAttestationCheck struct {
PolicyURL string `json:"policyUrl"`
Enabled bool `json:"enabled"`
}

// PresentationChecks are checks to be performed during presentation verification.
Expand Down
Loading
Loading