Skip to content

Commit

Permalink
feat: Public key store/cache for Observer
Browse files Browse the repository at this point in the history
Implemented a public key storage and cache for the Observer. When verifying a witness proof, the Observer will load the public key of the signer from the cache/database. If it doesn't exist in the DB then the public key is retrieved using the public key fetcher.

Also enhanced the BDD test so that, when creating DIDs on multiple targets, the target will be greylisted if it is down and the create will be performed on another target.

closes #1261

Signed-off-by: Bob Stasyszyn <Bob.Stasyszyn@securekey.com>
  • Loading branch information
bstasyszyn committed Apr 26, 2022
1 parent 4425233 commit 23b246b
Show file tree
Hide file tree
Showing 12 changed files with 574 additions and 57 deletions.
14 changes: 13 additions & 1 deletion cmd/orb-server/startcmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"encoding/pem"
"errors"
"fmt"
"github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier"
"github.com/trustbloc/orb/pkg/store/publickey"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -870,6 +872,15 @@ func startOrbServices(parameters *orbParameters) error {
return fmt.Errorf("open store: %w", err)
}

pkStore, err := publickey.New(storeProviders.provider, verifiable.NewVDRKeyResolver(vdr).PublicKeyFetcher())
if err != nil {
return fmt.Errorf("create public key storage: %w", err)
}

publicKeyFetcher := func(issuerID, keyID string) (*verifier.PublicKey, error) {
return pkStore.GetPublicKey(issuerID, keyID)
}

// create new observer and start it
providers := &observer.Providers{
ProtocolClientProvider: pcp,
Expand All @@ -881,7 +892,7 @@ func startOrbServices(parameters *orbParameters) error {
WebFingerResolver: resourceResolver,
CASResolver: casResolver,
DocLoader: orbDocumentLoader,
Pkf: verifiable.NewVDRKeyResolver(vdr).PublicKeyFetcher(),
PublicKeyFetcher: publicKeyFetcher,
AnchorLinkStore: anchorLinkStore,
}

Expand Down Expand Up @@ -994,6 +1005,7 @@ func startOrbServices(parameters *orbParameters) error {
discoveryclient.WithNamespace(parameters.didNamespace),
discoveryclient.WithHTTPClient(httpClient),
discoveryclient.WithDIDWebHTTP(parameters.enableDevMode),
discoveryclient.WithPublicKeyFetcher(publicKeyFetcher),
)

if parameters.verifyLatestFromAnchorOrigin {
Expand Down
18 changes: 15 additions & 3 deletions pkg/discovery/endpoint/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type Client struct {
casReader casReader
authToken string
disableProofCheck bool
publicKeyFetcher verifiable.PublicKeyFetcher
didWebHTTP bool
docLoader ld.DocumentLoader
orbClient orbClient
Expand Down Expand Up @@ -108,13 +109,16 @@ func New(docLoader ld.DocumentLoader, casReader casReader, opts ...Option) (*Cli
if configService.disableProofCheck {
orbClientOpts = append(orbClientOpts, aoprovider.WithDisableProofCheck(configService.disableProofCheck))
} else {
orbClientOpts = append(orbClientOpts, aoprovider.WithPublicKeyFetcher(
verifiable.NewVDRKeyResolver(vdr.New(vdr.WithVDR(&webVDR{
if configService.publicKeyFetcher == nil {
configService.publicKeyFetcher = verifiable.NewVDRKeyResolver(vdr.New(vdr.WithVDR(&webVDR{
http: configService.httpClient,
useHTTP: configService.didWebHTTP,
VDR: web.New(),
}),
)).PublicKeyFetcher()))
)).PublicKeyFetcher()
}

orbClientOpts = append(orbClientOpts, aoprovider.WithPublicKeyFetcher(configService.publicKeyFetcher))
}

orbClient, err := aoprovider.New(configService.namespace, configService.casReader, orbClientOpts...)
Expand Down Expand Up @@ -498,6 +502,14 @@ func WithDisableProofCheck(disable bool) Option {
}
}

// WithPublicKeyFetcher sets the public key fetcher. If not set then
// the default fetcher is used.
func WithPublicKeyFetcher(pkf verifiable.PublicKeyFetcher) Option {
return func(opts *Client) {
opts.publicKeyFetcher = pkf
}
}

// WithDIDWebHTTP use did web http.
func WithDIDWebHTTP(enable bool) Option {
return func(opts *Client) {
Expand Down
15 changes: 15 additions & 0 deletions pkg/discovery/endpoint/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"testing"
"time"

"github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier"
"github.com/stretchr/testify/require"

"github.com/trustbloc/orb/pkg/activitypub/client/transport"
Expand Down Expand Up @@ -48,6 +49,20 @@ func TestNew(t *testing.T) {
require.Equal(t, time.Minute, cs.cacheLifetime)
require.Equal(t, 500, cs.cacheSize)
})

t.Run("success - with public key fetcher", func(t *testing.T) {
cs, err := New(nil, &referenceCASReaderImplementation{},
WithAuthToken("t1"),
WithPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) {
return &verifier.PublicKey{}, nil
}),
)
require.NoError(t, err)
require.NotNil(t, cs)

require.Equal(t, defaultCacheLifetime, cs.cacheLifetime)
require.Equal(t, defaultCacheSize, cs.cacheSize)
})
}

func TestConfigService_GetEndpointAnchorOrigin(t *testing.T) {
Expand Down
116 changes: 116 additions & 0 deletions pkg/mocks/publickeyretriever.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions pkg/observer/observer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/trustbloc/orb/pkg/anchor/subject"
"github.com/trustbloc/orb/pkg/anchor/util"
discoveryrest "github.com/trustbloc/orb/pkg/discovery/endpoint/restapi"
"github.com/trustbloc/orb/pkg/errors"
orberrors "github.com/trustbloc/orb/pkg/errors"
"github.com/trustbloc/orb/pkg/hashlink"
"github.com/trustbloc/orb/pkg/linkset"
"github.com/trustbloc/orb/pkg/pubsub/spi"
Expand Down Expand Up @@ -135,7 +135,7 @@ type Providers struct {
WebFingerResolver resourceResolver
CASResolver casResolver
DocLoader documentLoader
Pkf verifiable.PublicKeyFetcher
PublicKeyFetcher verifiable.PublicKeyFetcher
AnchorLinkStore anchorLinkStore
}

Expand Down Expand Up @@ -253,7 +253,7 @@ func (o *Observer) processDID(did string) error {
if err := o.processAnchor(
&anchorinfo.AnchorInfo{Hashlink: anchor.CID},
anchor.Info, suffix); err != nil {
if errors.IsTransient(err) {
if orberrors.IsTransient(err) {
// Return an error so that the message is redelivered and retried.
return fmt.Errorf("process out-of-system anchor [%s]: %w", anchor.CID, err)
}
Expand Down Expand Up @@ -313,7 +313,7 @@ func (o *Observer) processAnchor(anchor *anchorinfo.AnchorInfo,
}

vc, err := util.VerifiableCredentialFromAnchorLink(anchorLink,
verifiable.WithPublicKeyFetcher(o.Pkf),
verifiable.WithPublicKeyFetcher(o.PublicKeyFetcher),
verifiable.WithJSONLDDocumentLoader(o.DocLoader),
)
if err != nil {
Expand Down
Loading

0 comments on commit 23b246b

Please sign in to comment.