Commit b21f247c authored by Sietse Ringers's avatar Sietse Ringers
Browse files

refactor: change revocation configuration in scheme and server configuration

parent 8d0c0554
......@@ -57,19 +57,19 @@ type Issuer struct {
// CredentialType is a description of a credential type, specifying (a.o.) its name, issuer, and attributes.
type CredentialType struct {
ID string `xml:"CredentialID"`
Name TranslatedString `xml:"Name"`
ShortName TranslatedString `xml:"ShortName"`
IssuerID string `xml:"IssuerID"`
SchemeManagerID string `xml:"SchemeManager"`
IsSingleton bool `xml:"ShouldBeSingleton"`
DisallowDelete bool `xml:"DisallowDelete"`
Description TranslatedString
AttributeTypes []*AttributeType `xml:"Attributes>Attribute" json:"-"`
SupportsRevocation bool
XMLVersion int `xml:"version,attr"`
XMLName xml.Name `xml:"IssueSpecification"`
IssueURL TranslatedString `xml:"IssueURL"`
ID string `xml:"CredentialID"`
Name TranslatedString `xml:"Name"`
ShortName TranslatedString `xml:"ShortName"`
IssuerID string `xml:"IssuerID"`
SchemeManagerID string `xml:"SchemeManager"`
IsSingleton bool `xml:"ShouldBeSingleton"`
DisallowDelete bool `xml:"DisallowDelete"`
Description TranslatedString
AttributeTypes []*AttributeType `xml:"Attributes>Attribute" json:"-"`
RevocationServer string
XMLVersion int `xml:"version,attr"`
XMLName xml.Name `xml:"IssueSpecification"`
IssueURL TranslatedString `xml:"IssueURL"`
Valid bool `xml:"-"`
}
......@@ -98,6 +98,10 @@ func (ad AttributeType) IsOptional() bool {
return ad.Optional == "true"
}
func (ct *CredentialType) SupportsRevocation() bool {
return ct.RevocationServer != ""
}
// ContainsAttribute tests whether the specified attribute is contained in this
// credentialtype.
func (ct *CredentialType) ContainsAttribute(ai AttributeTypeIdentifier) bool {
......
......@@ -148,31 +148,30 @@ func (s *Server) verifyPrivateKeys(configuration *server.Configuration) error {
return server.LogError(errors.Errorf("Private key %s-%d does not belong to corresponding public key", issid.String(), sk.Counter))
}
}
for issid := range s.conf.IrmaConfiguration.Issuers {
sk, err := s.conf.PrivateKey(issid)
return nil
}
func (s *Server) verifyRevocation(configuration *server.Configuration) error {
for credid, settings := range s.conf.RevocationServers {
if _, known := s.conf.IrmaConfiguration.CredentialTypes[credid]; !known {
return server.LogError(errors.Errorf("unknown credential type %s in revocation settings", credid))
}
db, err := s.conf.IrmaConfiguration.RevocationDB(credid)
if err != nil {
return server.LogError(err)
}
if sk == nil || !sk.RevocationSupported() {
continue
}
for credid, credtype := range s.conf.IrmaConfiguration.CredentialTypes {
if credtype.IssuerIdentifier() != issid || !credtype.SupportsRevocation {
continue
}
db, err := s.conf.IrmaConfiguration.RevocationDB(credid)
if err != nil {
return server.LogError(err)
}
if !db.Enabled() {
s.conf.Logger.WithFields(logrus.Fields{"cred": credid}).Warn("revocation supported in scheme but not enabled")
} else {
if err = db.LoadCurrent(); err != nil {
return server.LogError(err)
db.OnChange(func(record *revocation.Record) {
transport := irma.NewHTTPTransport("")
o := struct{}{}
for _, url := range settings.PostURLs {
if err := transport.Post(url+"/-/revocation/records", &o, &[]*revocation.Record{record}); err != nil {
s.conf.Logger.Warn("error sending revocation update", err)
}
s.conf.RevocableCredentials[credid] = struct{}{}
}
}
})
}
return nil
......@@ -221,7 +220,9 @@ func (s *Server) verifyConfiguration(configuration *server.Configuration) error
irma.Logger = s.conf.Logger
// loop to avoid repetetive err != nil line triplets
for _, f := range []func(*server.Configuration) error{s.verifyIrmaConf, s.verifyPrivateKeys, s.verifyURL, s.verifyEmail} {
for _, f := range []func(*server.Configuration) error{
s.verifyIrmaConf, s.verifyPrivateKeys, s.verifyRevocation, s.verifyURL, s.verifyEmail,
} {
if err := f(configuration); err != nil {
return err
}
......@@ -552,9 +553,6 @@ func (s *Server) handleRevocationMessage(
func (s *Server) handlePostRevocationRecords(
cred irma.CredentialTypeIdentifier, records []*revocation.Record,
) (interface{}, *irma.RemoteError) {
if _, ok := s.conf.RevocableCredentials[cred]; !ok {
return nil, server.RemoteError(server.ErrorInvalidRequest, "not supported by this server")
}
db, err := s.conf.IrmaConfiguration.RevocationDB(cred)
if err != nil {
return nil, server.RemoteError(server.ErrorUnknown, err.Error()) // TODO error type
......@@ -569,8 +567,8 @@ func (s *Server) handlePostRevocationRecords(
func (s *Server) handleGetRevocationRecords(
cred irma.CredentialTypeIdentifier, index int,
) ([]revocation.Record, *irma.RemoteError) {
if _, ok := s.conf.RevocableCredentials[cred]; !ok {
) ([]*revocation.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)
......
......@@ -203,7 +203,7 @@ func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentM
var witness *revocation.Witness
var nonrevAttr *big.Int
if session.conf.IrmaConfiguration.CredentialTypes[cred.CredentialTypeID].SupportsRevocation {
if session.conf.IrmaConfiguration.CredentialTypes[cred.CredentialTypeID].SupportsRevocation() {
db, err := session.conf.IrmaConfiguration.RevocationDB(cred.CredentialTypeID)
if err != nil {
return nil, session.fail(server.ErrorIssuanceFailed, err.Error())
......
......@@ -98,7 +98,7 @@ func (s *Server) validateIssuanceRequest(request *irma.IssuanceRequest) error {
if err := cred.Validate(s.conf.IrmaConfiguration); err != nil {
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)
if err != nil {
return err
......
......@@ -341,12 +341,10 @@ func TestOptionalDisclosure(t *testing.T) {
}
}
func editDB(t *testing.T, path string, keystore revocation.Keystore, current bool, f func(*revocation.DB)) {
func editDB(t *testing.T, path string, keystore revocation.Keystore, enabled bool, f func(*revocation.DB)) {
db, err := revocation.LoadDB(path, keystore)
require.NoError(t, err)
if current {
require.NoError(t, db.LoadCurrent())
}
require.True(t, !enabled || db.Enabled())
f(db)
require.NoError(t, db.Close())
}
......@@ -354,7 +352,7 @@ func editDB(t *testing.T, path string, keystore revocation.Keystore, current boo
func revocationSession(t *testing.T, client *irmaclient.Client, options ...sessionOption) *requestorSessionResult {
attr := irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.root.BSN")
req := irma.NewDisclosureRequest(attr)
req.Revocation = irma.RevocationSet{attr.CredentialTypeIdentifier(): struct{}{}}
req.Revocation = []irma.CredentialTypeIdentifier{attr.CredentialTypeIdentifier()}
result := requestorSessionHelper(t, req, client, options...)
require.Nil(t, result.Err)
return result
......
......@@ -60,6 +60,9 @@ func StartIrmaServer(t *testing.T, updatedIrmaConf bool) {
Logger: logger,
SchemesPath: filepath.Join(testdata, irmaconf),
RevocationPath: filepath.Join(testdata, "storage", "revocation"),
RevocationServers: map[irma.CredentialTypeIdentifier]server.RevocationServer{
irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root"): {},
},
})
require.NoError(t, err)
......
......@@ -250,16 +250,8 @@ func configureServer(cmd *cobra.Command) error {
}
// Handle requestors
var requestors map[string]interface{}
if val, flagOrEnv := viper.Get("requestors").(string); !flagOrEnv || val != "" {
if requestors, err = cast.ToStringMapE(viper.Get("requestors")); err != nil {
return errors.WrapPrefix(err, "Failed to unmarshal requestors from flag or env var", 0)
}
}
if len(requestors) > 0 {
if err := mapstructure.Decode(requestors, &conf.Requestors); err != nil {
return errors.WrapPrefix(err, "Failed to unmarshal requestors from config file", 0)
}
if err = handleMapOrString("requestors", &conf.Requestors); err != nil {
return err
}
logger.Debug("Done configuring")
......@@ -267,6 +259,23 @@ func configureServer(cmd *cobra.Command) error {
return nil
}
func handleMapOrString(key string, dest interface{}) error {
var m map[string]interface{}
var err error
if val, flagOrEnv := viper.Get(key).(string); !flagOrEnv || val != "" {
if m, err = cast.ToStringMapE(viper.Get(key)); err != nil {
return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from flag or env var", 0)
}
}
if len(m) == 0 {
return nil
}
if err := mapstructure.Decode(m, dest); err != nil {
return errors.WrapPrefix(err, "Failed to unmarshal "+key+" from config file", 0)
}
return nil
}
func handlePermission(typ string) []string {
if !viper.IsSet(typ) && (!viper.GetBool("production") || typ != "issue-perms") {
return []string{"*"}
......
......@@ -29,13 +29,13 @@ type BaseRequest struct {
// Revocation instructs the client to include nonrevocation zero-knowledge proofs for the
// specified credential types.
Revocation RevocationSet `json:"revocation,omitempty"`
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][]*revocation.Record `json:"revocationUpdates,omitempty"`
ids *IrmaIdentifierSet // cache for Identifiers() method
......@@ -45,33 +45,6 @@ type BaseRequest struct {
ClientReturnURL string `json:"clientReturnUrl,omitempty"` // URL to proceed to when IRMA session is completed
}
type RevocationSet map[CredentialTypeIdentifier]struct{}
func (r *RevocationSet) MarshalJSON() ([]byte, error) {
if r == nil {
return json.Marshal(nil)
}
l := make([]CredentialTypeIdentifier, 0, len(*r))
for c := range *r {
l = append(l, c)
}
return json.Marshal(l)
}
func (r *RevocationSet) UnmarshalJSON(bts []byte) error {
var l []CredentialTypeIdentifier
if err := json.Unmarshal(bts, &l); err != nil {
return err
}
if *r == nil {
*r = RevocationSet{}
}
for _, c := range l {
(*r)[c] = struct{}{}
}
return nil
}
// An AttributeCon is only satisfied if all of its containing attribute requests are satisfied.
type AttributeCon []AttributeRequest
......@@ -244,8 +217,8 @@ func (b *BaseRequest) SetRevocationRecords(conf *Configuration) error {
if len(b.Revocation) == 0 {
return nil
}
b.RevocationUpdates = make(map[CredentialTypeIdentifier][]revocation.Record, len(b.Revocation))
for credid := range b.Revocation {
b.RevocationUpdates = make(map[CredentialTypeIdentifier][]*revocation.Record, len(b.Revocation))
for _, credid := range b.Revocation {
db, err := conf.RevocationDB(credid)
if err != nil {
return err
......
......@@ -40,10 +40,6 @@ type Configuration struct {
IssuerPrivateKeysPath string `json:"privkeys" mapstructure:"privkeys"`
// Issuer private keys
IssuerPrivateKeys map[irma.IssuerIdentifier]*gabi.PrivateKey `json:"-"`
// Path at which to store revocation databases
RevocationPath string `json:"revocation_path" mapstructure:"revocation_path"`
// Credentials types for which revocation database should be hosted
RevocableCredentials map[irma.CredentialTypeIdentifier]struct{} `json:"-"`
// URL at which the IRMA app can reach this server during sessions
URL string `json:"url" mapstructure:"url"`
// Required to be set to true if URL does not begin with https:// in production mode.
......@@ -66,10 +62,19 @@ type Configuration struct {
// Custom logger instance. If specified, Verbose, Quiet and LogJSON are ignored.
Logger *logrus.Logger `json:"-"`
// Path at which to store revocation databases
RevocationPath string `json:"revocation_path" mapstructure:"revocation_path"`
// Credentials types for which revocation database should be hosted
RevocationServers map[irma.CredentialTypeIdentifier]RevocationServer `json:"revocation_servers" mapstructure:"revocation_servers"`
// Production mode: enables safer and stricter defaults and config checking
Production bool `json:"production" mapstructure:"production"`
}
type RevocationServer struct {
PostURLs []string `json:"post_urls" mapstructure:"post_urls"`
}
type SessionPackage struct {
SessionPtr *irma.Qr `json:"sessionPtr"`
Token string `json:"token"`
......
......@@ -48,8 +48,7 @@ type Configuration struct {
ClientTlsPrivateKeyFile string `json:"client_tls_privkey_file" mapstructure:"client_tls_privkey_file"`
// Requestor-specific permission and authentication configuration
RequestorsString string `json:"-" mapstructure:"requestors"`
Requestors map[string]Requestor `json:"requestors"`
Requestors map[string]Requestor `json:"requestors"`
// Used in the "iss" field of result JWTs from /result-jwt and /getproof
JwtIssuer string `json:"jwt_issuer" mapstructure:"jwt_issuer"`
......
......@@ -16,7 +16,7 @@
</Description>
<IssueURL><en></en><nl></nl></IssueURL>
<ShouldBeSingleton>true</ShouldBeSingleton>
<SupportsRevocation>true</SupportsRevocation>
<RevocationServer>http://localhost:48683/</RevocationServer>
<Attributes>
<Attribute id="BSN">
......
1eeaa044eb9bc9177986762311d169016dfbe782688f668ddf4cfd804b4beeba irma-demo/MijnOverheid/Issues/fullName/description.xml
61a1fc7f161e43f8fc5b0c6ac2997cfe6bc0da7d27009b9914a04dca79ec6718 irma-demo/MijnOverheid/Issues/fullName/logo.png
1ddecad4a185894d203334b7a8903a0e4e648d949857009b10d376f737f5f2ac irma-demo/MijnOverheid/Issues/root/description.xml
77d6ce26354d573d6da40c5a2eb3f380b8ea42a6af59b0c927e55d5fb17bf2a4 irma-demo/MijnOverheid/Issues/root/description.xml
61a1fc7f161e43f8fc5b0c6ac2997cfe6bc0da7d27009b9914a04dca79ec6718 irma-demo/MijnOverheid/Issues/root/logo.png
3571e30777cdf5b97acbb0820f1b69983d2dc2b6bae91c8fb67cfc79ef4e2543 irma-demo/MijnOverheid/PublicKeys/0.xml
db0fdbe65ee9519290b756198a0d10b47c2af417e37843a2e790f5cc0e82d282 irma-demo/MijnOverheid/PublicKeys/1.xml
......@@ -15,4 +15,4 @@ dbd465d9cdb1c64206443e425fb1f8950605aee35e77f1e8bcf6cca8c34b8b65 irma-demo/RU/Pu
a4f6cc35cace3e9dc9388b29a8756ea83e5884f799d75cadd4efa60e1a12d855 irma-demo/RU/description.xml
35697bb7ffb19518a0ac6739ac3eef6b0272cd322c4619b075328b88c06ac43d irma-demo/RU/logo.png
ab4e98001906a4ad118ddb82794ef24e9f356980e15753f59d4720747f684e5b irma-demo/description.xml
2d95190ae9be3302a72453cc0ea22476cc38335188b05794b96c18d2c0d6e127 irma-demo/timestamp
aacd94be69cdb24da6d3bd57aa746bc1b90221e0fe3ef36671beb15fc47e4513 irma-demo/timestamp
......@@ -16,7 +16,7 @@
</Description>
<IssueURL><en></en><nl></nl></IssueURL>
<ShouldBeSingleton>true</ShouldBeSingleton>
<SupportsRevocation>true</SupportsRevocation>
<RevocationServer>http://localhost:48683/</RevocationServer>
<Attributes>
<Attribute id="BSN">
......
1eeaa044eb9bc9177986762311d169016dfbe782688f668ddf4cfd804b4beeba irma-demo/MijnOverheid/Issues/fullName/description.xml
61a1fc7f161e43f8fc5b0c6ac2997cfe6bc0da7d27009b9914a04dca79ec6718 irma-demo/MijnOverheid/Issues/fullName/logo.png
1ddecad4a185894d203334b7a8903a0e4e648d949857009b10d376f737f5f2ac irma-demo/MijnOverheid/Issues/root/description.xml
77d6ce26354d573d6da40c5a2eb3f380b8ea42a6af59b0c927e55d5fb17bf2a4 irma-demo/MijnOverheid/Issues/root/description.xml
61a1fc7f161e43f8fc5b0c6ac2997cfe6bc0da7d27009b9914a04dca79ec6718 irma-demo/MijnOverheid/Issues/root/logo.png
3571e30777cdf5b97acbb0820f1b69983d2dc2b6bae91c8fb67cfc79ef4e2543 irma-demo/MijnOverheid/PublicKeys/0.xml
db0fdbe65ee9519290b756198a0d10b47c2af417e37843a2e790f5cc0e82d282 irma-demo/MijnOverheid/PublicKeys/1.xml
......@@ -15,4 +15,4 @@ dbd465d9cdb1c64206443e425fb1f8950605aee35e77f1e8bcf6cca8c34b8b65 irma-demo/RU/Pu
a4f6cc35cace3e9dc9388b29a8756ea83e5884f799d75cadd4efa60e1a12d855 irma-demo/RU/description.xml
35697bb7ffb19518a0ac6739ac3eef6b0272cd322c4619b075328b88c06ac43d irma-demo/RU/logo.png
ab4e98001906a4ad118ddb82794ef24e9f356980e15753f59d4720747f684e5b irma-demo/description.xml
a06116f793be348f3a90b4fe5d1033e16487bb00ec722ed7a1d4d84384af869a irma-demo/timestamp
2702ed3b26876ec34306d69746286519afc378126afffdc9f47a4a02eba3a1b3 irma-demo/timestamp
......@@ -16,7 +16,7 @@
</Description>
<IssueURL><en></en><nl></nl></IssueURL>
<ShouldBeSingleton>true</ShouldBeSingleton>
<SupportsRevocation>true</SupportsRevocation>
<RevocationServer>http://localhost:48683/</RevocationServer>
<Attributes>
<Attribute id="BSN">
......
1eeaa044eb9bc9177986762311d169016dfbe782688f668ddf4cfd804b4beeba irma-demo/MijnOverheid/Issues/fullName/description.xml
61a1fc7f161e43f8fc5b0c6ac2997cfe6bc0da7d27009b9914a04dca79ec6718 irma-demo/MijnOverheid/Issues/fullName/logo.png
1ddecad4a185894d203334b7a8903a0e4e648d949857009b10d376f737f5f2ac irma-demo/MijnOverheid/Issues/root/description.xml
77d6ce26354d573d6da40c5a2eb3f380b8ea42a6af59b0c927e55d5fb17bf2a4 irma-demo/MijnOverheid/Issues/root/description.xml
61a1fc7f161e43f8fc5b0c6ac2997cfe6bc0da7d27009b9914a04dca79ec6718 irma-demo/MijnOverheid/Issues/root/logo.png
3571e30777cdf5b97acbb0820f1b69983d2dc2b6bae91c8fb67cfc79ef4e2543 irma-demo/MijnOverheid/PublicKeys/0.xml
db0fdbe65ee9519290b756198a0d10b47c2af417e37843a2e790f5cc0e82d282 irma-demo/MijnOverheid/PublicKeys/1.xml
......@@ -15,4 +15,4 @@ dbd465d9cdb1c64206443e425fb1f8950605aee35e77f1e8bcf6cca8c34b8b65 irma-demo/RU/Pu
a4f6cc35cace3e9dc9388b29a8756ea83e5884f799d75cadd4efa60e1a12d855 irma-demo/RU/description.xml
35697bb7ffb19518a0ac6739ac3eef6b0272cd322c4619b075328b88c06ac43d irma-demo/RU/logo.png
ab4e98001906a4ad118ddb82794ef24e9f356980e15753f59d4720747f684e5b irma-demo/description.xml
a06116f793be348f3a90b4fe5d1033e16487bb00ec722ed7a1d4d84384af869a irma-demo/timestamp
2702ed3b26876ec34306d69746286519afc378126afffdc9f47a4a02eba3a1b3 irma-demo/timestamp
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