Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
IRMA
Github mirrors
irmago
Commits
786f0836
Commit
786f0836
authored
Sep 16, 2019
by
Sietse Ringers
Browse files
refactor: move revocation.DB and related structs from gabi to root package
parent
2919f416
Changes
11
Hide whitespace changes
Inline
Side-by-side
internal/servercore/api.go
View file @
786f0836
...
...
@@ -14,7 +14,6 @@ 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"
...
...
@@ -54,7 +53,7 @@ func New(conf *server.Configuration) (*Server, error) {
// TODO rethink this condition
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
())
_
=
server
.
LogError
(
err
)
}
...
...
@@ -67,7 +66,7 @@ func New(conf *server.Configuration) (*Server, error) {
}
func
(
s
*
Server
)
Stop
()
{
if
err
:=
s
.
conf
.
IrmaConfiguration
.
Close
();
err
!=
nil
{
if
err
:=
s
.
conf
.
IrmaConfiguration
.
RevocationStorage
.
Close
();
err
!=
nil
{
_
=
server
.
LogWarning
(
err
)
}
s
.
stopScheduler
<-
true
...
...
@@ -141,7 +140,7 @@ func (s *Server) CancelSession(token 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
)
{
...
...
@@ -387,7 +386,7 @@ func (s *Server) handleRevocationMessage(
return
server
.
JsonResponse
(
nil
,
server
.
RemoteError
(
server
.
ErrorInvalidRequest
,
"POST records expects 1 url arguments"
))
}
cred
:=
irma
.
NewCredentialTypeIdentifier
(
args
[
0
])
var
records
[]
*
revocation
.
Record
var
records
[]
*
irma
.
Record
if
err
:=
json
.
Unmarshal
(
message
,
&
records
);
err
!=
nil
{
return
server
.
JsonResponse
(
nil
,
server
.
RemoteError
(
server
.
ErrorMalformedInput
,
err
.
Error
()))
}
...
...
internal/servercore/handle.go
View file @
786f0836
...
...
@@ -4,7 +4,6 @@ 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"
...
...
@@ -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
// was started, so that the client always gets the very latest revocation records
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
}
...
...
@@ -216,9 +215,9 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM
}
func
(
s
*
Server
)
handlePostRevocationRecords
(
cred
irma
.
CredentialTypeIdentifier
,
records
[]
*
revocation
.
Record
,
cred
irma
.
CredentialTypeIdentifier
,
records
[]
*
irma
.
Record
,
)
(
interface
{},
*
irma
.
RemoteError
)
{
db
,
err
:=
s
.
conf
.
IrmaConfiguration
.
RevocationDB
(
cred
)
db
,
err
:=
s
.
conf
.
IrmaConfiguration
.
RevocationStorage
.
RevocationDB
(
cred
)
if
err
!=
nil
{
return
nil
,
server
.
RemoteError
(
server
.
ErrorUnknown
,
err
.
Error
())
// TODO error type
}
...
...
@@ -230,11 +229,11 @@ func (s *Server) handlePostRevocationRecords(
func
(
s
*
Server
)
handleGetRevocationRecords
(
cred
irma
.
CredentialTypeIdentifier
,
index
int
,
)
([]
*
revocation
.
Record
,
*
irma
.
RemoteError
)
{
)
([]
*
irma
.
Record
,
*
irma
.
RemoteError
)
{
if
_
,
ok
:=
s
.
conf
.
RevocationServers
[
cred
];
!
ok
{
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
{
return
nil
,
server
.
RemoteError
(
server
.
ErrorUnknown
,
err
.
Error
())
// TODO error type
}
...
...
@@ -265,13 +264,13 @@ func (s *Server) handlePostIssuanceRecord(
if
err
!=
nil
{
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
{
return
""
,
server
.
RemoteError
(
server
.
ErrorUnauthorized
,
err
.
Error
())
}
// Insert the record into the database
db
,
err
:=
s
.
conf
.
IrmaConfiguration
.
RevocationDB
(
cred
)
db
,
err
:=
s
.
conf
.
IrmaConfiguration
.
RevocationStorage
.
RevocationDB
(
cred
)
if
err
!=
nil
{
return
""
,
server
.
RemoteError
(
server
.
ErrorUnknown
,
err
.
Error
())
}
...
...
internal/servercore/helpers.go
View file @
786f0836
...
...
@@ -85,12 +85,12 @@ func (session *session) issuanceHandleRevocation(
// ensure the client always gets an up to date nonrevocation witness
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
}
}
db
,
err
:=
session
.
conf
.
IrmaConfiguration
.
RevocationDB
(
cred
.
CredentialTypeID
)
db
,
err
:=
session
.
conf
.
IrmaConfiguration
.
RevocationStorage
.
RevocationDB
(
cred
.
CredentialTypeID
)
if
err
!=
nil
{
return
}
...
...
@@ -102,13 +102,13 @@ func (session *session) issuanceHandleRevocation(
return
}
nonrevAttr
=
witness
.
E
issrecord
:=
&
revocation
.
IssuanceRecord
{
issrecord
:=
&
irma
.
IssuanceRecord
{
Key
:
cred
.
RevocationKey
,
Attr
:
nonrevAttr
,
Issued
:
time
.
Now
()
.
UnixNano
(),
// or (floored) cred issuance time?
ValidUntil
:
attributes
.
Expiry
()
.
UnixNano
(),
}
err
=
session
.
conf
.
IrmaConfiguration
.
SendRevocationIssuanceRecord
(
cred
.
CredentialTypeID
,
issrecord
)
err
=
session
.
conf
.
IrmaConfiguration
.
RevocationStorage
.
SendRevocationIssuanceRecord
(
cred
.
CredentialTypeID
,
issrecord
)
if
err
!=
nil
{
_
=
server
.
LogWarning
(
errors
.
WrapPrefix
(
err
,
"Failed to send issuance record to revocation server"
,
0
))
session
.
conf
.
Logger
.
Warn
(
"Storing issuance record locally"
)
...
...
@@ -144,7 +144,7 @@ func (s *Server) validateIssuanceRequest(request *irma.IssuanceRequest) error {
return
err
}
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
{
return
err
}
...
...
internal/sessiontest/requestor_test.go
View file @
786f0836
...
...
@@ -6,13 +6,10 @@ import (
"io/ioutil"
"net/http"
"path/filepath"
"reflect"
"testing"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/test"
"github.com/privacybydesign/irmago/irmaclient"
...
...
@@ -352,20 +349,7 @@ func TestRevocation(t *testing.T) {
// setup client, constants, and revocation key material
defer
test
.
ClearTestStorage
(
t
)
client
,
_
:=
parseStorage
(
t
)
iss
:=
irma
.
NewIssuerIdentifier
(
"irma-demo.MijnOverheid"
)
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
)
// issue two MijnOverheid.root instances with revocation enabled
...
...
internal/sessiontest/server_test.go
View file @
786f0836
...
...
@@ -51,15 +51,24 @@ func StopRequestorServer() {
func
StartRevocationServer
(
t
*
testing
.
T
)
{
var
err
error
revocationServer
,
err
=
irmaserver
.
New
(
&
server
.
Configuration
{
cred
:=
irma
.
NewCredentialTypeIdentifier
(
"irma-demo.MijnOverheid.root"
)
conf
:=
&
server
.
Configuration
{
Logger
:
logger
,
DisableSchemesUpdate
:
true
,
SchemesPath
:
filepath
.
Join
(
testdata
,
"irma_configuration"
),
RevocationPath
:
filepath
.
Join
(
testdata
,
"tmp"
,
"issuer"
),
// todo rename this path to revocation?
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
)
mux
:=
http
.
NewServeMux
()
...
...
irmaclient/credential.go
View file @
786f0836
...
...
@@ -51,8 +51,7 @@ func (cred *credential) PrepareNonrevocation(conf *irma.Configuration, request i
revupdates
:=
m
[
credtype
]
nonrev
:=
len
(
revupdates
)
>
0
keystore
:=
conf
.
RevocationKeystore
(
credtype
.
IssuerIdentifier
())
if
updated
,
err
:=
cred
.
NonRevocationWitness
.
Update
(
revupdates
,
keystore
);
err
!=
nil
{
if
updated
,
err
:=
conf
.
RevocationStorage
.
UpdateWitness
(
cred
.
NonRevocationWitness
,
revupdates
,
credtype
.
IssuerIdentifier
());
err
!=
nil
{
return
false
,
err
}
else
if
updated
{
cred
.
DiscardRevocationCache
()
...
...
@@ -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,
// i.e. we were too far behind. Update from revocation server.
re
cord
s
,
err
:=
conf
.
RevocationGetUpdates
(
credtype
,
cred
.
NonRevocationWitness
.
Index
+
1
)
re
vupdate
s
,
err
:=
conf
.
RevocationStorage
.
RevocationGetUpdates
(
credtype
,
cred
.
NonRevocationWitness
.
Index
+
1
)
if
err
!=
nil
{
return
nonrev
,
err
}
_
,
err
=
c
red
.
NonRevocationWitness
.
Update
(
records
,
keystore
)
_
,
err
=
c
onf
.
RevocationStorage
.
UpdateWitness
(
cred
.
NonRevocationWitness
,
revupdates
,
credtype
.
IssuerIdentifier
()
)
return
nonrev
,
err
}
irmaconfig.go
View file @
786f0836
...
...
@@ -33,7 +33,6 @@ import (
"github.com/jasonlvhit/gocron"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation"
"github.com/privacybydesign/gabi/signed"
"github.com/privacybydesign/irmago/internal/fs"
)
...
...
@@ -46,6 +45,8 @@ type Configuration struct {
CredentialTypes
map
[
CredentialTypeIdentifier
]
*
CredentialType
AttributeTypes
map
[
AttributeTypeIdentifier
]
*
AttributeType
RevocationStorage
*
RevocationStorage
// Path to the irma_configuration folder that this instance represents
Path
string
RevocationPath
string
...
...
@@ -60,7 +61,6 @@ type Configuration struct {
publicKeys
map
[
IssuerIdentifier
]
map
[
int
]
*
gabi
.
PublicKey
privateKeys
map
[
IssuerIdentifier
]
*
gabi
.
PrivateKey
reverseHashes
map
[
string
]
CredentialTypeIdentifier
revDBs
map
[
CredentialTypeIdentifier
]
*
revocation
.
DB
initialized
bool
assets
string
readOnly
bool
...
...
@@ -143,6 +143,7 @@ func newConfiguration(path string, assets string) (conf *Configuration, err erro
RevocationPath
:
filepath
.
Join
(
DefaultDataPath
(),
"revocation"
),
assets
:
assets
,
}
conf
.
RevocationStorage
=
&
RevocationStorage
{
conf
:
conf
}
if
conf
.
assets
!=
""
{
// If an assets folder is specified, then it must exist
if
err
=
fs
.
AssertPathExists
(
conf
.
assets
);
err
!=
nil
{
...
...
requests.go
View file @
786f0836
...
...
@@ -13,7 +13,6 @@ 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"
)
...
...
@@ -33,10 +32,10 @@ type BaseRequest struct {
Revocation
[]
CredentialTypeIdentifier
`json:"revocation,omitempty"`
// Set by the IRMA server during the session
Context
*
big
.
Int
`json:"context,omitempty"`
Nonce
*
big
.
Int
`json:"nonce,omitempty"`
ProtocolVersion
*
ProtocolVersion
`json:"protocolVersion,omitempty"`
RevocationUpdates
map
[
CredentialTypeIdentifier
][]
*
revocation
.
Record
`json:"revocationUpdates,omitempty"`
Context
*
big
.
Int
`json:"context,omitempty"`
Nonce
*
big
.
Int
`json:"nonce,omitempty"`
ProtocolVersion
*
ProtocolVersion
`json:"protocolVersion,omitempty"`
RevocationUpdates
map
[
CredentialTypeIdentifier
][]
*
Record
`json:"revocationUpdates,omitempty"`
ids
*
IrmaIdentifierSet
// cache for Identifiers() method
...
...
revocation.go
View file @
786f0836
...
...
@@ -7,21 +7,75 @@ import (
"github.com/go-errors/errors"
"github.com/hashicorp/go-multierror"
"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/revocation"
"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
}
}
// issuerKeystore implements
revocation.
Keystore.
// issuerKeystore implements Keystore.
type
issuerKeystore
struct
{
issid
IssuerIdentifier
conf
*
Configuration
}
var
_
revocation
.
Keystore
=
(
*
issuerKeystore
)(
nil
)
var
_
Keystore
=
(
*
issuerKeystore
)(
nil
)
func
(
ks
*
issuerKeystore
)
PublicKey
(
counter
uint
)
(
*
revocation
.
PublicKey
,
error
)
{
pk
,
err
:=
ks
.
conf
.
PublicKey
(
ks
.
issid
,
int
(
counter
))
...
...
@@ -41,9 +95,304 @@ func (ks *issuerKeystore) PublicKey(counter uint) (*revocation.PublicKey, error)
return
rpk
,
nil
}
func
(
conf
*
Configuration
)
RevocationGetUpdates
(
credid
CredentialTypeIdentifier
,
index
uint64
)
([]
*
revocation
.
Record
,
error
)
{
var
records
[]
*
revocation
.
Record
err
:=
NewHTTPTransport
(
conf
.
CredentialTypes
[
credid
]
.
RevocationServer
)
.
func
(
rdb
*
DB
)
EnableRevocation
(
sk
*
revocation
.
PrivateKey
)
error
{
msg
,
acc
,
err
:=
revocation
.
NewAccumulator
(
sk
)
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
}
if
err
=
signed
.
UnmarshalVerify
(
pk
.
ECDSA
,
updateMsg
,
&
update
);
err
!=
nil
{
return
err
}
return
rdb
.
bolt
.
Bolt
()
.
Update
(
func
(
tx
*
bolt
.
Tx
)
error
{
return
rdb
.
add
(
update
,
updateMsg
,
counter
,
tx
)
})
}
func
(
rdb
*
DB
)
add
(
update
revocation
.
AccumulatorUpdate
,
updateMsg
signed
.
Message
,
pkCounter
uint
,
tx
*
bolt
.
Tx
)
error
{
var
err
error
record
:=
&
Record
{
StartIndex
:
update
.
StartIndex
,
EndIndex
:
update
.
Accumulator
.
Index
,
PublicKeyIndex
:
pkCounter
,
Message
:
updateMsg
,
}
if
err
=
rdb
.
bolt
.
TxInsert
(
tx
,
update
.
Accumulator
.
Index
,
record
);
err
!=
nil
{
return
err
}
if
update
.
Accumulator
.
Index
!=
0
{
var
tr
TimeRecord
if
err
=
rdb
.
bolt
.
TxGet
(
tx
,
update
.
Accumulator
.
Index
-
1
,
&
tr
);
err
==
nil
{
tr
.
End
=
time
.
Now
()
.
UnixNano
()
if
err
=
rdb
.
bolt
.
TxUpdate
(
tx
,
update
.
Accumulator
.
Index
-
1
,
&
tr
);
err
!=
nil
{
return
err
}
}
}
if
err
=
rdb
.
bolt
.
TxInsert
(
tx
,
update
.
Accumulator
.
Index
,
&
TimeRecord
{
Index
:
update
.
Accumulator
.
Index
,
Start
:
time
.
Now
()
.
UnixNano
(),
});
err
!=
nil
{
return
err
}
if
err
=
rdb
.
bolt
.
TxUpsert
(
tx
,
boltCurrentIndexKey
,
&
currentRecord
{
update
.
Accumulator
.
Index
});
err
!=
nil
{
return
err
}
for
_
,
f
:=
range
rdb
.
onChange
{
f
(
record
)
}
rdb
.
Current
=
update
.
Accumulator
return
nil
}
func
(
rdb
*
DB
)
Enabled
()
bool
{
var
currentIndex
currentRecord
err
:=
rdb
.
bolt
.
Get
(
boltCurrentIndexKey
,
&
currentIndex
)
return
err
==
nil
}
func
(
rdb
*
DB
)
loadCurrent
()
error
{
var
currentIndex
currentRecord
if
err
:=
rdb
.
bolt
.
Get
(
boltCurrentIndexKey
,
&
currentIndex
);
err
==
bolthold
.
ErrNotFound
{
return
errors
.
New
(
"revocation database not initialized"
)
}
else
if
err
!=
nil
{
return
err
}
var
record
Record
if
err
:=
rdb
.
bolt
.
Get
(
currentIndex
.
Index
,
&
record
);
err
!=
nil
{
return
err
}
pk
,
err
:=
rdb
.
keystore
.
PublicKey
(
record
.
PublicKeyIndex
)
if
err
!=
nil
{
return
err
}
var
u
revocation
.
AccumulatorUpdate
if
err
=
signed
.
UnmarshalVerify
(
pk
.
ECDSA
,
record
.
Message
,
&
u
);
err
!=
nil
{
return
err
}
rdb
.
Current
=
u
.
Accumulator
return
nil
}
func
(
rdb
*
DB
)
RevokeAttr
(
sk
*
revocation
.
PrivateKey
,
e
*
big
.
Int
)
error
{
return
rdb
.
bolt
.
Bolt
()
.
Update
(
func
(
tx
*
bolt
.
Tx
)
error
{
return
rdb
.
revokeAttr
(
sk
,
e
,
tx
)
})
}
func
(
rdb
*
DB
)
revokeAttr
(
sk
*
revocation
.
PrivateKey
,
e
*
big
.
Int
,
tx
*
bolt
.
Tx
)
error
{
// don't update rdb.Current until after all possible errors are handled
newAcc
,
err
:=
rdb
.
Current
.
Remove
(
sk
,
e
)
if
err
!=
nil
{
return
err
}
update
:=
revocation
.
AccumulatorUpdate
{
Accumulator
:
*
newAcc
,
StartIndex
:
newAcc
.
Index
,
Revoked
:
[]
*
big
.
Int
{
e
},
Time
:
time
.
Now
()
.
UnixNano
(),
}
updateMsg
,
err
:=
signed
.
MarshalSign
(
sk
.
ECDSA
,
update
)
if
err
!=
nil
{
return
err
}
if
err
=
rdb
.
add
(
update
,
updateMsg
,
sk
.
Counter
,
tx
);
err
!=
nil
{
return
err
}
rdb
.
Current
=
*
newAcc
return
nil
}
func
(
rdb
*
DB
)
Close
()
error
{
rdb
.
onChange
=
nil
if
rdb
.
bolt
!=
nil
{
return
rdb
.
bolt
.
Close
()
}
return
nil
}
func
(
rdb
*
DB
)
OnChange
(
handler
func
(
*
Record
))
{
rdb
.
onChange
=
append
(
rdb
.
onChange
,
handler
)
}
func
(
r
*
Record
)
UnmarshalVerify
(
keystore
Keystore
)
(
*
revocation
.
AccumulatorUpdate
,
error
)
{
pk
,
err
:=
keystore
.
PublicKey
(
r
.
PublicKeyIndex
)
if
err
!=
nil
{
return
nil
,
err
}
msg
:=
&
revocation
.
AccumulatorUpdate
{}
if
err
:=
signed
.
UnmarshalVerify
(
pk
.
ECDSA
,
r
.
Message
,
msg
);
err
!=
nil
{
return
nil
,
err
}
if
(
r
.
StartIndex
!=
msg
.
StartIndex
)
||
(
r
.
EndIndex
>
0
&&
r
.
EndIndex
!=
msg
.
StartIndex
+
uint64
(
len
(
msg
.
Revoked
))
-
1
)
{
return
nil
,
errors
.
New
(
"record has invalid start or end index"
)
}
return
msg
,
nil
}
func
(
rs
*
RevocationStorage
)
LoadDB
(
credid
CredentialTypeIdentifier
)
(
*
DB
,
error
)
{
path
:=
filepath
.
Join
(
rs
.
conf
.
RevocationPath
,
credid
.
String
())
keystore
:=
rs
.
conf
.
RevocationKeystore
(
credid
.
IssuerIdentifier
())
b
,
err
:=
bolthold
.
Open
(
path
,
0600
,
&
bolthold
.
Options
{
Options
:
&
bolt
.
Options
{
Timeout
:
1
*
time
.
Second
}})
if
err
!=
nil
{
return
nil
,
err
}
db
:=
&
DB
{
bolt
:
b
,
keystore
:
keystore
,
}
if
db
.
Enabled
()
{