Commit 669bd187 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

feat: refactor revocation update messages into hashed chain structure

parent 33598603
package irma
import (
"database/sql/driver"
"database/sql/driver" // only imported to refer to the driver.Value type
"fmt"
"strings"
......
......@@ -14,6 +14,7 @@ import (
"github.com/go-errors/errors"
"github.com/jasonlvhit/gocron"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server"
"github.com/sirupsen/logrus"
......@@ -154,7 +155,7 @@ func (s *Server) Revoke(credid irma.CredentialTypeIdentifier, key string) error
}
func ParsePath(path string) (token, noun string, arg []string, err error) {
rev := regexp.MustCompile("revocation/(records|latestrecords|issuancerecord)/?(.*)$")
rev := regexp.MustCompile("revocation/(updatefrom|updatelatest|update|issuancerecord)/?(.*)$")
matches := rev.FindStringSubmatch(path)
if len(matches) == 3 {
args := strings.Split(matches[2], "/")
......@@ -381,7 +382,7 @@ func (s *Server) handleClientMessage(
func (s *Server) handleRevocationMessage(
noun, method string, args []string, headers map[string][]string, message []byte,
) (int, []byte) {
if (noun == "records" || noun == "latestrecords") && method == http.MethodGet {
if (noun == "updatefrom" || noun == "updatelatest") && method == http.MethodGet {
if len(args) != 2 {
return server.JsonResponse(nil, server.RemoteError(server.ErrorInvalidRequest, "GET "+noun+" expects 2 url arguments"))
}
......@@ -390,21 +391,22 @@ func (s *Server) handleRevocationMessage(
return server.JsonResponse(nil, server.RemoteError(server.ErrorMalformedInput, err.Error()))
}
cred := irma.NewCredentialTypeIdentifier(args[0])
if noun == "records" {
return server.JsonResponse(s.handleGetRevocationRecords(cred, i))
if noun == "updatefrom" {
return server.JsonResponse(s.handleGetUpdateFrom(cred, i))
} else {
return server.JsonResponse(s.handleGetLatestRevocationRecords(cred, i))
return server.JsonResponse(s.handleGetUpdateLatest(cred, i))
}
}
if noun == "records" && method == http.MethodPost {
if len(args) != 0 {
return server.JsonResponse(nil, server.RemoteError(server.ErrorInvalidRequest, "POST records expects no url arguments"))
if noun == "update" && method == http.MethodPost {
if len(args) != 1 {
return server.JsonResponse(nil, server.RemoteError(server.ErrorInvalidRequest, "POST update expects 1 url argument"))
}
var records []*irma.RevocationRecord
if err := json.Unmarshal(message, &records); err != nil {
cred := irma.NewCredentialTypeIdentifier(args[0])
var update *revocation.Update
if err := json.Unmarshal(message, &update); err != nil {
return server.JsonResponse(nil, server.RemoteError(server.ErrorMalformedInput, err.Error()))
}
return server.JsonResponse(s.handlePostRevocationRecords(records))
return server.JsonResponse(s.handlePostUpdate(cred, update))
}
if noun == "issuancerecord" && method == http.MethodPost {
if len(args) != 2 {
......
......@@ -4,6 +4,7 @@ import (
"time"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/gabi/signed"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server"
......@@ -33,10 +34,10 @@ func (session *session) handleGetRequest(min, max *irma.ProtocolVersion) (irma.S
session.markAlive()
logger := session.conf.Logger.WithFields(logrus.Fields{"session": session.token})
// we include the latest revocation records for the client here, as opposed to when the session
// we include the latest revocation updates for the client here, as opposed to when the session
// was started, so that the client always gets the very latest revocation records
var err error
if err = session.conf.IrmaConfiguration.Revocation.SetRevocationRecords(session.request.Base()); err != nil {
if err = session.conf.IrmaConfiguration.Revocation.SetRevocationUpdates(session.request.Base()); err != nil {
return nil, session.fail(server.ErrorUnknown, err.Error()) // TODO error type
}
......@@ -214,40 +215,42 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM
return sigs, nil
}
// POST revocation/records
func (s *Server) handlePostRevocationRecords(records []*irma.RevocationRecord) (interface{}, *irma.RemoteError) {
if err := s.conf.IrmaConfiguration.Revocation.AddRevocationRecords(records); err != nil {
// POST revocation/update/{credtype}
func (s *Server) handlePostUpdate(typ irma.CredentialTypeIdentifier, update *revocation.Update) (interface{}, *irma.RemoteError) {
if err := s.conf.IrmaConfiguration.Revocation.AddUpdate(typ, update); err != nil {
return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type
}
return nil, nil
}
// GET revocation/records/{credtype}/{index}
func (s *Server) handleGetRevocationRecords(
// GET revocation/updatefrom/{credtype}/{index}
func (s *Server) handleGetUpdateFrom(
cred irma.CredentialTypeIdentifier, index uint64,
) ([]*irma.RevocationRecord, *irma.RemoteError) {
if _, ok := s.conf.RevocationSettings[cred]; !ok {
) (*revocation.Update, *irma.RemoteError) {
if settings := s.conf.RevocationSettings[cred]; settings == nil ||
!(settings.Mode == irma.RevocationModeProxy || settings.Mode == irma.RevocationModeServer) {
return nil, server.RemoteError(server.ErrorInvalidRequest, "not supported by this server")
}
records, err := s.conf.IrmaConfiguration.Revocation.RevocationRecords(cred, index)
update, err := s.conf.IrmaConfiguration.Revocation.UpdateFrom(cred, index)
if err != nil {
return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type
}
return records, nil
return update, nil
}
// GET revocation/latestrecords/{credtype}/{count}
func (s *Server) handleGetLatestRevocationRecords(
// GET revocation/updatelatest/{credtype}/{count}
func (s *Server) handleGetUpdateLatest(
cred irma.CredentialTypeIdentifier, count uint64,
) ([]*irma.RevocationRecord, *irma.RemoteError) {
if _, ok := s.conf.RevocationSettings[cred]; !ok {
) (*revocation.Update, *irma.RemoteError) {
if settings := s.conf.RevocationSettings[cred]; settings == nil ||
!(settings.Mode == irma.RevocationModeProxy || settings.Mode == irma.RevocationModeServer) {
return nil, server.RemoteError(server.ErrorInvalidRequest, "not supported by this server")
}
records, err := s.conf.IrmaConfiguration.Revocation.LatestRevocationRecords(cred, count)
update, err := s.conf.IrmaConfiguration.Revocation.UpdateLatest(cred, count)
if err != nil {
return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type
}
return records, nil
return update, nil
}
// POST revocation/issuancerecord/{credtype}/{keycounter}
......
......@@ -95,25 +95,25 @@ func (session *session) issuanceHandleRevocation(
// Fetch latest revocation record, and then extract the current value of the accumulator
// from it to generate the witness from
records, err := rs.LatestRevocationRecords(id, 1)
u, err := rs.UpdateLatest(id, 0)
if err != nil {
return
}
r := records[len(records)-1]
pk, err := rs.Keys.PublicKey(id.IssuerIdentifier(), r.PublicKeyIndex)
sig := u.SignedAccumulator
pk, err := rs.Keys.PublicKey(id.IssuerIdentifier(), sig.PKIndex)
if err != nil {
return nil, nil, err
}
msg, err := r.UnmarshalVerify(pk)
acc, err := sig.UnmarshalVerify(pk)
if err != nil {
return nil, nil, err
}
if witness, err = sk.RevocationGenerateWitness(&msg.Accumulator); err != nil {
if witness, err = sk.RevocationGenerateWitness(acc); err != nil {
return
}
witness.Record = &r.Record // attach previously selected reocation record to the witness for the client
witness.SignedAccumulator = sig // attach previously selected reocation record to the witness for the client
nonrevAttr = witness.E
issrecord := &irma.IssuanceRecord{
CredType: id,
......@@ -122,7 +122,7 @@ func (session *session) issuanceHandleRevocation(
Issued: time.Now().UnixNano(), // or (floored) cred issuance time?
ValidUntil: attributes.Expiry().UnixNano(),
}
err = session.conf.IrmaConfiguration.Revocation.SaveIssuanceRecord(id, issrecord)
err = session.conf.IrmaConfiguration.Revocation.SaveIssuanceRecord(id, issrecord, sk)
return
}
......
......@@ -5,7 +5,6 @@ import (
"encoding/json"
"io/ioutil"
"net/http"
"reflect"
"testing"
......
......@@ -83,9 +83,11 @@ func StartRevocationServer(t *testing.T) {
// Connect to database and clear records from previous test runs
g, err := gorm.Open("postgres", conf.RevocationDB)
require.NoError(t, err)
require.NoError(t, g.DropTableIfExists((*irma.RevocationRecord)(nil)).Error)
require.NoError(t, g.DropTableIfExists((*irma.EventRecord)(nil)).Error)
require.NoError(t, g.DropTableIfExists((*irma.AccumulatorRecord)(nil)).Error)
require.NoError(t, g.DropTableIfExists((*irma.IssuanceRecord)(nil)).Error)
require.NoError(t, g.AutoMigrate((*irma.RevocationRecord)(nil)).Error)
require.NoError(t, g.AutoMigrate((*irma.EventRecord)(nil)).Error)
require.NoError(t, g.AutoMigrate((*irma.AccumulatorRecord)(nil)).Error)
require.NoError(t, g.AutoMigrate((*irma.IssuanceRecord)(nil)).Error)
require.NoError(t, g.Close())
......
package irmaclient
import (
"errors"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago"
......@@ -61,17 +59,18 @@ func (cred *credential) NonrevPrepare(conf *irma.Configuration, request irma.Ses
// first try to update witness by applying the revocation update messages attached to the session request
keys := irma.RevocationKeys{Conf: conf}
revupdates := base.RevocationUpdates[credtype]
count := len(revupdates.Events)
updated, err := cred.NonrevApplyUpdates(revupdates, keys)
if err != nil {
return updated, err
}
if cred.NonRevocationWitness.Accumulator.Index >= revupdates[len(revupdates)-1].EndIndex {
if cred.NonRevocationWitness.Accumulator.Index >= revupdates.Events[count-1].Index {
return updated, nil
}
// nonrevocation witness is still out of date after applying the updates from the request:
// we were too far behind. Update from revocation server.
revupdates, err = irma.RevocationClient{Conf: conf}.FetchRevocationRecords(credtype, cred.NonRevocationWitness.Accumulator.Index+1)
revupdates, err = irma.RevocationClient{Conf: conf}.FetchUpdateFrom(credtype, cred.NonRevocationWitness.Accumulator.Index+1)
if err != nil {
return updated, err
}
......@@ -80,21 +79,15 @@ func (cred *credential) NonrevPrepare(conf *irma.Configuration, request irma.Ses
// NonrevApplyUpdates updates the credential's nonrevocation witness using the specified messages,
// if they all verify and if their indices are ahead and adjacent to that of our witness.
func (cred *credential) NonrevApplyUpdates(messages []*irma.RevocationRecord, keys irma.RevocationKeys) (bool, error) {
func (cred *credential) NonrevApplyUpdates(update *revocation.Update, keys irma.RevocationKeys) (bool, error) {
oldindex := cred.NonRevocationWitness.Accumulator.Index
var err error
var pk *revocation.PublicKey
for _, record := range messages {
if cred.CredentialType().IssuerIdentifier() != record.CredType.IssuerIdentifier() {
return false, errors.New("cannot apply revocation record of other credential type")
}
if pk, err = keys.PublicKey(cred.CredentialType().IssuerIdentifier(), record.PublicKeyIndex); err != nil {
return false, err
}
if err = cred.NonRevocationWitness.Update(pk, &record.Record); err != nil {
return false, err
}
pk, err := keys.PublicKey(cred.CredentialType().IssuerIdentifier(), update.SignedAccumulator.PKIndex)
if err != nil {
return false, err
}
if err = cred.NonRevocationWitness.Update(pk, update); err != nil {
return false, err
}
return cred.NonRevocationWitness.Accumulator.Index != oldindex, nil
......
......@@ -359,6 +359,7 @@ func (session *session) doSession(proceed bool) {
err := <-session.prepRevocation
if err != nil {
session.fail(&irma.SessionError{ErrorType: irma.ErrorCrypto, Err: err}) // TODO error type
return
}
if !session.Distributed() {
......@@ -668,6 +669,7 @@ func (session *session) finish() bool {
func (session *session) fail(err *irma.SessionError) {
if session.finish() && err.ErrorType != irma.ErrorKeyshareUnenrolled {
irma.Logger.Warn("client session error: ", err.Error())
err.Err = errors.Wrap(err.Err, 0)
session.Handler.Failure(err)
}
......
......@@ -254,7 +254,7 @@ func (s *storage) LoadSignature(attrs *irma.AttributeList) (*gabi.CLSignature, *
if sig.Witness != nil {
pk, err := s.Configuration.Revocation.Keys.PublicKey(
attrs.CredentialType().IssuerIdentifier(),
sig.Witness.Record.PublicKeyIndex,
sig.Witness.SignedAccumulator.PKIndex,
)
if err != nil {
return nil, nil, err
......
......@@ -13,6 +13,7 @@ import (
"github.com/go-errors/errors"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago/internal/fs"
)
......@@ -38,7 +39,7 @@ type BaseRequest struct {
Revocation []CredentialTypeIdentifier `json:"revocation,omitempty"`
// RevocationUpdates contains revocation update messages for the client to update its
// revocation state.
RevocationUpdates map[CredentialTypeIdentifier][]*RevocationRecord `json:"revocationUpdates,omitempty"`
RevocationUpdates map[CredentialTypeIdentifier]*revocation.Update `json:"revocationUpdates,omitempty"`
ids *IrmaIdentifierSet // cache for Identifiers() method
......@@ -199,7 +200,7 @@ type AttributeRequest struct {
type RevocationRequest struct {
LDContext string `json:"@context,omitempty"`
CredentialType CredentialTypeIdentifier `json:"type"`
Key string `json:"key,omitempty"`
Key string `json:"revocationKey,omitempty"`
Enable bool `json:"enable,omitempty"`
}
......@@ -236,7 +237,7 @@ func (b *BaseRequest) GetNonce(*atum.Timestamp) *big.Int {
// RequestsRevocation indicates whether or not the requestor requires a nonrevocation proof for
// the given credential type; that is, whether or not it included revocation update messages.
func (b *BaseRequest) RequestsRevocation(id CredentialTypeIdentifier) bool {
return len(b.RevocationUpdates) > 0 && len(b.RevocationUpdates[id]) > 0
return len(b.RevocationUpdates) > 0 && len(b.RevocationUpdates[id].Events) > 0
}
func (b *BaseRequest) RevocationConsistent() error {
......
This diff is collapsed.
......@@ -7,6 +7,7 @@ import (
"github.com/go-errors/errors"
"github.com/jinzhu/gorm"
"github.com/privacybydesign/gabi/revocation"
"github.com/sirupsen/logrus"
)
......@@ -20,6 +21,7 @@ type (
Insert(o interface{}) error
// Save an existing record.
Save(o interface{}) error
Upsert(o interface{}) error
// Last deserializes the last record into o.
Last(typ CredentialTypeIdentifier, o interface{}) error
// Exists checks whether records exist satisfying col = key.
......@@ -40,63 +42,87 @@ type (
gorm *gorm.DB
}
// memRevStorage is a much simpler in-memory database, suitable only for storing the last
// few revocation records, for requestors.
// memRevStorage is a much simpler in-memory database, suitable only for storing update messages.
memRevStorage struct {
sync.Mutex
records map[CredentialTypeIdentifier]*memRevRecords
records map[CredentialTypeIdentifier]*memUpdateRecord
}
memRevRecords struct {
memUpdateRecord struct {
sync.Mutex
r []*RevocationRecord
r *revocation.Update
}
)
func newMemStorage() memRevStorage {
return memRevStorage{
records: make(map[CredentialTypeIdentifier]*memRevRecords),
records: make(map[CredentialTypeIdentifier]*memUpdateRecord),
}
}
func (m memRevStorage) get(typ CredentialTypeIdentifier) *memRevRecords {
func (m memRevStorage) get(typ CredentialTypeIdentifier) *memUpdateRecord {
m.Lock()
defer m.Unlock()
if _, ok := m.records[typ]; !ok {
m.records[typ] = &memRevRecords{r: make([]*RevocationRecord, 0, revocationUpdateCount)}
}
return m.records[typ]
}
func (m memRevStorage) Latest(typ CredentialTypeIdentifier, count uint64, r *[]*RevocationRecord) {
records := m.get(typ)
records.Lock()
defer records.Unlock()
func (m memRevStorage) Latest(typ CredentialTypeIdentifier, count uint64) *revocation.Update {
record := m.get(typ)
if record == nil {
return nil
}
record.Lock()
defer record.Unlock()
c := count
if c > uint64(len(records.r)) {
c = uint64(len(records.r))
offset := int64(len(record.r.Events)) - int64(count) - 1
if offset < 0 {
offset = 0
}
for _, rec := range records.r[:c] {
Logger.Trace("membdb: get ", rec.StartIndex)
*r = append(*r, rec)
response := &revocation.Update{SignedAccumulator: record.r.SignedAccumulator}
for _, rec := range record.r.Events[offset:] {
Logger.Trace("membdb: get ", rec.Index)
response.Events = append(response.Events, rec)
}
return response
}
func (m memRevStorage) Insert(record *RevocationRecord) {
r := m.get(record.CredType)
r.Lock()
defer r.Unlock()
func (m memRevStorage) Insert(typ CredentialTypeIdentifier, update *revocation.Update) {
record := m.get(typ)
if record == nil {
record = &memUpdateRecord{r: &revocation.Update{}}
m.records[typ] = record
}
record.Lock()
defer record.Unlock()
ours := record.r.Events
if len(ours) == 0 {
record.r = update
return
}
theirs := update.Events
if len(theirs) == 0 {
return
}
theirStart, theirEnd, ourEnd := theirs[0].Index, theirs[len(theirs)-1].Index, ours[len(ours)-1].Index
offset := ourEnd - theirStart
if theirEnd <= ourEnd || offset < 0 {
return
}
Logger.Trace("membdb: insert ", record)
r.r = append(r.r, record)
Logger.Trace("membdb: inserting")
record.r.SignedAccumulator = update.SignedAccumulator
record.r.Events = append(record.r.Events, theirs[offset:]...)
}
func (m memRevStorage) HasRecords(typ CredentialTypeIdentifier) bool {
r := m.get(typ)
r.Lock()
defer r.Unlock()
return len(r.r) > 0
record := m.get(typ)
if record == nil {
return false
}
record.Lock()
defer record.Unlock()
return len(record.r.Events) > 0
}
func newSqlStorage(debug bool, db string) (revStorage, error) {
......@@ -109,7 +135,10 @@ func newSqlStorage(debug bool, db string) (revStorage, error) {
g.LogMode(true)
g.SetLogger(gorm.Logger{LogWriter: log.New(Logger.WriterLevel(logrus.DebugLevel), "db: ", 0)})
}
if g.AutoMigrate((*RevocationRecord)(nil)); g.Error != nil {
if g.AutoMigrate((*EventRecord)(nil)); g.Error != nil {
return nil, g.Error
}
if g.AutoMigrate((*AccumulatorRecord)(nil)); g.Error != nil {
return nil, g.Error
}
if g.AutoMigrate((*IssuanceRecord)(nil)); g.Error != nil {
......@@ -153,6 +182,16 @@ func (s sqlRevStorage) Save(o interface{}) error {
return s.gorm.Save(o).Error
}
func (s sqlRevStorage) Upsert(o interface{}) error {
var c int
s.gorm.Model(o).Count(&c)
if c == 0 {
return s.Insert(o)
} else {
return s.Save(o)
}
}
func (s sqlRevStorage) Last(typ CredentialTypeIdentifier, o interface{}) error {
return s.gorm.Last(o, "cred_type = ?", typ).Error
}
......
......@@ -8,6 +8,7 @@ import (
"github.com/go-errors/errors"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation"
)
// ProofStatus is the status of the complete proof
......@@ -110,7 +111,7 @@ func (pl ProofList) VerifyProofs(
configuration *Configuration,
context *big.Int, nonce *big.Int,
publickeys []*gabi.PublicKey,
revRecords map[CredentialTypeIdentifier][]*RevocationRecord,
revRecords map[CredentialTypeIdentifier]*revocation.Update,
isSig bool,
) (bool, map[int]*time.Time, error) {
// Empty proof lists are allowed (if consistent with the session request, which is checked elsewhere)
......@@ -149,7 +150,7 @@ func (pl ProofList) VerifyProofs(
// - verify that any singleton credential occurs at most once in the prooflist
// - verify that all required nonrevocation proofs are present
singletons := map[CredentialTypeIdentifier]bool{}
revocation := map[int]*time.Time{} // per proof, store up to what time it is known to be not revoked
revocationtime := map[int]*time.Time{} // per proof, stores up to what time it is known to be not revoked
for i, proof := range pl {
proofd, ok := proof.(*gabi.ProofD)
if !ok {
......@@ -174,25 +175,36 @@ func (pl ProofList) VerifyProofs(
// the last one in the update message set we provided along with the session request,
// OR a newer one included in the proofs itself.
r := revRecords[id]
if len(r) == 0 { // no nonrevocation proof was requested for this credential
if r == nil { // no nonrevocation proof was requested for this credential
return true, nil, nil
}
if !proofd.HasNonRevocationProof() {
return false, nil, nil
}
ours, theirs := proofd.NonRevocationProof.Accumulator.Index, r[len(r)-1].EndIndex
if ours < theirs {
sig := proofd.NonRevocationProof.SignedAccumulator
pk, err := RevocationKeys{configuration}.PublicKey(typ.IssuerIdentifier(), sig.PKIndex)
if err != nil {
return false, nil, nil
}
acc, err := proofd.NonRevocationProof.SignedAccumulator.UnmarshalVerify(pk)
if err != nil {
return false, nil, nil
}
ours, theirs := r.Events[len(r.Events)-1].Index, acc.Index
if ours > theirs {
return false, nil, errors.New("nonrevocation proof used wrong accumulator")
}
if ours == theirs {
settings := configuration.Revocation.getSettings(id)
if uint(time.Now().Sub(settings.updated).Seconds()) > settings.MaxNonrevocationDuration {
revocation[i] = &settings.updated
revocationtime[i] = &settings.updated
}
}
}
return true, revocation, nil
return true, revocationtime, nil
}
func (d *Disclosure) extraIndices(condiscon AttributeConDisCon) []*DisclosedAttributeIndex {
......@@ -235,11 +247,11 @@ func (d *Disclosure) extraIndices(condiscon AttributeConDisCon) []*DisclosedAttr
// is included, then the first attributes in the returned slice match with the disjunction list in
// the disjunction list. The first return parameter of this function indicates whether or not all
// disjunctions (if present) are satisfied.
func (d *Disclosure) DisclosedAttributes(configuration *Configuration, condiscon AttributeConDisCon, revocation map[int]*time.Time) (bool, [][]*DisclosedAttribute, error) {
if revocation == nil {
revocation = map[int]*time.Time{}
func (d *Disclosure) DisclosedAttributes(configuration *Configuration, condiscon AttributeConDisCon, revtimes map[int]*time.Time) (bool, [][]*DisclosedAttribute, error) {
if revtimes == nil {
revtimes = map[int]*time.Time{}
}
complete, list, err := condiscon.Satisfy(d, revocation, configuration)
complete, list, err := condiscon.Satisfy(d, revtimes, configuration)
if err != nil {
return false, nil, err
}
......@@ -247,7 +259,7 @@ func (d *Disclosure) DisclosedAttributes(configuration *Configuration, condiscon
var extra []*DisclosedAttribute
indices := d.extraIndices(condiscon)
for _, index := range indices {
attr, _, err := extractAttribute(d.Proofs, index, revocation[index.CredentialIndex], configuration)
attr, _, err := extractAttribute(d.Proofs, index, revtimes[index.CredentialIndex], configuration)
if err != nil {
return false, nil, err
}
......@@ -299,20 +311,20 @@ func (d *Disclosure) VerifyAgainstRequest(
issig bool,
) ([][]*DisclosedAttribute, ProofStatus, error) {
var required AttributeConDisCon
var revRecords map[CredentialTypeIdentifier][]*RevocationRecord
var revupdates map[CredentialTypeIdentifier]*revocation.Update
if request != nil {
revRecords = request.Base().RevocationUpdates
revupdates = request.Base().RevocationUpdates
required = request.Disclosure().Disclose
}
// Cryptographically verify all included IRMA proofs
valid, revocation, err := ProofList(d.Proofs).VerifyProofs(configuration, context, nonce, publickeys, revRecords, issig)
valid, revtimes, err := ProofList(d.Proofs).VerifyProofs(configuration, context, nonce, publickeys, revupdates, issig)
if !valid || err != nil {
return nil, ProofStatusInvalid, err