Skip to content

Commit

Permalink
Merge pull request #104 from dc4eu/masv_sdjwtvc
Browse files Browse the repository at this point in the history
jwk and some smaller fixes.
  • Loading branch information
masv3971 authored Oct 11, 2024
2 parents 67412c5 + ef5c9cc commit 1b3bddb
Show file tree
Hide file tree
Showing 120 changed files with 21,510 additions and 24 deletions.
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ require (
github.com/go-logr/zapr v1.3.0
github.com/go-playground/validator/v10 v10.22.0
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/lestrrat-go/jwx v1.2.30
github.com/lithammer/shortuuid/v4 v4.0.0
github.com/masv3971/goretask v0.0.2
github.com/masv3971/gosdjwt v0.0.10
Expand Down Expand Up @@ -47,6 +49,7 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/eapache/go-resiliency v1.7.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
Expand All @@ -72,6 +75,11 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
Expand Down
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbD
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
Expand Down Expand Up @@ -135,6 +137,19 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx v1.2.30 h1:VKIFrmjYn0z2J51iLPadqoHIVLzvWNa1kCsTqNDHYPA=
github.com/lestrrat-go/jwx v1.2.30/go.mod h1:vMxrwFhunGZ3qddmfmEm2+uced8MSI6QFWGTKygjSzQ=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c=
github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
Expand Down Expand Up @@ -176,6 +191,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
Expand Down
20 changes: 11 additions & 9 deletions internal/apigw/db/methods_vc_datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,17 +215,21 @@ func (c *VCDatastoreColl) GetDocument(ctx context.Context, query *GetDocumentQue

// DocumentListQuery is the query to get document list
type DocumentListQuery struct {
AuthenticSource string `json:"authentic_source" bson:"authentic_source" validate:"required"`
AuthenticSource string `json:"authentic_source" bson:"authentic_source"`
Identity *model.Identity `json:"identity" bson:"identity" validate:"required"`
DocumentType string `json:"document_type" bson:"document_type" validate:"required"`
DocumentType string `json:"document_type" bson:"document_type"`
ValidFrom int64 `json:"valid_from" bson:"valid_from"`
ValidTo int64 `json:"valid_to" bson:"valid_to"`
}

// DocumentList return matching documents if any, or error
func (c *VCDatastoreColl) DocumentList(ctx context.Context, query *DocumentListQuery) ([]*model.DocumentList, error) {
if err := helpers.Check(ctx, c.Service.cfg, query, c.Service.log); err != nil {
return nil, err
}

filter := bson.M{
"identities.schema.version": bson.M{"$eq": query.Identity.Schema.Version},
"identities.schema.name": bson.M{"$eq": query.Identity.Schema.Name},
}

if query.AuthenticSource != "" {
Expand All @@ -242,7 +246,6 @@ func (c *VCDatastoreColl) DocumentList(ctx context.Context, query *DocumentListQ
filter["identities.family_name"] = bson.M{"$eq": query.Identity.FamilyName}
filter["identities.given_name"] = bson.M{"$eq": query.Identity.GivenName}
filter["identities.birth_date"] = bson.M{"$eq": query.Identity.BirthDate}
//... figure out how to match any of the above attributes
}

cursor, err := c.Coll.Find(ctx, filter)
Expand Down Expand Up @@ -285,11 +288,10 @@ type GetDocumentCollectIDQuery struct {
// GetDocumentCollectID return matching document if any, or error
func (c *VCDatastoreColl) GetDocumentCollectID(ctx context.Context, query *GetDocumentCollectIDQuery) (*model.Document, error) {
filter := bson.M{
"meta.authentic_source": bson.M{"$eq": query.Meta.AuthenticSource},
"meta.collect.id": bson.M{"$eq": query.Meta.Collect.ID},
"meta.document_type": bson.M{"$eq": query.Meta.DocumentType},
"identities.schema.version": bson.M{"$eq": query.Identity.Schema.Version},
"identities.schema.name": bson.M{"$eq": query.Identity.Schema.Name},
"meta.authentic_source": bson.M{"$eq": query.Meta.AuthenticSource},
"meta.collect.id": bson.M{"$eq": query.Meta.Collect.ID},
"meta.document_type": bson.M{"$eq": query.Meta.DocumentType},
"identities.schema.name": bson.M{"$eq": query.Identity.Schema.Name},
}

if query.Identity.AuthenticSourcePersonID != "" {
Expand Down
12 changes: 9 additions & 3 deletions internal/issuer/apiv1/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Client struct {
auditLog *auditlog.Service
privateKey *ecdsa.PrivateKey
publicKey *ecdsa.PublicKey
jwkClaim jwt.MapClaims

ehicClient *ehicClient
pda1Client *pda1Client
Expand All @@ -51,7 +52,7 @@ func New(ctx context.Context, auditLog *auditlog.Service, cfg *model.Cfg, tracer
return nil, err
}

if err := c.initKeys(); err != nil {
if err := c.initKeys(ctx); err != nil {
return nil, err
}

Expand All @@ -60,7 +61,7 @@ func New(ctx context.Context, auditLog *auditlog.Service, cfg *model.Cfg, tracer
return c, nil
}

func (c *Client) initKeys() error {
func (c *Client) initKeys(ctx context.Context) error {
keyByte, err := os.ReadFile(c.cfg.Issuer.SigningKeyPath)
if err != nil {
c.log.Error(err, "Failed to read signing key, please create a ECDSA prime256v1 key and save it to the path")
Expand All @@ -76,13 +77,18 @@ func (c *Client) initKeys() error {

c.publicKey = &c.privateKey.PublicKey

if err := c.createJWK(ctx); err != nil {
return err
}

return nil
}

func (c *Client) sign(instruction gosdjwt.InstructionsV2) (*gosdjwt.SDJWT, error) {
func (c *Client) sign(ctx context.Context, instruction gosdjwt.InstructionsV2) (*gosdjwt.SDJWT, error) {
jwtConfig := &gosdjwt.Config{
ISS: c.cfg.Issuer.JWTAttribute.Issuer,
VCT: c.cfg.Issuer.JWTAttribute.VerifiableCredentialType,
CNF: c.jwkClaim,
}

if c.cfg.Issuer.JWTAttribute.EnableNotBefore {
Expand Down
2 changes: 1 addition & 1 deletion internal/issuer/apiv1/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c *Client) MakeSDJWT(ctx context.Context, req *CreateCredentialRequest) (*
instruction = c.ehicClient.sdjwt(ctx, doc)
}

signedCredential, err := c.sign(instruction)
signedCredential, err := c.sign(ctx, instruction)
if err != nil {
return nil, err
}
Expand Down
55 changes: 55 additions & 0 deletions internal/issuer/apiv1/jwk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package apiv1

import (
"context"
"encoding/json"
"time"

"github.com/golang-jwt/jwt/v5"
"github.com/lestrrat-go/jwx/jwk"
)

type jwkClaims struct {
CRV string `json:"crv"`
KID string `json:"kid"`
KTY string `json:"kty"`
X string `json:"x"`
Y string `json:"y"`
D string `json:"d"`
}

func (c *Client) createJWK(ctx context.Context) error {
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(2*time.Second))
defer cancel()

key, err := jwk.New(c.privateKey)
if err != nil {
return err
}

key.Set("kid", "singing_")

buf, err := json.MarshalIndent(key, "", " ")
if err != nil {
return err
}

j := &jwkClaims{}
if err := json.Unmarshal(buf, j); err != nil {
return err
}

c.jwkClaim = jwt.MapClaims{}

jwkClaim := jwt.MapClaims{
"crv": j.CRV,
"kid": j.KID,
"kty": j.KTY,
"x": j.X,
"y": j.Y,
"d": j.D,
}
c.jwkClaim["jwk"] = jwkClaim

return nil
}
125 changes: 125 additions & 0 deletions internal/issuer/apiv1/jwk_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package apiv1

import (
"bytes"
"context"
"crypto/ecdsa"
"crypto/elliptic"
"testing"
"vc/internal/issuer/auditlog"
"vc/pkg/logger"
"vc/pkg/model"
"vc/pkg/trace"

"github.com/golang-jwt/jwt/v5"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
)

var nonRandom = bytes.NewReader([]byte("01234567890123456789012345678901234567890123456789ABCDEF"))

func mockGenerateECDSAKey(t *testing.T) *ecdsa.PrivateKey {
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), nonRandom)
assert.NoError(t, err)

return privateKey
}

func TestGenereateECDSAKey(t *testing.T) {
tts := []struct {
name string
}{
{
name: "Test 1",
},
}

for _, tt := range tts {
t.Run(tt.name, func(t *testing.T) {
mockGenerateECDSAKey(t)
})
}
}

func mockClient(t *testing.T) *Client {
ctx := context.TODO()
cfg := &model.Cfg{
Common: model.Common{
HTTPProxy: "",
Production: false,
Log: model.Log{},
Mongo: model.Mongo{},
Tracing: model.OTEL{
Addr: "",
Type: "jaeger",
Timeout: 0,
},
Queues: model.Queues{},
KeyValue: model.KeyValue{},
QR: model.QRCfg{},
Kafka: model.Kafka{},
},
AuthenticSources: map[string]model.AuthenticSource{},
APIGW: model.APIGW{},
Issuer: model.Issuer{},
Verifier: model.Verifier{},
Datastore: model.Datastore{},
Registry: model.Registry{},
Persistent: model.Persistent{},
MockAS: model.MockAS{},
UI: model.UI{},
}

auditlog, err := auditlog.New(ctx, cfg, logger.NewSimple("testing_apiv1"))
assert.NoError(t, err)

tracer, err := trace.New(ctx, cfg, logger.NewSimple("testing_apiv1"), "projectName", "serviceName")
assert.NoError(t, err)

client := &Client{
cfg: cfg,
log: logger.NewSimple("testing_apiv1"),
tp: tracer,
auditLog: auditlog,
privateKey: mockGenerateECDSAKey(t),
}

client.createJWK(ctx)

return client
}

// Sometimes this test does not behave deterministically
func TestCreateJWK(t *testing.T) {
tts := []struct {
name string
want jwt.MapClaims
}{
{
name: "Test 1",
want: jwt.MapClaims{
"jwk": jwt.MapClaims{
"crv": "P-256",
"kid": "singing_",
"kty": "EC",
"d": "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI",
"x": "YiPlXIq3VAfGMMoVzAKB2wYLy0e5n9nYkjmAbBCIdBs",
"y": "d2P8TyUlmM1jop1yUH-fHBYXgbijF0IY4fPA7bQZuDE",
},
},
},
}

for _, tt := range tts {
t.Run(tt.name, func(t *testing.T) {
client := mockClient(t)

err := client.createJWK(context.Background())
assert.NoError(t, err)

if diff := cmp.Diff(tt.want, client.jwkClaim); diff != "" {
t.Errorf("MakeGatewayInfo() mismatch (-want +got):\n%s", diff)
}
})
}
}
9 changes: 1 addition & 8 deletions pkg/datastoreclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -60,8 +59,6 @@ func (c *Client) newRequest(ctx context.Context, method, path string, body any)
}
url := u.ResolveReference(rel)

fmt.Println("url", url.String())

var buf io.ReadWriter
if body != nil {
buf = new(bytes.Buffer)
Expand All @@ -76,8 +73,6 @@ func (c *Client) newRequest(ctx context.Context, method, path string, body any)
return nil, err
}

fmt.Println("req", req)

if body != nil {
req.Header.Set("Content-Type", "application/json")
}
Expand Down Expand Up @@ -112,7 +107,7 @@ func (c *Client) do(ctx context.Context, req *http.Request, reply any) (*http.Re
}

if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
fmt.Println("err", err)
c.log.Error(err, "failed to decode response")
return nil, err
}

Expand Down Expand Up @@ -148,7 +143,5 @@ func (c *Client) call(ctx context.Context, method, url string, body, reply any)
return resp, err
}

fmt.Println("reply", reply)

return resp, nil
}
Loading

0 comments on commit 1b3bddb

Please sign in to comment.