Commit c8509831 authored by Sietse Ringers's avatar Sietse Ringers

feat: support nonrevocation proofs in attribute based signatures

parent 416c3097
package sessiontest package sessiontest
import ( import (
"encoding/json"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv" "strconv"
...@@ -46,7 +47,7 @@ func TestRevocationAll(t *testing.T) { ...@@ -46,7 +47,7 @@ func TestRevocationAll(t *testing.T) {
// perform disclosure session (of cred1) with nonrevocation proof // perform disclosure session (of cred1) with nonrevocation proof
logger.Info("step 1") logger.Info("step 1")
result = revocationSession(t, client) result = revocationSession(t, client, nil)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
require.NotEmpty(t, result.Disclosed) require.NotEmpty(t, result.Disclosed)
...@@ -57,7 +58,7 @@ func TestRevocationAll(t *testing.T) { ...@@ -57,7 +58,7 @@ func TestRevocationAll(t *testing.T) {
// perform another disclosure session with nonrevocation proof to see that cred1 still works // perform another disclosure session with nonrevocation proof to see that cred1 still works
// client updates its witness to the new accumulator first // client updates its witness to the new accumulator first
logger.Info("step 3") logger.Info("step 3")
result = revocationSession(t, client) result = revocationSession(t, client, nil)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
require.NotEmpty(t, result.Disclosed) require.NotEmpty(t, result.Disclosed)
...@@ -68,7 +69,7 @@ func TestRevocationAll(t *testing.T) { ...@@ -68,7 +69,7 @@ func TestRevocationAll(t *testing.T) {
// try to perform session with revoked credential // try to perform session with revoked credential
// client notices that his credential is revoked and aborts // client notices that his credential is revoked and aborts
logger.Info("step 5") logger.Info("step 5")
result = revocationSession(t, client, sessionOptionIgnoreClientError) result = revocationSession(t, client, nil, sessionOptionIgnoreClientError)
require.Equal(t, server.StatusCancelled, result.Status) require.Equal(t, server.StatusCancelled, result.Status)
// client revocation callback was called // client revocation callback was called
require.NotNil(t, handler.(*TestClientHandler).revoked) require.NotNil(t, handler.(*TestClientHandler).revoked)
...@@ -79,6 +80,52 @@ func TestRevocationAll(t *testing.T) { ...@@ -79,6 +80,52 @@ func TestRevocationAll(t *testing.T) {
require.NotEmpty(t, missing) require.NotEmpty(t, missing)
}) })
t.Run("AttributeBasedSignature", func(t *testing.T) {
defer test.ClearTestStorage(t)
client, _ := revocationSetup(t)
request := revocationSigRequest()
result := revocationSession(t, client, request)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
require.NotEmpty(t, result.Disclosed)
require.NotNil(t, result.Signature)
_, status, err := result.Signature.Verify(client.Configuration, request)
require.NoError(t, err)
require.Equal(t, irma.ProofStatusValid, status)
_, status, err = result.Signature.Verify(client.Configuration, nil)
require.NoError(t, err)
require.Equal(t, irma.ProofStatusValid, status)
})
t.Run("VerifyAttributeBasedSignature", func(t *testing.T) {
client, _ := parseStorage(t)
defer test.ClearTestStorage(t)
j := `{"@context":"https://irma.app/ld/signature/v2","signature":[{"c":"e2nKrqit2VU+dSMrgZeUzVTuf8NQ0MPWrjCSW9ZmJYk=","A":"b2/DBvaqnmd346EEvSKu8zDqSDukEHutZdE14HnmljLsVy8DI93gjH0Udsc+p4Sj2AO8x6vjtrXSVptncMsE4tz+7m8euDfH6tdggAd07p5wRxXJCOg/EQpC750QJU3Z30rNkjDv5ajA4stLaKtGs92TFJ0S676PlbYfUHS0QHg=","e_response":"Sfwy53PSeEmBiJJxMU3qqm/z+8klQoRhHYhRqs6gJeGlUUMeQFxzdNC/P9PmzK8wOvpGwTjw7MgY","v_response":"Dj36QVCjaZACzUGckLJWNSJibCGN6xtgt5gDrFQw2yuQmxNm+SFpfK9Pe/REozkHOV5raqynEZG+CX7zGmjEp2M8AoKdgoDc3hsDpyUfOmRVcszJikljWB+gd1HCiJYDruzif1Ar2XElP1Z0ehHjZl504wVabVR3VfuRawRel/jvuhHbnxEgmRrj7AseQdwgUU9t/Qnq1538Uaa0crjJbO8YpEE6zcs/UP1uRZJ93rBhlMo9ui2idPCtaiUYlELAsLEHK2Kjw19F2t2ffa2Iv0NRR5MlDXNjFOLJEbLovrylSs/kihC9eOzF+JopUh6qtcZ7NDgaVSDN2giZA8J+","a_responses":{"0":"JRsR9U7nyK6vjEJ1IbIc3tObCXVksaoqDbmLkTKXLMgysTw3CSQLWWiPLu6mK2/czfY2JtT/c09jhxsvWt4lqVs72WoPKpNhVMQ="},"nonrev_response":"B0M4FYrv3jergGlsiFQqXJ7VCfdM8gJG2q5bydFfs9Raw8FCuHDKjgFWaAn+OF7T7gdZ5tlBs6CgT6HdhLIucadOSbbQE+J87Q==","nonrev_proof":{"C_r":"G0A1Tz6jB1mEJJJp5/4Vk8B4JFWHztqspKa8Mn7IkzaJPBi6xKqIcvEj6JupoZOTgqrIOoZLKE2FzOt9zmgqWyEy+mZPchAEXDka5LB02o2Yals+zu4tDoINgOIjiSOXpByEJogGTkTUJxwv4Ug494nBf669QpeUKXiqFSD4hog=","C_u":"FknWq3GdaetxuMiC+hcgf/tb9MRy9lYR+ha4RwHdOOtzDwkGio4vSDV9WB4KcrRrdMfwMQ82doiAKlAKhMd4KCIx4g2S3lC8zuODx+SbgtbJKA+6UZ8n1jRqYFvGH9+BZWQbegVu8QZlbJUUsFciEszHjwkv0ac0QmkZajTybjU=","responses":{"beta":"ATdypWmAGl9U/JHtBupMcukq6J4641TDkUkGnLdphd/t5cVp6suEC7MXAoi+a+gZxKPuRyCqz/MB6rURmRR3l4oCuEbGVEcGqPxbCEWGx7vA3DTm1AVjohNEbLRu/xHGzW8kNEt/fzf0reU65eYneoEvFIYLxOd46hsK0ppfZn8hU5+umn8NiyMRr7GfH8/qmKrv7Ul62qVlvXJDKNhVbwBQToohT2xvPikLRVI4ZWWKuoUHqatenRzBfZyhyv14TG7ybVDA4X3+","delta":"ASQwxh5OZbSDunGm5HPVW8494idgYikMyC8400NT1Z+IIEWO3u8lS6rWO7rNF9SazLV9luP0Mw2qKmjP2eMHmdN5W9v5LnPAWHut0iAAnQhAymyYUFbQtka1Q2jAx3MnET9BqgE0AUZ3RmDmysv4BckkY8pyvY/rYD/rlG5KgtkZap5tniadWQu8w7ulsMJDbjc7YudlOw1hXaY64TZP34vX6EHSaa3vYy6+sA6RYD0OeshO6wQO9i87+Z1QIEiZBU2aeNdlEknK","epsilon":"Gmw3aqtwbEZrJ/ej9YdD1IE08DG8KjrIP7nmYZKVfwTexAb3mqrlrue7rXR3gfMeufIUmTZeIAkKTw4UcUBKaposc3NaOo8e+kmK0kZ9biLMC53bHZ36KZWrT5h20hwtcmMq4FG8NDh/o8lb2Ibbv8mf71opJyyVUUoEqIatZh1pVYvLVdi9Vxwc1P7tHrJQ8e9ppDqVHkVFYGNfVNGW3RXLKHr/tMsLbUIP9DjVY7M=","zeta":"BKdrESBubE/eKZ1m0eVY5VT5tYrbKA6ArB1o68PV1sMu8IhhOw745zv5KbIH56k/5+JJXv5Hyx3lY3qgI1w+h+w+/G+So7EzhXw4pqFkZy29Seq0xQM/Su6FMMC97auV3hRYX2VAaf+Qc2mb02cDMbKeX92p6+R6wj0KN/1Wel1IHb1GgMOvIURHddROJCpQI23MEU+uxJOb8TZQY/ICM2QFax/rd7FIawdGXnwYXY4="},"sacc":{"data":"omNNc2dYxaRiTnVYgFrKyTR/bZDCSwK1Kg9nNIdIkxX+/PkQAK6FaOT9YFAcEcG+rYqhdfVRWohl2KeBV8Fa1o8AfZ/MbvXcPiTh91p6PNX5OVBFHIGC5GDkLo9MMot6rJ/UZrtmhrhGHzX8c5Gf7xa01XB5MCZGjLKq6AbxTabyWedkhZpdnDN5Y5nSZUluZGV4AWRUaW1lGl4guwxpRXZlbnRIYXNoWCISIOeNpEe8g6DBBYWG1BJ4uA2tJGSt9etirxuxm+/R5W27Y1NpZ1hHMEUCIBNGB6X96tm/zyF9IaHiGt4WqISi+WK0DEEaq0iIEbRgAiEAxg/WLqsO8Aeis/B2embcwy5dBNNShLcMC2CKzIz9w6U=","pk":2}},"a_disclosed":{"1":"AwAKMwAaAAIIuOcAMwFiUVy4Y5PtnTFG","2":"ZHJybnJkaGpx"}}],"indices":[[{"cred":0,"attr":2}]],"nonce":"aXxcuAXX4c0qlD7rsgfsCw==","context":"AQ==","message":"message","timestamp":{"Time":1579203344,"ServerUrl":"https://keyshare.privacybydesign.foundation/atumd","Sig":{"Alg":"ed25519","Data":"6+RHBJ8SUjQu8UNVvVRntUnW7dPCWTbv5N5lC9lGsbcKj4NYMTiyKkD8Vp3c1170ZcWVDH4yIuabIaOJNDAFAw==","PublicKey":"MKdXxJxEWPRIwNP7SuvP0J/M/NV51VZvqCyO+7eDwJ8="}}}`
sig := &irma.SignedMessage{}
require.NoError(t, json.Unmarshal([]byte(j), sig))
_, status, err := sig.Verify(client.Configuration, nil)
require.NoError(t, err)
require.Equal(t, irma.ProofStatusValid, status)
})
t.Run("UpdateAccumulatorTime", func(t *testing.T) {
startRevocationServer(t)
cred := irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root")
_, acc, err := revocationConfiguration.IrmaConfiguration.Revocation.Accumulator(cred, 2)
require.NoError(t, err)
tme := acc.Time
time.Sleep(time.Second)
revocationConfiguration.IrmaConfiguration.Scheduler.RunAll()
_, acc, err = revocationConfiguration.IrmaConfiguration.Revocation.Accumulator(cred, 2)
require.NoError(t, err)
require.NotEqual(t, tme, acc.Time)
})
t.Run("OtherAccumulator", func(t *testing.T) { t.Run("OtherAccumulator", func(t *testing.T) {
defer test.ClearTestStorage(t) defer test.ClearTestStorage(t)
attr := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN") attr := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN")
...@@ -97,7 +144,7 @@ func TestRevocationAll(t *testing.T) { ...@@ -97,7 +144,7 @@ func TestRevocationAll(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Prepare session request // Prepare session request
request := revocationRequest().(*irma.DisclosureRequest) request := revocationRequest()
require.NoError(t, revocationConfiguration.IrmaConfiguration.Revocation.SetRevocationUpdates(request.Base())) require.NoError(t, revocationConfiguration.IrmaConfiguration.Revocation.SetRevocationUpdates(request.Base()))
events := request.RevocationUpdates[cred][2].Events events := request.RevocationUpdates[cred][2].Events
require.Equal(t, uint64(1), events[len(events)-1].Index) require.Equal(t, uint64(1), events[len(events)-1].Index)
...@@ -122,13 +169,13 @@ func TestRevocationAll(t *testing.T) { ...@@ -122,13 +169,13 @@ func TestRevocationAll(t *testing.T) {
// Try to verify against updated session request // Try to verify against updated session request
_, status, err := disclosure.Verify(client.Configuration, request) _, status, err := disclosure.Verify(client.Configuration, request)
require.Error(t, err) require.NoError(t, err)
require.Equal(t, irma.ProofStatusInvalid, status) require.Equal(t, irma.ProofStatusInvalid, status)
// Revoke another bogus credential, advancing index to 3, and make a new disclosure request // Revoke another bogus credential, advancing index to 3, and make a new disclosure request
// requiring a nonrevocation proof against the accumulator with index 3 // requiring a nonrevocation proof against the accumulator with index 3
revoke(t, "3", conf, cred, acc) revoke(t, "3", conf, cred, acc)
newrequest := revocationRequest().(*irma.DisclosureRequest) newrequest := revocationRequest()
require.NoError(t, conf.SetRevocationUpdates(newrequest.Base())) require.NoError(t, conf.SetRevocationUpdates(newrequest.Base()))
events = newrequest.RevocationUpdates[cred][2].Events events = newrequest.RevocationUpdates[cred][2].Events
require.Equal(t, uint64(3), events[len(events)-1].Index) require.Equal(t, uint64(3), events[len(events)-1].Index)
...@@ -147,6 +194,17 @@ func TestRevocationAll(t *testing.T) { ...@@ -147,6 +194,17 @@ func TestRevocationAll(t *testing.T) {
_, status, err = disclosure.Verify(client.Configuration, request) _, status, err = disclosure.Verify(client.Configuration, request)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, irma.ProofStatusValid, status) require.Equal(t, irma.ProofStatusValid, status)
// If the client does not send a nonrevocation proof the proof is invalid
// clear revocation data from newrequest and create a disclosure from it
newrequest.Revocation = nil
newrequest.RevocationUpdates = nil
disclosure, _, err = client.Proofs(choice, newrequest)
require.NoError(t, err)
// verify disclosure against request that still requests nonrevocation proofs
_, status, err = disclosure.Verify(client.Configuration, request)
require.NoError(t, err)
require.Equal(t, irma.ProofStatusInvalid, status)
}) })
t.Run("ClientUpdate", func(t *testing.T) { t.Run("ClientUpdate", func(t *testing.T) {
...@@ -173,7 +231,7 @@ func TestRevocationAll(t *testing.T) { ...@@ -173,7 +231,7 @@ func TestRevocationAll(t *testing.T) {
revoke(t, key, conf, cred, acc) revoke(t, key, conf, cred, acc)
} }
result := revocationSession(t, client) result := revocationSession(t, client, nil)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
require.NotEmpty(t, result.Disclosed) require.NotEmpty(t, result.Disclosed)
}) })
...@@ -190,7 +248,7 @@ func TestRevocationAll(t *testing.T) { ...@@ -190,7 +248,7 @@ func TestRevocationAll(t *testing.T) {
require.NoError(t, revocationConfiguration.IrmaConfiguration.Revocation.Close()) require.NoError(t, revocationConfiguration.IrmaConfiguration.Revocation.Close())
// do disclosure session, using irmaServer's memdb // do disclosure session, using irmaServer's memdb
result := revocationSession(t, client, sessionOptionReuseServer) result := revocationSession(t, client, nil, sessionOptionReuseServer)
require.Equal(t, irma.ProofStatusValid, result.ProofStatus) require.Equal(t, irma.ProofStatusValid, result.ProofStatus)
require.NotEmpty(t, result.Disclosed) require.NotEmpty(t, result.Disclosed)
}) })
...@@ -198,15 +256,25 @@ func TestRevocationAll(t *testing.T) { ...@@ -198,15 +256,25 @@ func TestRevocationAll(t *testing.T) {
// Helper functions // Helper functions
func revocationRequest() irma.SessionRequest { func revocationSigRequest() *irma.SignatureRequest {
attr := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN")
req := irma.NewSignatureRequest("message", attr)
req.Revocation = []irma.CredentialTypeIdentifier{attr.CredentialTypeIdentifier()}
return req
}
func revocationRequest() *irma.DisclosureRequest {
attr := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN") attr := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN")
req := irma.NewDisclosureRequest(attr) req := irma.NewDisclosureRequest(attr)
req.Revocation = []irma.CredentialTypeIdentifier{attr.CredentialTypeIdentifier()} req.Revocation = []irma.CredentialTypeIdentifier{attr.CredentialTypeIdentifier()}
return req return req
} }
func revocationSession(t *testing.T, client *irmaclient.Client, options ...sessionOption) *requestorSessionResult { func revocationSession(t *testing.T, client *irmaclient.Client, request irma.SessionRequest, options ...sessionOption) *requestorSessionResult {
result := requestorSessionHelper(t, revocationRequest(), client, options...) if request == nil {
request = revocationRequest()
}
result := requestorSessionHelper(t, request, client, options...)
require.Nil(t, result.Err) require.Nil(t, result.Err)
return result return result
} }
......
...@@ -133,6 +133,8 @@ func NewConfiguration(path string, opts ConfigurationOptions) (conf *Configurati ...@@ -133,6 +133,8 @@ func NewConfiguration(path string, opts ConfigurationOptions) (conf *Configurati
assets: opts.Assets, assets: opts.Assets,
readOnly: opts.ReadOnly, readOnly: opts.ReadOnly,
} }
conf.Scheduler = gocron.NewScheduler()
conf.Scheduler.Start()
conf.Revocation = &RevocationStorage{conf: conf} conf.Revocation = &RevocationStorage{conf: conf}
if err = conf.Revocation.Load( if err = conf.Revocation.Load(
Logger.IsLevelEnabled(logrus.DebugLevel), Logger.IsLevelEnabled(logrus.DebugLevel),
...@@ -155,9 +157,6 @@ func NewConfiguration(path string, opts ConfigurationOptions) (conf *Configurati ...@@ -155,9 +157,6 @@ func NewConfiguration(path string, opts ConfigurationOptions) (conf *Configurati
// Init all maps // Init all maps
conf.clear() conf.clear()
conf.Scheduler = gocron.NewScheduler()
conf.Scheduler.Start()
return return
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/fxamacker/cbor" "github.com/fxamacker/cbor"
"github.com/getsentry/raven-go"
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
...@@ -96,12 +97,6 @@ type ( ...@@ -96,12 +97,6 @@ type (
ValidUntil int64 ValidUntil int64
RevokedAt int64 `json:",omitempty"` // 0 if not currently revoked RevokedAt int64 `json:",omitempty"` // 0 if not currently revoked
} }
// TODO
TimeRecord struct {
Index uint64
Start, End int64
}
) )
const ( const (
...@@ -133,6 +128,10 @@ const ( ...@@ -133,6 +128,10 @@ const (
// latest accumulator that we know is still the latest one: clients should prove nonrevocation // latest accumulator that we know is still the latest one: clients should prove nonrevocation
// against a 'younger' accumulator. // against a 'younger' accumulator.
revocationMaxAccumulatorAge uint = 5 * 60 revocationMaxAccumulatorAge uint = 5 * 60
// If server mode is enabled for a credential type, then once every so many seconds
// the timestamp in each accumulator is updated to now.
revocationAccumulatorUpdateInterval uint64 = 10
) )
// EnableRevocation creates an initial accumulator for a given credential type. This function is the // EnableRevocation creates an initial accumulator for a given credential type. This function is the
...@@ -182,7 +181,7 @@ func (rs *RevocationStorage) UpdateFrom(typ CredentialTypeIdentifier, pkcounter ...@@ -182,7 +181,7 @@ func (rs *RevocationStorage) UpdateFrom(typ CredentialTypeIdentifier, pkcounter
return err return err
} }
var events []*EventRecord var events []*EventRecord
if err := tx.From(&events, "cred_type = ? and pk_counter = ? and eventindex >= ?", typ, pkcounter, index); err != nil { if err := tx.Find(&events, "cred_type = ? and pk_counter = ? and eventindex >= ?", typ, pkcounter, index); err != nil {
return err return err
} }
update = rs.newUpdate(acc, events) update = rs.newUpdate(acc, events)
...@@ -465,15 +464,51 @@ func (rs *RevocationStorage) SaveIssuanceRecord(typ CredentialTypeIdentifier, re ...@@ -465,15 +464,51 @@ func (rs *RevocationStorage) SaveIssuanceRecord(typ CredentialTypeIdentifier, re
// Misscelaneous methods // Misscelaneous methods
func (rs *RevocationStorage) updateAccumulatorTimes(types []CredentialTypeIdentifier) error {
return rs.db.Transaction(func(tx revStorage) error {
var err error
var records []AccumulatorRecord
Logger.Tracef("updating accumulator times")
if err = tx.Find(&records, "cred_type in (?)", types); err != nil {
return err
}
for _, r := range records {
pk, err := rs.Keys.PublicKey(r.CredType.IssuerIdentifier(), r.PKCounter)
if err != nil {
return err
}
sk, err := rs.Keys.PrivateKey(r.CredType.IssuerIdentifier(), r.PKCounter)
if err != nil {
return err
}
acc, err := r.SignedAccumulator().UnmarshalVerify(pk)
if err != nil {
return err
}
acc.Time = time.Now().Unix()
sacc, err := acc.Sign(sk)
if err != nil {
return err
}
r.Data = signedMessage(sacc.Data)
if err = tx.Save(r); err != nil {
return err
}
}
return nil
})
}
func (rs *RevocationStorage) Load(debug bool, dbtype, connstr string, settings map[CredentialTypeIdentifier]*RevocationSetting) error { func (rs *RevocationStorage) Load(debug bool, dbtype, connstr string, settings map[CredentialTypeIdentifier]*RevocationSetting) error {
var t *CredentialTypeIdentifier var t *CredentialTypeIdentifier
var ourtypes []CredentialTypeIdentifier
for typ, s := range settings { for typ, s := range settings {
switch s.Mode { switch s.Mode {
case RevocationModeServer: case RevocationModeServer:
if s.ServerURL != "" { if s.ServerURL != "" {
return errors.New("server_url cannot be combined with server mode") return errors.New("server_url cannot be combined with server mode")
} }
ourtypes = append(ourtypes, typ)
t = &typ t = &typ
case RevocationModeProxy: case RevocationModeProxy:
t = &typ t = &typ
...@@ -487,6 +522,15 @@ func (rs *RevocationStorage) Load(debug bool, dbtype, connstr string, settings m ...@@ -487,6 +522,15 @@ func (rs *RevocationStorage) Load(debug bool, dbtype, connstr string, settings m
return errors.Errorf("revocation mode for %s requires SQL database but no connection string given", *t) return errors.Errorf("revocation mode for %s requires SQL database but no connection string given", *t)
} }
if len(ourtypes) > 0 {
rs.conf.Scheduler.Every(revocationAccumulatorUpdateInterval).Seconds().Do(func() {
if err := rs.updateAccumulatorTimes(ourtypes); err != nil {
err = errors.WrapPrefix(err, "failed to write updated accumulator record", 0)
raven.CaptureError(err, nil)
}
})
}
if connstr == "" { if connstr == "" {
Logger.Trace("Using memory revocation database") Logger.Trace("Using memory revocation database")
rs.memdb = newMemStorage() rs.memdb = newMemStorage()
......
...@@ -22,8 +22,8 @@ type ( ...@@ -22,8 +22,8 @@ type (
Last(dest interface{}, query interface{}, args ...interface{}) error Last(dest interface{}, query interface{}, args ...interface{}) error
// Exists checks whether records exist satisfying col = key. // Exists checks whether records exist satisfying col = key.
Exists(typ interface{}, query interface{}, args ...interface{}) (bool, error) Exists(typ interface{}, query interface{}, args ...interface{}) (bool, error)
// From deserializes into o all records where col >= key. // Find deserializes into o all records satisfying the specified query.
From(dest interface{}, query interface{}, args ...interface{}) error Find(dest interface{}, query interface{}, args ...interface{}) error
// Latest deserializes into o the last items; amount specified by count, ordered by col. // Latest deserializes into o the last items; amount specified by count, ordered by col.
Latest(dest interface{}, count uint64, query interface{}, args ...interface{}) error Latest(dest interface{}, count uint64, query interface{}, args ...interface{}) error
// Close the database. // Close the database.
...@@ -125,7 +125,7 @@ func (s sqlRevStorage) Exists(typ interface{}, query interface{}, args ...interf ...@@ -125,7 +125,7 @@ func (s sqlRevStorage) Exists(typ interface{}, query interface{}, args ...interf
return c > 0, db.Error return c > 0, db.Error
} }
func (s sqlRevStorage) From(dest interface{}, query interface{}, args ...interface{}) error { func (s sqlRevStorage) Find(dest interface{}, query interface{}, args ...interface{}) error {
return s.gorm. return s.gorm.
Where(query, args...). Where(query, args...).
Set("gorm:order_by_primary_key", "ASC"). Set("gorm:order_by_primary_key", "ASC").
......
...@@ -112,6 +112,7 @@ func (pl ProofList) VerifyProofs( ...@@ -112,6 +112,7 @@ func (pl ProofList) VerifyProofs(
context *big.Int, nonce *big.Int, context *big.Int, nonce *big.Int,
publickeys []*gabi.PublicKey, publickeys []*gabi.PublicKey,
revRecords map[CredentialTypeIdentifier]map[uint]*revocation.Update, revRecords map[CredentialTypeIdentifier]map[uint]*revocation.Update,
validAt *time.Time,
isSig bool, isSig bool,
) (bool, map[int]*time.Time, error) { ) (bool, map[int]*time.Time, error) {
// Empty proof lists are allowed (if consistent with the session request, which is checked elsewhere) // Empty proof lists are allowed (if consistent with the session request, which is checked elsewhere)
...@@ -175,17 +176,16 @@ func (pl ProofList) VerifyProofs( ...@@ -175,17 +176,16 @@ func (pl ProofList) VerifyProofs(
// the last one in the update message set we provided along with the session request, // the last one in the update message set we provided along with the session request,
// OR a newer one included in the proofs itself. // OR a newer one included in the proofs itself.
updates := revRecords[id] updates := revRecords[id]
if updates == nil { // no nonrevocation proof was requested for this credential
return true, nil, nil
}
if !proofd.HasNonRevocationProof() { if !proofd.HasNonRevocationProof() {
return false, nil, nil if updates != nil {
// no nonrevocation proof is included but one was required in the session request
return false, nil, nil
} else {
continue
}
} }
sig := proofd.NonRevocationProof.SignedAccumulator sig := proofd.NonRevocationProof.SignedAccumulator
u := updates[sig.PKCounter]
if u == nil {
return false, nil, errors.Errorf("nonrevocation proof used unknown public key %d", sig.PKCounter)
}
pk, err := RevocationKeys{configuration}.PublicKey(typ.IssuerIdentifier(), sig.PKCounter) pk, err := RevocationKeys{configuration}.PublicKey(typ.IssuerIdentifier(), sig.PKCounter)
if err != nil { if err != nil {
return false, nil, nil return false, nil, nil
...@@ -195,16 +195,28 @@ func (pl ProofList) VerifyProofs( ...@@ -195,16 +195,28 @@ func (pl ProofList) VerifyProofs(
return false, nil, nil return false, nil, nil
} }
ours, theirs := u.Events[len(u.Events)-1].Index, acc.Index theirs := acc.Index
acctime := time.Unix(acc.Time, 0)
settings := configuration.Revocation.getSettings(id)
var ours uint64
if u := updates[sig.PKCounter]; u != nil {
ours = u.Events[len(u.Events)-1].Index
}
if ours > theirs { if ours > theirs {
return false, nil, errors.New("nonrevocation proof used wrong accumulator") return false, nil, nil
} }
if ours == theirs { if ours == theirs {
settings := configuration.Revocation.getSettings(id) if settings.updated.After(acctime) {
if uint(time.Now().Sub(settings.updated).Seconds()) > settings.MaxNonrevocationDuration { acctime = settings.updated
revocationtime[i] = &settings.updated
} }
} }
if validAt == nil {
t := time.Now()
validAt = &t
}
if uint(validAt.Sub(acctime).Seconds()) > settings.MaxNonrevocationDuration {
revocationtime[i] = &acctime
}
} }
return true, revocationtime, nil return true, revocationtime, nil
...@@ -321,7 +333,7 @@ func (d *Disclosure) VerifyAgainstRequest( ...@@ -321,7 +333,7 @@ func (d *Disclosure) VerifyAgainstRequest(
} }
// Cryptographically verify all included IRMA proofs // Cryptographically verify all included IRMA proofs
valid, revtimes, err := ProofList(d.Proofs).VerifyProofs(configuration, context, nonce, publickeys, revupdates, issig) valid, revtimes, err := ProofList(d.Proofs).VerifyProofs(configuration, context, nonce, publickeys, revupdates, validAt, issig)
if !valid || err != nil { if !valid || err != nil {
return nil, ProofStatusInvalid, err return nil, ProofStatusInvalid, err
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment