Commit 786f0836 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

refactor: move revocation.DB and related structs from gabi to root package

parent 2919f416
...@@ -14,7 +14,6 @@ import ( ...@@ -14,7 +14,6 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/jasonlvhit/gocron" "github.com/jasonlvhit/gocron"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server" "github.com/privacybydesign/irmago/server"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
...@@ -54,7 +53,7 @@ func New(conf *server.Configuration) (*Server, error) { ...@@ -54,7 +53,7 @@ func New(conf *server.Configuration) (*Server, error) {
// TODO rethink this condition // TODO rethink this condition
continue continue
} }
if err := s.conf.IrmaConfiguration.RevocationUpdateDB(credid); err != nil { if err := s.conf.IrmaConfiguration.RevocationStorage.RevocationUpdateDB(credid); err != nil {
s.conf.Logger.Error("failed to update revocation database for %s:", credid.String()) s.conf.Logger.Error("failed to update revocation database for %s:", credid.String())
_ = server.LogError(err) _ = server.LogError(err)
} }
...@@ -67,7 +66,7 @@ func New(conf *server.Configuration) (*Server, error) { ...@@ -67,7 +66,7 @@ func New(conf *server.Configuration) (*Server, error) {
} }
func (s *Server) Stop() { func (s *Server) Stop() {
if err := s.conf.IrmaConfiguration.Close(); err != nil { if err := s.conf.IrmaConfiguration.RevocationStorage.Close(); err != nil {
_ = server.LogWarning(err) _ = server.LogWarning(err)
} }
s.stopScheduler <- true s.stopScheduler <- true
...@@ -141,7 +140,7 @@ func (s *Server) CancelSession(token string) error { ...@@ -141,7 +140,7 @@ func (s *Server) CancelSession(token string) error {
} }
func (s *Server) Revoke(credid irma.CredentialTypeIdentifier, key string) error { func (s *Server) Revoke(credid irma.CredentialTypeIdentifier, key string) error {
return s.conf.IrmaConfiguration.Revoke(credid, key) return s.conf.IrmaConfiguration.RevocationStorage.Revoke(credid, key)
} }
func ParsePath(path string) (token, noun string, arg []string, err error) { func ParsePath(path string) (token, noun string, arg []string, err error) {
...@@ -387,7 +386,7 @@ func (s *Server) handleRevocationMessage( ...@@ -387,7 +386,7 @@ func (s *Server) handleRevocationMessage(
return server.JsonResponse(nil, server.RemoteError(server.ErrorInvalidRequest, "POST records expects 1 url arguments")) return server.JsonResponse(nil, server.RemoteError(server.ErrorInvalidRequest, "POST records expects 1 url arguments"))
} }
cred := irma.NewCredentialTypeIdentifier(args[0]) cred := irma.NewCredentialTypeIdentifier(args[0])
var records []*revocation.Record var records []*irma.Record
if err := json.Unmarshal(message, &records); err != nil { if err := json.Unmarshal(message, &records); err != nil {
return server.JsonResponse(nil, server.RemoteError(server.ErrorMalformedInput, err.Error())) return server.JsonResponse(nil, server.RemoteError(server.ErrorMalformedInput, err.Error()))
} }
......
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"time" "time"
"github.com/privacybydesign/gabi" "github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/gabi/signed" "github.com/privacybydesign/gabi/signed"
"github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/server" "github.com/privacybydesign/irmago/server"
...@@ -37,7 +36,7 @@ func (session *session) handleGetRequest(min, max *irma.ProtocolVersion) (irma.S ...@@ -37,7 +36,7 @@ func (session *session) handleGetRequest(min, max *irma.ProtocolVersion) (irma.S
// we include the latest revocation records for the client here, as opposed to when the session // we include the latest revocation records for the client here, as opposed to when the session
// was started, so that the client always gets the very latest revocation records // was started, so that the client always gets the very latest revocation records
var err error var err error
if err = session.conf.IrmaConfiguration.RevocationSetRecords(session.request.Base()); err != nil { if err = session.conf.IrmaConfiguration.RevocationStorage.RevocationSetRecords(session.request.Base()); err != nil {
return nil, session.fail(server.ErrorUnknown, err.Error()) // TODO error type return nil, session.fail(server.ErrorUnknown, err.Error()) // TODO error type
} }
...@@ -216,9 +215,9 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM ...@@ -216,9 +215,9 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM
} }
func (s *Server) handlePostRevocationRecords( func (s *Server) handlePostRevocationRecords(
cred irma.CredentialTypeIdentifier, records []*revocation.Record, cred irma.CredentialTypeIdentifier, records []*irma.Record,
) (interface{}, *irma.RemoteError) { ) (interface{}, *irma.RemoteError) {
db, err := s.conf.IrmaConfiguration.RevocationDB(cred) db, err := s.conf.IrmaConfiguration.RevocationStorage.RevocationDB(cred)
if err != nil { if err != nil {
return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type
} }
...@@ -230,11 +229,11 @@ func (s *Server) handlePostRevocationRecords( ...@@ -230,11 +229,11 @@ func (s *Server) handlePostRevocationRecords(
func (s *Server) handleGetRevocationRecords( func (s *Server) handleGetRevocationRecords(
cred irma.CredentialTypeIdentifier, index int, cred irma.CredentialTypeIdentifier, index int,
) ([]*revocation.Record, *irma.RemoteError) { ) ([]*irma.Record, *irma.RemoteError) {
if _, ok := s.conf.RevocationServers[cred]; !ok { if _, ok := s.conf.RevocationServers[cred]; !ok {
return nil, server.RemoteError(server.ErrorInvalidRequest, "not supported by this server") return nil, server.RemoteError(server.ErrorInvalidRequest, "not supported by this server")
} }
db, err := s.conf.IrmaConfiguration.RevocationDB(cred) db, err := s.conf.IrmaConfiguration.RevocationStorage.RevocationDB(cred)
if err != nil { if err != nil {
return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type
} }
...@@ -265,13 +264,13 @@ func (s *Server) handlePostIssuanceRecord( ...@@ -265,13 +264,13 @@ func (s *Server) handlePostIssuanceRecord(
if err != nil { if err != nil {
return "", server.RemoteError(server.ErrorUnknown, err.Error()) return "", server.RemoteError(server.ErrorUnknown, err.Error())
} }
var rec revocation.IssuanceRecord var rec irma.IssuanceRecord
if err := signed.UnmarshalVerify(revpk.ECDSA, message, &rec); err != nil { if err := signed.UnmarshalVerify(revpk.ECDSA, message, &rec); err != nil {
return "", server.RemoteError(server.ErrorUnauthorized, err.Error()) return "", server.RemoteError(server.ErrorUnauthorized, err.Error())
} }
// Insert the record into the database // Insert the record into the database
db, err := s.conf.IrmaConfiguration.RevocationDB(cred) db, err := s.conf.IrmaConfiguration.RevocationStorage.RevocationDB(cred)
if err != nil { if err != nil {
return "", server.RemoteError(server.ErrorUnknown, err.Error()) return "", server.RemoteError(server.ErrorUnknown, err.Error())
} }
......
...@@ -85,12 +85,12 @@ func (session *session) issuanceHandleRevocation( ...@@ -85,12 +85,12 @@ func (session *session) issuanceHandleRevocation(
// ensure the client always gets an up to date nonrevocation witness // ensure the client always gets an up to date nonrevocation witness
if _, ours := session.conf.RevocationServers[cred.CredentialTypeID]; !ours { if _, ours := session.conf.RevocationServers[cred.CredentialTypeID]; !ours {
if err = session.conf.IrmaConfiguration.RevocationUpdateDB(cred.CredentialTypeID); err != nil { if err = session.conf.IrmaConfiguration.RevocationStorage.RevocationUpdateDB(cred.CredentialTypeID); err != nil {
return return
} }
} }
db, err := session.conf.IrmaConfiguration.RevocationDB(cred.CredentialTypeID) db, err := session.conf.IrmaConfiguration.RevocationStorage.RevocationDB(cred.CredentialTypeID)
if err != nil { if err != nil {
return return
} }
...@@ -102,13 +102,13 @@ func (session *session) issuanceHandleRevocation( ...@@ -102,13 +102,13 @@ func (session *session) issuanceHandleRevocation(
return return
} }
nonrevAttr = witness.E nonrevAttr = witness.E
issrecord := &revocation.IssuanceRecord{ issrecord := &irma.IssuanceRecord{
Key: cred.RevocationKey, Key: cred.RevocationKey,
Attr: nonrevAttr, Attr: nonrevAttr,
Issued: time.Now().UnixNano(), // or (floored) cred issuance time? Issued: time.Now().UnixNano(), // or (floored) cred issuance time?
ValidUntil: attributes.Expiry().UnixNano(), ValidUntil: attributes.Expiry().UnixNano(),
} }
err = session.conf.IrmaConfiguration.SendRevocationIssuanceRecord(cred.CredentialTypeID, issrecord) err = session.conf.IrmaConfiguration.RevocationStorage.SendRevocationIssuanceRecord(cred.CredentialTypeID, issrecord)
if err != nil { if err != nil {
_ = server.LogWarning(errors.WrapPrefix(err, "Failed to send issuance record to revocation server", 0)) _ = server.LogWarning(errors.WrapPrefix(err, "Failed to send issuance record to revocation server", 0))
session.conf.Logger.Warn("Storing issuance record locally") session.conf.Logger.Warn("Storing issuance record locally")
...@@ -144,7 +144,7 @@ func (s *Server) validateIssuanceRequest(request *irma.IssuanceRequest) error { ...@@ -144,7 +144,7 @@ func (s *Server) validateIssuanceRequest(request *irma.IssuanceRequest) error {
return err return err
} }
if s.conf.IrmaConfiguration.CredentialTypes[cred.CredentialTypeID].SupportsRevocation() { if s.conf.IrmaConfiguration.CredentialTypes[cred.CredentialTypeID].SupportsRevocation() {
db, err := s.conf.IrmaConfiguration.RevocationDB(cred.CredentialTypeID) db, err := s.conf.IrmaConfiguration.RevocationStorage.RevocationDB(cred.CredentialTypeID)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -6,13 +6,10 @@ import ( ...@@ -6,13 +6,10 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"path/filepath"
"reflect" "reflect"
"testing" "testing"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago" "github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/test" "github.com/privacybydesign/irmago/internal/test"
"github.com/privacybydesign/irmago/irmaclient" "github.com/privacybydesign/irmago/irmaclient"
...@@ -352,20 +349,7 @@ func TestRevocation(t *testing.T) { ...@@ -352,20 +349,7 @@ func TestRevocation(t *testing.T) {
// setup client, constants, and revocation key material // setup client, constants, and revocation key material
defer test.ClearTestStorage(t) defer test.ClearTestStorage(t)
client, _ := parseStorage(t) client, _ := parseStorage(t)
iss := irma.NewIssuerIdentifier("irma-demo.MijnOverheid")
cred := irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root") cred := irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root")
keystore := client.Configuration.RevocationKeystore(iss)
sk, err := client.Configuration.PrivateKey(iss)
require.NoError(t, err)
revsk, err := sk.RevocationKey()
require.NoError(t, err)
// enable revocation for our credential type by creating and saving an initial accumulator
db, err := revocation.LoadDB(filepath.Join(testdata, "tmp", "issuer", cred.String()), keystore)
require.NoError(t, err)
require.NoError(t, db.EnableRevocation(revsk))
require.NoError(t, db.Close()) // so StartRevocationServer() can open it again
StartRevocationServer(t) StartRevocationServer(t)
// issue two MijnOverheid.root instances with revocation enabled // issue two MijnOverheid.root instances with revocation enabled
......
...@@ -51,15 +51,24 @@ func StopRequestorServer() { ...@@ -51,15 +51,24 @@ func StopRequestorServer() {
func StartRevocationServer(t *testing.T) { func StartRevocationServer(t *testing.T) {
var err error var err error
revocationServer, err = irmaserver.New(&server.Configuration{ cred := irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root")
conf := &server.Configuration{
Logger: logger, Logger: logger,
DisableSchemesUpdate: true, DisableSchemesUpdate: true,
SchemesPath: filepath.Join(testdata, "irma_configuration"), SchemesPath: filepath.Join(testdata, "irma_configuration"),
RevocationPath: filepath.Join(testdata, "tmp", "issuer"), // todo rename this path to revocation? RevocationPath: filepath.Join(testdata, "tmp", "issuer"), // todo rename this path to revocation?
RevocationServers: map[irma.CredentialTypeIdentifier]server.RevocationServer{ RevocationServers: map[irma.CredentialTypeIdentifier]server.RevocationServer{
irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root"): {}, cred: {},
}, },
}) }
revocationServer, err = irmaserver.New(conf)
require.NoError(t, err)
sk, err := conf.IrmaConfiguration.RevocationStorage.PrivateKey(cred.IssuerIdentifier())
require.NoError(t, err)
db, err := conf.IrmaConfiguration.RevocationStorage.RevocationDB(cred)
require.NoError(t, err)
err = db.EnableRevocation(sk)
require.NoError(t, err) require.NoError(t, err)
mux := http.NewServeMux() mux := http.NewServeMux()
......
...@@ -51,8 +51,7 @@ func (cred *credential) PrepareNonrevocation(conf *irma.Configuration, request i ...@@ -51,8 +51,7 @@ func (cred *credential) PrepareNonrevocation(conf *irma.Configuration, request i
revupdates := m[credtype] revupdates := m[credtype]
nonrev := len(revupdates) > 0 nonrev := len(revupdates) > 0
keystore := conf.RevocationKeystore(credtype.IssuerIdentifier()) if updated, err := conf.RevocationStorage.UpdateWitness(cred.NonRevocationWitness, revupdates, credtype.IssuerIdentifier()); err != nil {
if updated, err := cred.NonRevocationWitness.Update(revupdates, keystore); err != nil {
return false, err return false, err
} else if updated { } else if updated {
cred.DiscardRevocationCache() cred.DiscardRevocationCache()
...@@ -65,11 +64,10 @@ func (cred *credential) PrepareNonrevocation(conf *irma.Configuration, request i ...@@ -65,11 +64,10 @@ func (cred *credential) PrepareNonrevocation(conf *irma.Configuration, request i
// nonrevocation witness is still out of date after applying the updates from the request, // nonrevocation witness is still out of date after applying the updates from the request,
// i.e. we were too far behind. Update from revocation server. // i.e. we were too far behind. Update from revocation server.
records, err := conf.RevocationGetUpdates(credtype, cred.NonRevocationWitness.Index+1) revupdates, err := conf.RevocationStorage.RevocationGetUpdates(credtype, cred.NonRevocationWitness.Index+1)
if err != nil { if err != nil {
return nonrev, err return nonrev, err
} }
_, err = cred.NonRevocationWitness.Update(records, keystore) _, err = conf.RevocationStorage.UpdateWitness(cred.NonRevocationWitness, revupdates, credtype.IssuerIdentifier())
return nonrev, err return nonrev, err
} }
...@@ -33,7 +33,6 @@ import ( ...@@ -33,7 +33,6 @@ import (
"github.com/jasonlvhit/gocron" "github.com/jasonlvhit/gocron"
"github.com/privacybydesign/gabi" "github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big" "github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/gabi/signed" "github.com/privacybydesign/gabi/signed"
"github.com/privacybydesign/irmago/internal/fs" "github.com/privacybydesign/irmago/internal/fs"
) )
...@@ -46,6 +45,8 @@ type Configuration struct { ...@@ -46,6 +45,8 @@ type Configuration struct {
CredentialTypes map[CredentialTypeIdentifier]*CredentialType CredentialTypes map[CredentialTypeIdentifier]*CredentialType
AttributeTypes map[AttributeTypeIdentifier]*AttributeType AttributeTypes map[AttributeTypeIdentifier]*AttributeType
RevocationStorage *RevocationStorage
// Path to the irma_configuration folder that this instance represents // Path to the irma_configuration folder that this instance represents
Path string Path string
RevocationPath string RevocationPath string
...@@ -60,7 +61,6 @@ type Configuration struct { ...@@ -60,7 +61,6 @@ type Configuration struct {
publicKeys map[IssuerIdentifier]map[int]*gabi.PublicKey publicKeys map[IssuerIdentifier]map[int]*gabi.PublicKey
privateKeys map[IssuerIdentifier]*gabi.PrivateKey privateKeys map[IssuerIdentifier]*gabi.PrivateKey
reverseHashes map[string]CredentialTypeIdentifier reverseHashes map[string]CredentialTypeIdentifier
revDBs map[CredentialTypeIdentifier]*revocation.DB
initialized bool initialized bool
assets string assets string
readOnly bool readOnly bool
...@@ -143,6 +143,7 @@ func newConfiguration(path string, assets string) (conf *Configuration, err erro ...@@ -143,6 +143,7 @@ func newConfiguration(path string, assets string) (conf *Configuration, err erro
RevocationPath: filepath.Join(DefaultDataPath(), "revocation"), RevocationPath: filepath.Join(DefaultDataPath(), "revocation"),
assets: assets, assets: assets,
} }
conf.RevocationStorage = &RevocationStorage{conf: conf}
if conf.assets != "" { // If an assets folder is specified, then it must exist if conf.assets != "" { // If an assets folder is specified, then it must exist
if err = fs.AssertPathExists(conf.assets); err != nil { if err = fs.AssertPathExists(conf.assets); err != nil {
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/privacybydesign/gabi" "github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big" "github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago/internal/fs" "github.com/privacybydesign/irmago/internal/fs"
) )
...@@ -33,10 +32,10 @@ type BaseRequest struct { ...@@ -33,10 +32,10 @@ type BaseRequest struct {
Revocation []CredentialTypeIdentifier `json:"revocation,omitempty"` Revocation []CredentialTypeIdentifier `json:"revocation,omitempty"`
// Set by the IRMA server during the session // Set by the IRMA server during the session
Context *big.Int `json:"context,omitempty"` Context *big.Int `json:"context,omitempty"`
Nonce *big.Int `json:"nonce,omitempty"` Nonce *big.Int `json:"nonce,omitempty"`
ProtocolVersion *ProtocolVersion `json:"protocolVersion,omitempty"` ProtocolVersion *ProtocolVersion `json:"protocolVersion,omitempty"`
RevocationUpdates map[CredentialTypeIdentifier][]*revocation.Record `json:"revocationUpdates,omitempty"` RevocationUpdates map[CredentialTypeIdentifier][]*Record `json:"revocationUpdates,omitempty"`
ids *IrmaIdentifierSet // cache for Identifiers() method ids *IrmaIdentifierSet // cache for Identifiers() method
......
...@@ -7,21 +7,75 @@ import ( ...@@ -7,21 +7,75 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation" "github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/gabi/signed" "github.com/privacybydesign/gabi/signed"
"github.com/timshannon/bolthold"
bolt "go.etcd.io/bbolt"
) )
func (conf *Configuration) RevocationKeystore(issuerid IssuerIdentifier) revocation.Keystore { type (
// Keystore provides support for revocation public key rollover.
Keystore interface {
// PublicKey either returns the specified, non-nil public key or an error
PublicKey(counter uint) (*revocation.PublicKey, error)
}
// DB is a bolthold database storing revocation state for a particular accumulator
// (Record instances, and IssuanceRecord instances if used by an issuer).
DB struct {
Current revocation.Accumulator
Updated time.Time
onChange []func(*Record)
bolt *bolthold.Store
keystore Keystore
}
RevocationStorage struct {
dbs map[CredentialTypeIdentifier]*DB
conf *Configuration
}
// Record contains a signed AccumulatorUpdate and associated information.
Record struct {
StartIndex uint64
EndIndex uint64
PublicKeyIndex uint
Message signed.Message // signed revocation.AccumulatorUpdate
}
TimeRecord struct {
Index uint64
Start, End int64
}
// IssuanceRecord contains information generated during issuance, needed for later revocation.
IssuanceRecord struct {
Key string
Attr *big.Int
Issued int64
ValidUntil int64
RevokedAt int64 // 0 if not currently revoked
}
currentRecord struct {
Index uint64
}
)
const boltCurrentIndexKey = "currentIndex"
func (conf *Configuration) RevocationKeystore(issuerid IssuerIdentifier) Keystore {
return &issuerKeystore{issid: issuerid, conf: conf} return &issuerKeystore{issid: issuerid, conf: conf}
} }
// issuerKeystore implements revocation.Keystore. // issuerKeystore implements Keystore.
type issuerKeystore struct { type issuerKeystore struct {
issid IssuerIdentifier issid IssuerIdentifier
conf *Configuration conf *Configuration
} }
var _ revocation.Keystore = (*issuerKeystore)(nil) var _ Keystore = (*issuerKeystore)(nil)
func (ks *issuerKeystore) PublicKey(counter uint) (*revocation.PublicKey, error) { func (ks *issuerKeystore) PublicKey(counter uint) (*revocation.PublicKey, error) {
pk, err := ks.conf.PublicKey(ks.issid, int(counter)) pk, err := ks.conf.PublicKey(ks.issid, int(counter))
...@@ -41,9 +95,304 @@ func (ks *issuerKeystore) PublicKey(counter uint) (*revocation.PublicKey, error) ...@@ -41,9 +95,304 @@ func (ks *issuerKeystore) PublicKey(counter uint) (*revocation.PublicKey, error)
return rpk, nil return rpk, nil
} }
func (conf *Configuration) RevocationGetUpdates(credid CredentialTypeIdentifier, index uint64) ([]*revocation.Record, error) { func (rdb *DB) EnableRevocation(sk *revocation.PrivateKey) error {
var records []*revocation.Record msg, acc, err := revocation.NewAccumulator(sk)
err := NewHTTPTransport(conf.CredentialTypes[credid].RevocationServer). if err != nil {
return err
}
if err = rdb.Add(msg, sk.Counter); err != nil {
return err
}
rdb.Current = acc
return nil
}
// Revoke revokes the credential specified specified by key if found within the current database,
// by updating its revocation time to now, adding its revocation attribute to the current accumulator,
// and updating the revocation database on disk.
func (rdb *DB) Revoke(sk *revocation.PrivateKey, key []byte) error {
return rdb.bolt.Bolt().Update(func(tx *bolt.Tx) error {
var err error
cr := IssuanceRecord{}
if err = rdb.bolt.TxGet(tx, key, &cr); err != nil {
return err
}
cr.RevokedAt = time.Now().UnixNano()
if err = rdb.bolt.TxUpdate(tx, key, &cr); err != nil {
return err
}
return rdb.revokeAttr(sk, cr.Attr, tx)
})
}
// Get returns all records that a client requires to update its revocation state if it is currently
// at the specified index, that is, all records whose end index is greater than or equal to
// the specified index.
func (rdb *DB) RevocationRecords(index int) ([]*Record, error) {
var records []*Record
if err := rdb.bolt.Find(&records, bolthold.Where(bolthold.Key).Ge(uint64(index))); err != nil {
return nil, err
}
return records, nil
}
func (rdb *DB) LatestRecords(count int) ([]*Record, error) {
c := int(rdb.Current.Index) - count + 1
if c < 0 {
c = 0
}
return rdb.RevocationRecords(c)
}
func (rdb *DB) IssuanceRecordExists(key []byte) (bool, error) {
_, err := rdb.IssuanceRecord(key)
switch err {
case nil:
return true, nil
case bolthold.ErrNotFound:
return false, nil
default:
return false, err
}
}
func (rdb *DB) AddIssuanceRecord(r *IssuanceRecord) error {
return rdb.bolt.Insert([]byte(r.Key), r)
}
func (rdb *DB) IssuanceRecord(key []byte) (*IssuanceRecord, error) {
r := &IssuanceRecord{}
if err := rdb.bolt.Get(key, r); err != nil {
return nil, err
}
return r, nil
}
func (rdb *DB) AddRecords(records []*Record) error {
var err error
for _, r := range records {
if err = rdb.Add(r.Message, r.PublicKeyIndex); err != nil {
return err
}
}
rdb.Updated = time.Now() // TODO update this in add()?
return nil
}
func (rdb *DB) Add(updateMsg signed.Message, counter uint) error {
var err error
var update revocation.AccumulatorUpdate
pk, err := rdb.keystore.PublicKey(counter)
if err != nil {
return err