Skip to content

Commit

Permalink
feat: add proof.expires field to data integrity proof
Browse files Browse the repository at this point in the history
Signed-off-by: Misha Sizov <mykhailo.sizov@securekey.com>
  • Loading branch information
mishasizov-SK committed Dec 27, 2024
1 parent e7c4c51 commit a495257
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 50 deletions.
7 changes: 1 addition & 6 deletions dataintegrity/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestIntegration(t *testing.T) {
Purpose: AssertionMethod,
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
Expires: time.Now().Add(time.Hour),
}

signedCred, err := signer.AddProof(validCredential, signOpts)
Expand All @@ -103,7 +103,6 @@ func TestIntegration(t *testing.T) {
Purpose: AssertionMethod,
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
}

err = verifier.VerifyProof(signedCred, verifyOpts)
Expand All @@ -118,7 +117,6 @@ func TestIntegration(t *testing.T) {
Purpose: AssertionMethod,
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
}

signedCred, err := signer.AddProof(validCredential, signOpts)
Expand All @@ -130,7 +128,6 @@ func TestIntegration(t *testing.T) {
Purpose: AssertionMethod,
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
}

err = verifier.VerifyProof(signedCred, verifyOpts)
Expand All @@ -155,7 +152,6 @@ func TestIntegration(t *testing.T) {
SuiteType: ecdsa2019.SuiteType,
Purpose: AssertionMethod,
ProofType: models.DataIntegrityProof,
MaxAge: 100,
}

signedCred, err := signer.AddProof(validCredential, signOpts)
Expand All @@ -181,7 +177,6 @@ func TestIntegration(t *testing.T) {
SuiteType: ecdsa2019.SuiteType,
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
MaxAge: 100,
Created: time.Time{},
}

Expand Down
3 changes: 2 additions & 1 deletion dataintegrity/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Proof struct {
ProofPurpose string `json:"proofPurpose"`
VerificationMethod string `json:"verificationMethod"`
Created string `json:"created,omitempty"`
Expires string `json:"expires,omitempty"`
Domain string `json:"domain,omitempty"`
Challenge string `json:"challenge,omitempty"`
ProofValue string `json:"proofValue"`
Expand All @@ -56,7 +57,7 @@ type ProofOptions struct {
Domain string
Challenge string
Created time.Time
MaxAge int64
Expires time.Time // During verification process the value must be taken from Proof.Expires.
CustomFields map[string]interface{}
}

Expand Down
8 changes: 4 additions & 4 deletions dataintegrity/signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func TestSigner_AddProof(t *testing.T) {

t.Run("success", func(t *testing.T) {
createdTime := time.Now().Format(models.DateTimeFormat)
expiresTime := time.Now().Add(time.Minute).Format(models.DateTimeFormat)

s, err := NewSigner(
&Options{
Expand All @@ -77,6 +78,7 @@ func TestSigner_AddProof(t *testing.T) {
Domain: "mock-domain",
Challenge: "mock-challenge",
Created: createdTime,
Expires: expiresTime,
},
},
typeStr: mockSuiteType,
Expand All @@ -89,7 +91,6 @@ func TestSigner_AddProof(t *testing.T) {
VerificationMethodID: "did:foo:bar#key-1",
Domain: "mock-domain",
Challenge: "mock-challenge",
MaxAge: 1000,
Purpose: Authentication,
})
require.NoError(t, err)
Expand All @@ -100,9 +101,10 @@ func TestSigner_AddProof(t *testing.T) {
"verificationMethod":"mock-vm",
"proofValue":"",
"created": "%s",
"expires": "%s",
"domain": "mock-domain",
"challenge":"mock-challenge"
}`, Authentication, createdTime))
}`, Authentication, createdTime, expiresTime))

proofBytes, unsignedDoc := extractProof(t, signedDoc)

Expand Down Expand Up @@ -157,7 +159,6 @@ func TestSigner_AddProof(t *testing.T) {
SuiteType: mockSuiteType,
Domain: "mock-domain",
Challenge: "mock-challenge",
MaxAge: 1000,
})
require.ErrorIs(t, err, ErrNoResolver)
})
Expand Down Expand Up @@ -193,7 +194,6 @@ func TestSigner_AddProof(t *testing.T) {
Purpose: CapabilityDelegation,
Domain: "mock-domain",
Challenge: "mock-challenge",
MaxAge: 1000,
})
require.ErrorIs(t, err, errExpected)
require.ErrorIs(t, err, ErrVMResolution)
Expand Down
12 changes: 11 additions & 1 deletion dataintegrity/suite/ecdsa2019/ecdsa2019.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ func (s *Suite) CreateProof(doc []byte, opts *models.ProofOptions) (*models.Proo
return nil, err
}

var expires string
if !opts.Expires.IsZero() {
expires = opts.Expires.Format(models.DateTimeFormat)
}

p := &models.Proof{
Type: models.DataIntegrityProof,
CryptoSuite: opts.SuiteType,
Expand All @@ -215,6 +220,7 @@ func (s *Suite) CreateProof(doc []byte, opts *models.ProofOptions) (*models.Proo
VerificationMethod: opts.VerificationMethod.ID,
ProofValue: sigStr,
Created: opts.Created.Format(models.DateTimeFormat),
Expires: expires,
}

return p, nil
Expand Down Expand Up @@ -322,7 +328,7 @@ func (s *Suite) transformAndHash(doc []byte, opts *models.ProofOptions) ([]byte,

confData := proofConfig(docData[ldCtxKey], opts)

if opts.ProofType != "DataIntegrityProof" || (opts.SuiteType != SuiteType && opts.SuiteType != SuiteTypeNew) {
if opts.ProofType != models.DataIntegrityProof || (opts.SuiteType != SuiteType && opts.SuiteType != SuiteTypeNew) {
return nil, nil, nil, suite.ErrProofTransformation
}

Expand Down Expand Up @@ -406,6 +412,10 @@ func proofConfig(docCtx interface{}, opts *models.ProofOptions) map[string]inter
proof["created"] = opts.Created.Format(models.DateTimeFormat)
}

if !opts.Expires.IsZero() {
proof["expires"] = opts.Expires.Format(models.DateTimeFormat)
}

if opts.Challenge != "" {
proof["challenge"] = opts.Challenge
}
Expand Down
6 changes: 4 additions & 2 deletions dataintegrity/suite/ecdsa2019/ecdsa2019_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func successCase(t *testing.T) *testCase {
signer := &mockwrapper.MockKMSCrypto{}

proofCreated := time.Now()
proofExpires := proofCreated.Add(time.Hour)

proofOpts := &models.ProofOptions{
VerificationMethod: mockVM,
Expand All @@ -106,7 +107,7 @@ func successCase(t *testing.T) *testCase {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: proofCreated,
MaxAge: 100,
Expires: proofExpires,
}

mockSig, err := multibase.Encode(multibase.Base58BTC, []byte("mock signature"))
Expand All @@ -118,6 +119,7 @@ func successCase(t *testing.T) *testCase {
ProofPurpose: "assertionMethod",
VerificationMethod: mockVM.ID,
Created: proofCreated.Format(models.DateTimeFormat),
Expires: proofExpires.Format(models.DateTimeFormat),
ProofValue: mockSig,
}

Expand Down Expand Up @@ -279,7 +281,7 @@ func TestSharedFailures(t *testing.T) {

testSign(t, tc)
})

t.Run("unsupported ECDSA curve", func(t *testing.T) {
tc := successCase(t)

Expand Down
7 changes: 3 additions & 4 deletions dataintegrity/suite/ecdsa2019/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestIntegration(t *testing.T) {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
Expires: time.Now().Add(time.Minute),
}

proof, err := signer.CreateProof(validCredential, proofOpts)
Expand All @@ -80,7 +80,7 @@ func TestIntegration(t *testing.T) {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
Expires: time.Now().Add(time.Minute),
}

proof, err := signer.CreateProof(validCredential, proofOpts)
Expand All @@ -100,7 +100,7 @@ func TestIntegration(t *testing.T) {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
Expires: time.Now().Add(time.Minute),
}

proof, err := signer.CreateProof(validCredential, proofOpts)
Expand Down Expand Up @@ -128,7 +128,6 @@ func TestIntegration(t *testing.T) {
SuiteType: SuiteType,
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
MaxAge: 100,
}

proof, err := signer.CreateProof(validCredential, signOpts)
Expand Down
12 changes: 11 additions & 1 deletion dataintegrity/suite/eddsa2022/eddsa2022.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ func (s *Suite) CreateProof(doc []byte, opts *models.ProofOptions) (*models.Proo
return nil, err
}

var expires string
if !opts.Expires.IsZero() {
expires = opts.Expires.Format(models.DateTimeFormat)
}

p := &models.Proof{
Type: models.DataIntegrityProof,
CryptoSuite: SuiteType,
Expand All @@ -198,6 +203,7 @@ func (s *Suite) CreateProof(doc []byte, opts *models.ProofOptions) (*models.Proo
VerificationMethod: opts.VerificationMethod.ID,
ProofValue: sigStr,
Created: opts.Created.Format(models.DateTimeFormat),
Expires: expires,
}

return p, nil
Expand Down Expand Up @@ -234,7 +240,7 @@ func (s *Suite) transformAndHash(doc []byte, opts *models.ProofOptions) ([]byte,

confData := proofConfig(docData[ldCtxKey], opts)

if opts.ProofType != "DataIntegrityProof" || (opts.SuiteType != SuiteType &&
if opts.ProofType != models.DataIntegrityProof || (opts.SuiteType != SuiteType &&
opts.SuiteType != SuiteType2) {
return nil, nil, nil, suite.ErrProofTransformation
}
Expand Down Expand Up @@ -318,6 +324,10 @@ func proofConfig(docCtx interface{}, opts *models.ProofOptions) map[string]inter
proof["created"] = opts.Created.Format(models.DateTimeFormat)
}

if !opts.Expires.IsZero() {
proof["expires"] = opts.Expires.Format(models.DateTimeFormat)
}

if opts.Challenge != "" {
proof["challenge"] = opts.Challenge
}
Expand Down
4 changes: 3 additions & 1 deletion dataintegrity/suite/eddsa2022/eddsa2022_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func successCase(t *testing.T) *testCase {
signer := &mockwrapper.MockKMSCrypto{}

proofCreated := time.Now()
proofExpires := proofCreated.Add(time.Hour)

proofOpts := &models.ProofOptions{
VerificationMethod: mockVM,
Expand All @@ -96,7 +97,7 @@ func successCase(t *testing.T) *testCase {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: proofCreated,
MaxAge: 100,
Expires: proofExpires,
}

mockSig, err := multibase.Encode(multibase.Base58BTC, []byte("mock signature"))
Expand All @@ -108,6 +109,7 @@ func successCase(t *testing.T) *testCase {
ProofPurpose: "assertionMethod",
VerificationMethod: mockVM.ID,
Created: proofCreated.Format(models.DateTimeFormat),
Expires: proofExpires.Format(models.DateTimeFormat),
ProofValue: mockSig,
}

Expand Down
4 changes: 2 additions & 2 deletions dataintegrity/suite/eddsa2022/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestIntegration(t *testing.T) {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: time.Now(),
MaxAge: 100,
Expires: time.Now().Add(time.Minute),
}

proof, err := signer.CreateProof(validCredential, proofOpts)
Expand All @@ -85,6 +85,7 @@ func TestIntegration(t *testing.T) {
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
Created: time.Now(),
Expires: time.Now().Add(time.Minute),
}

verifyOpts := &models.ProofOptions{
Expand All @@ -93,7 +94,6 @@ func TestIntegration(t *testing.T) {
SuiteType: SuiteType,
Purpose: "assertionMethod",
ProofType: models.DataIntegrityProof,
MaxAge: 100,
}

proof, err := signer.CreateProof(validCredential, signOpts)
Expand Down
32 changes: 15 additions & 17 deletions dataintegrity/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,21 @@ func (v *Verifier) verifyProof( // nolint:funlen,gocyclo
opts.Created = parsedCreatedTime
}

if proof.Expires != "" {
var parsedExpiresTime time.Time

parsedExpiresTime, err = time.Parse(models.DateTimeFormat, proof.Expires)
if err != nil {
return ErrMalformedProof
}

if time.Now().After(parsedExpiresTime) {
return ErrOutOfDate
}

opts.Expires = parsedExpiresTime
}

if proof.ProofPurpose != opts.Purpose {
return ErrMismatchedPurpose
}
Expand All @@ -163,23 +178,6 @@ func (v *Verifier) verifyProof( // nolint:funlen,gocyclo

verifyResult := verifierSuite.VerifyProof(unsecuredDoc, proof, opts)

if proof.Created != "" {
createdTime, err := time.Parse(models.DateTimeFormat, proof.Created)
if err != nil {
return ErrMalformedProof
}

if opts.MaxAge > 0 {
now := time.Now()

diff := now.Sub(createdTime)

if diff > time.Second*time.Duration(opts.MaxAge) {
return ErrOutOfDate
}
}
}

if opts.Domain != "" && opts.Domain != proof.Domain {
return ErrInvalidDomain
}
Expand Down
Loading

0 comments on commit a495257

Please sign in to comment.