diff --git a/cmd/policy/main.go b/cmd/policy/main.go
index fbc87fad7d77a8d7a1f176db7d1177a09281ff15..d85ff216f92623938fbc94a6ad0790a883f703c7 100644
--- a/cmd/policy/main.go
+++ b/cmd/policy/main.go
@@ -74,8 +74,10 @@ func main() {
 	// register rego extension functions
 	{
 		cacheFuncs := regofunc.NewCacheFuncs(cfg.Cache.Addr, httpClient())
+		didResolverFuncs := regofunc.NewDIDResolverFuncs(cfg.DIDResolver.Addr, httpClient())
 		regofunc.Register("cacheGet", rego.Function3(cacheFuncs.CacheGetFunc()))
 		regofunc.Register("cacheSet", rego.Function4(cacheFuncs.CacheSetFunc()))
+		regofunc.Register("didResolve", rego.Function1(didResolverFuncs.Resolve()))
 		regofunc.Register("strictBuiltinErrors", rego.StrictBuiltinErrors(true))
 	}
 
diff --git a/internal/config/config.go b/internal/config/config.go
index f9119f67420ba434f36949e3ddbb1380dae39595..9a52c10a1bdbbe1e7a668326fb5e77cea00015d0 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -3,9 +3,10 @@ package config
 import "time"
 
 type Config struct {
-	HTTP  httpConfig
-	Mongo mongoConfig
-	Cache cacheConfig
+	HTTP        httpConfig
+	Mongo       mongoConfig
+	Cache       cacheConfig
+	DIDResolver didResolverConfig
 
 	LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"`
 }
@@ -22,6 +23,10 @@ type cacheConfig struct {
 	Addr string `envconfig:"CACHE_ADDR" required:"true"`
 }
 
+type didResolverConfig struct {
+	Addr string `envconfig:"DID_RESOLVER_ADDR" required:"true"`
+}
+
 type mongoConfig struct {
 	Addr       string `envconfig:"MONGO_ADDR" required:"true"`
 	User       string `envconfig:"MONGO_USER" required:"true"`
diff --git a/internal/regofunc/did_resolver.go b/internal/regofunc/did_resolver.go
new file mode 100644
index 0000000000000000000000000000000000000000..45a7d2645b25d0ff2359a9a3dea0aa5162be1c2b
--- /dev/null
+++ b/internal/regofunc/did_resolver.go
@@ -0,0 +1,60 @@
+package regofunc
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/open-policy-agent/opa/ast"
+	"github.com/open-policy-agent/opa/rego"
+	"github.com/open-policy-agent/opa/types"
+
+	"code.vereign.com/gaiax/tsa/golib/errors"
+)
+
+type DIDResolverFuncs struct {
+	resolverAddr string
+	httpClient   *http.Client
+}
+
+func NewDIDResolverFuncs(resolverAddr string, httpClient *http.Client) *DIDResolverFuncs {
+	return &DIDResolverFuncs{
+		resolverAddr: resolverAddr,
+		httpClient:   httpClient,
+	}
+}
+
+func (dr *DIDResolverFuncs) Resolve() (*rego.Function, rego.Builtin1) {
+	return &rego.Function{
+			Name:    "did.resolve",
+			Decl:    types.NewFunction(types.Args(types.S), types.A),
+			Memoize: true,
+		},
+		func(bctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
+			var DID string
+
+			if err := ast.As(a.Value, &DID); err != nil {
+				return nil, fmt.Errorf("invalid DID: %s", err)
+			}
+			if DID == "" {
+				return nil, errors.New("DID cannot be empty")
+			}
+
+			req, err := http.NewRequest("GET", dr.resolverAddr+"/1.0/identifiers/"+DID, nil)
+			if err != nil {
+				return nil, err
+			}
+
+			resp, err := dr.httpClient.Do(req.WithContext(bctx.Context))
+			if err != nil {
+				return nil, err
+			}
+			defer resp.Body.Close() // nolint:errcheck
+
+			v, err := ast.ValueFromReader(resp.Body)
+			if err != nil {
+				return nil, err
+			}
+
+			return ast.NewTerm(v), nil
+		}
+}
diff --git a/internal/regofunc/did_resolver_test.go b/internal/regofunc/did_resolver_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cbe3156f8fb3326c6d37ecdb090080b1bdae7bdc
--- /dev/null
+++ b/internal/regofunc/did_resolver_test.go
@@ -0,0 +1,36 @@
+package regofunc_test
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/open-policy-agent/opa/rego"
+	"github.com/stretchr/testify/assert"
+
+	"code.vereign.com/gaiax/tsa/policy/internal/regofunc"
+)
+
+func TestResolveFunc(t *testing.T) {
+	expected := `{"data":{"@context":"https://w3id.org/did-resolution/v1","didDocument":"document"}}`
+	resolverSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		_, _ = fmt.Fprint(w, expected)
+	}))
+	defer resolverSrv.Close()
+
+	DIDResolverFuncs := regofunc.NewDIDResolverFuncs(resolverSrv.URL, http.DefaultClient)
+
+	r := rego.New(
+		rego.Query(`did.resolve("did:indy:idunion:BDrEcHc8Tb4Lb2VyQZWEDE")`),
+		rego.Function1(DIDResolverFuncs.Resolve()),
+	)
+	resultSet, err := r.Eval(context.Background())
+	assert.NoError(t, err)
+
+	resultBytes, err := json.Marshal(resultSet[0].Expressions[0].Value)
+	assert.NoError(t, err)
+	assert.Equal(t, expected, string(resultBytes))
+}