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
33848ed3
Commit
33848ed3
authored
Oct 05, 2017
by
Sietse Ringers
Browse files
Merge dynamic irma_configuration downloading
parents
235c5e6b
4140d9cb
Changes
11
Hide whitespace changes
Inline
Side-by-side
configstore.go
View file @
33848ed3
...
...
@@ -10,16 +10,22 @@ import (
"crypto/sha256"
"fmt"
"strings"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
// ConfigurationStore keeps track of scheme managers, issuers, credential types and public keys.
// ConfigurationStore keeps track of scheme managers, issuers, credential types and public keys,
// dezerializing them from an irma_configuration folder, and downloads and saves new ones on demand.
type
ConfigurationStore
struct
{
SchemeManagers
map
[
SchemeManagerIdentifier
]
*
SchemeManager
Issuers
map
[
IssuerIdentifier
]
*
Issuer
CredentialTypes
map
[
CredentialTypeIdentifier
]
*
CredentialType
publicKeys
map
[
IssuerIdentifier
]
[
]
*
gabi
.
PublicKey
publicKeys
map
[
IssuerIdentifier
]
map
[
int
]
*
gabi
.
PublicKey
reverseHashes
map
[
string
]
CredentialTypeIdentifier
path
string
initialized
bool
...
...
@@ -32,19 +38,13 @@ func NewConfigurationStore(path string, assets string) (store *ConfigurationStor
path
:
path
,
}
var
exist
bool
if
exist
,
err
=
PathExists
(
store
.
path
);
err
!=
nil
{
if
err
=
ensureDirectoryExists
(
store
.
path
);
err
!=
nil
{
return
nil
,
err
}
if
!
exist
{
if
err
=
ensureDirectoryExists
(
store
.
path
);
err
!=
nil
{
if
assets
!=
""
{
if
err
=
store
.
Copy
(
assets
,
false
);
err
!=
nil
{
return
nil
,
err
}
if
assets
!=
""
{
if
err
=
store
.
Copy
(
assets
,
false
);
err
!=
nil
{
return
nil
,
err
}
}
}
return
...
...
@@ -57,7 +57,8 @@ func (store *ConfigurationStore) ParseFolder() error {
store
.
SchemeManagers
=
make
(
map
[
SchemeManagerIdentifier
]
*
SchemeManager
)
store
.
Issuers
=
make
(
map
[
IssuerIdentifier
]
*
Issuer
)
store
.
CredentialTypes
=
make
(
map
[
CredentialTypeIdentifier
]
*
CredentialType
)
store
.
publicKeys
=
make
(
map
[
IssuerIdentifier
][]
*
gabi
.
PublicKey
)
store
.
publicKeys
=
make
(
map
[
IssuerIdentifier
]
map
[
int
]
*
gabi
.
PublicKey
)
store
.
reverseHashes
=
make
(
map
[
string
]
CredentialTypeIdentifier
)
err
:=
iterateSubfolders
(
store
.
path
,
func
(
dir
string
)
error
{
...
...
@@ -82,19 +83,12 @@ func (store *ConfigurationStore) ParseFolder() error {
// PublicKey returns the specified public key, or nil if not present in the ConfigurationStore.
func
(
store
*
ConfigurationStore
)
PublicKey
(
id
IssuerIdentifier
,
counter
int
)
(
*
gabi
.
PublicKey
,
error
)
{
if
_
,
contains
:=
store
.
publicKeys
[
id
];
!
contains
{
store
.
publicKeys
[
id
]
=
[]
*
gabi
.
PublicKey
{}
err
:=
store
.
parseKeysFolder
(
id
)
if
err
!=
nil
{
store
.
publicKeys
[
id
]
=
map
[
int
]
*
gabi
.
PublicKey
{}
if
err
:=
store
.
parseKeysFolder
(
id
);
err
!=
nil
{
return
nil
,
err
}
}
list
:=
store
.
publicKeys
[
id
]
if
len
(
list
)
>
counter
{
return
list
[
counter
],
nil
}
return
nil
,
nil
return
store
.
publicKeys
[
id
][
counter
],
nil
}
func
(
store
*
ConfigurationStore
)
addReverseHash
(
credid
CredentialTypeIdentifier
)
{
...
...
@@ -131,27 +125,33 @@ func (store *ConfigurationStore) parseIssuerFolders(path string) error {
})
}
// parse $schememanager/$issuer/PublicKeys/$i.xml for $i = 1, ...
func
(
store
*
ConfigurationStore
)
parseKeysFolder
(
issuerid
IssuerIdentifier
)
error
{
issuer
:=
store
.
Issuers
[
issuerid
]
path
:=
store
.
path
+
"/"
+
issuer
.
Identifier
()
.
SchemeManagerIdentifier
()
.
String
()
+
"/"
+
issuer
.
ID
+
"/PublicKeys/"
for
i
:=
0
;
;
i
++
{
file
:=
path
+
strconv
.
Itoa
(
i
)
+
".xml"
if
_
,
err
:=
os
.
Stat
(
file
);
err
!=
nil
{
break
path
:=
fmt
.
Sprintf
(
"%s/%s/%s/PublicKeys/*.xml"
,
store
.
path
,
issuerid
.
SchemeManagerIdentifier
()
.
Name
(),
issuerid
.
Name
())
files
,
err
:=
filepath
.
Glob
(
path
)
if
err
!=
nil
{
return
err
}
for
_
,
file
:=
range
files
{
filename
:=
filepath
.
Base
(
file
)
count
:=
filename
[
:
len
(
filename
)
-
4
]
i
,
err
:=
strconv
.
Atoi
(
count
)
if
err
!=
nil
{
continue
}
pk
,
err
:=
gabi
.
NewPublicKeyFromFile
(
file
)
if
err
!=
nil
{
return
err
}
pk
.
Issuer
=
issuer
.
Identifier
()
.
String
()
store
.
publicKeys
[
issuer
.
Identifier
()]
=
append
(
store
.
publicKeys
[
issuer
.
Identifier
()],
pk
)
pk
.
Issuer
=
issuer
id
.
String
()
store
.
publicKeys
[
issuer
id
][
i
]
=
pk
}
return
nil
}
// parse $schememanager/$issuer/Issues/*/description.xml
func
(
store
*
ConfigurationStore
)
parseCredentialsFolder
(
path
string
)
error
{
return
iterateSubfolders
(
path
,
func
(
dir
string
)
error
{
cred
:=
&
CredentialType
{}
...
...
@@ -266,3 +266,114 @@ func (store *ConfigurationStore) Copy(source string, parse bool) error {
}
return
nil
}
func
(
store
*
ConfigurationStore
)
DownloadSchemeManager
(
url
string
)
(
*
SchemeManager
,
error
)
{
if
!
strings
.
HasPrefix
(
url
,
"http://"
)
&&
!
strings
.
HasPrefix
(
url
,
"https://"
)
{
url
=
"https://"
+
url
}
if
url
[
len
(
url
)
-
1
]
==
'/'
{
url
=
url
[
:
len
(
url
)
-
1
]
}
if
strings
.
HasSuffix
(
url
,
"/description.xml"
)
{
url
=
url
[
:
len
(
url
)
-
len
(
"/description.xml"
)]
}
b
,
err
:=
NewHTTPTransport
(
url
)
.
GetBytes
(
"/description.xml"
)
if
err
!=
nil
{
return
nil
,
err
}
manager
:=
&
SchemeManager
{}
if
err
=
xml
.
Unmarshal
(
b
,
manager
);
err
!=
nil
{
return
nil
,
err
}
manager
.
URL
=
url
// TODO?
return
manager
,
nil
}
func
(
store
*
ConfigurationStore
)
RemoveSchemeManager
(
id
SchemeManagerIdentifier
)
error
{
// Remove everything falling under the manager's responsibility
for
credid
:=
range
store
.
CredentialTypes
{
if
credid
.
IssuerIdentifier
()
.
SchemeManagerIdentifier
()
==
id
{
delete
(
store
.
CredentialTypes
,
credid
)
}
}
for
issid
:=
range
store
.
Issuers
{
if
issid
.
SchemeManagerIdentifier
()
==
id
{
delete
(
store
.
Issuers
,
issid
)
}
}
for
issid
:=
range
store
.
publicKeys
{
if
issid
.
SchemeManagerIdentifier
()
==
id
{
delete
(
store
.
publicKeys
,
issid
)
}
}
// Remove from storage
return
os
.
RemoveAll
(
fmt
.
Sprintf
(
"%s/%s"
,
store
.
path
,
id
.
String
()))
// or, remove above iterations and call .ParseFolder()?
}
func
(
store
*
ConfigurationStore
)
AddSchemeManager
(
manager
*
SchemeManager
)
error
{
name
:=
manager
.
ID
if
err
:=
ensureDirectoryExists
(
fmt
.
Sprintf
(
"%s/%s"
,
store
.
path
,
name
));
err
!=
nil
{
return
err
}
b
,
err
:=
xml
.
Marshal
(
manager
)
if
err
!=
nil
{
return
err
}
if
err
:=
saveFile
(
fmt
.
Sprintf
(
"%s/%s/description.xml"
,
store
.
path
,
name
),
b
);
err
!=
nil
{
return
err
}
store
.
SchemeManagers
[
NewSchemeManagerIdentifier
(
name
)]
=
manager
return
nil
}
func
(
store
*
ConfigurationStore
)
Download
(
set
*
IrmaIdentifierSet
)
error
{
var
contains
bool
for
manid
:=
range
set
.
SchemeManagers
{
if
_
,
contains
=
store
.
SchemeManagers
[
manid
];
!
contains
{
return
errors
.
Errorf
(
"Unknown scheme manager: %s"
,
manid
)
}
}
transport
:=
NewHTTPTransport
(
""
)
for
issid
:=
range
set
.
Issuers
{
if
_
,
contains
=
store
.
Issuers
[
issid
];
!
contains
{
url
:=
store
.
SchemeManagers
[
issid
.
SchemeManagerIdentifier
()]
.
URL
+
"/"
+
issid
.
Name
()
path
:=
fmt
.
Sprintf
(
"%s/%s/%s"
,
store
.
path
,
issid
.
SchemeManagerIdentifier
()
.
String
(),
issid
.
Name
())
transport
.
GetFile
(
url
+
"/description.xml"
,
path
+
"/description.xml"
)
transport
.
GetFile
(
url
+
"/logo.png"
,
path
+
"/logo.png"
)
}
for
issid
,
list
:=
range
set
.
PublicKeys
{
for
_
,
count
:=
range
list
{
pk
,
err
:=
store
.
PublicKey
(
issid
,
count
)
if
err
!=
nil
{
return
err
}
if
pk
==
nil
{
manager
:=
issid
.
SchemeManagerIdentifier
()
suffix
:=
fmt
.
Sprintf
(
"/%s/PublicKeys/%d.xml"
,
issid
.
Name
(),
count
)
path
:=
fmt
.
Sprintf
(
"%s/%s/%s"
,
store
.
path
,
manager
.
String
(),
suffix
)
transport
.
GetFile
(
store
.
SchemeManagers
[
manager
]
.
URL
+
suffix
,
path
)
}
}
}
}
for
credid
:=
range
set
.
CredentialTypes
{
if
_
,
contains
:=
store
.
CredentialTypes
[
credid
];
!
contains
{
issuer
:=
credid
.
IssuerIdentifier
()
manager
:=
issuer
.
SchemeManagerIdentifier
()
local
:=
fmt
.
Sprintf
(
"%s/%s/%s/Issues"
,
store
.
path
,
manager
.
Name
(),
issuer
.
Name
())
if
err
:=
ensureDirectoryExists
(
local
);
err
!=
nil
{
return
err
}
transport
.
GetFile
(
fmt
.
Sprintf
(
"%s/%s/Issues/%s/description.xml"
,
store
.
SchemeManagers
[
manager
]
.
URL
,
issuer
.
Name
(),
credid
.
Name
()),
fmt
.
Sprintf
(
"%s/%s/description.xml"
,
local
,
credid
.
Name
()),
)
}
}
return
store
.
ParseFolder
()
}
descriptions.go
View file @
33848ed3
...
...
@@ -6,11 +6,15 @@ import (
"github.com/go-errors/errors"
)
// This file contains data types for scheme managers, issuers, credential types
// matching the XML files in irma_configuration.
// SchemeManager describes a scheme manager.
type
SchemeManager
struct
{
ID
string
`xml:"Id"`
Name
TranslatedString
`xml:"Name"`
URL
string
`xml:"Contact"`
URL
string
`xml:"Url"`
Contact
string
`xml:"contact"`
Description
TranslatedString
KeyshareServer
string
KeyshareWebsite
string
...
...
@@ -83,6 +87,26 @@ func (ct CredentialType) IndexOf(ai AttributeTypeIdentifier) (int, error) {
// TranslatedString is a map of translated strings.
type
TranslatedString
map
[
string
]
string
type
xmlTranslation
struct
{
XMLName
xml
.
Name
Text
string
`xml:",chardata"`
}
type
xmlTranslatedString
struct
{
Translations
[]
xmlTranslation
`xml:",any"`
}
// MarshalXML implements xml.Marshaler.
func
(
ts
*
TranslatedString
)
MarshalXML
(
e
*
xml
.
Encoder
,
start
xml
.
StartElement
)
error
{
temp
:=
&
xmlTranslatedString
{}
for
lang
,
text
:=
range
*
ts
{
temp
.
Translations
=
append
(
temp
.
Translations
,
xmlTranslation
{
XMLName
:
xml
.
Name
{
Local
:
lang
},
Text
:
text
},
)
}
return
e
.
EncodeElement
(
temp
,
start
)
}
// UnmarshalXML unmarshals an XML tag containing a string translated to multiple languages,
// for example: <Foo><en>Hello world</en><nl>Hallo wereld</nl></Foo>
// into a TranslatedString: { "en": "Hello world" , "nl": "Hallo wereld" }
...
...
@@ -90,12 +114,7 @@ func (ts *TranslatedString) UnmarshalXML(d *xml.Decoder, start xml.StartElement)
if
map
[
string
]
string
(
*
ts
)
==
nil
{
*
ts
=
TranslatedString
(
make
(
map
[
string
]
string
))
}
temp
:=
&
struct
{
Translations
[]
struct
{
XMLName
xml
.
Name
Text
string
`xml:",chardata"`
}
`xml:",any"`
}{}
temp
:=
&
xmlTranslatedString
{}
if
err
:=
d
.
DecodeElement
(
temp
,
&
start
);
err
!=
nil
{
return
err
}
...
...
identifiers.go
View file @
33848ed3
...
...
@@ -38,6 +38,15 @@ type AttributeIdentifier struct {
Count
int
}
// IrmaIdentifierSet contains a set (ensured by using map[...]struct{}) of all scheme managers,
// all issuers, all credential types and all public keys that are involved in an IRMA session.
type
IrmaIdentifierSet
struct
{
SchemeManagers
map
[
SchemeManagerIdentifier
]
struct
{}
Issuers
map
[
IssuerIdentifier
]
struct
{}
CredentialTypes
map
[
CredentialTypeIdentifier
]
struct
{}
PublicKeys
map
[
IssuerIdentifier
][]
int
}
// Parent returns the parent object of this identifier.
func
(
oi
metaObjectIdentifier
)
Parent
()
string
{
str
:=
string
(
oi
)
...
...
@@ -145,3 +154,12 @@ func (id *AttributeTypeIdentifier) UnmarshalText(text []byte) error {
*
id
=
NewAttributeTypeIdentifier
(
string
(
text
))
return
nil
}
func
(
set
*
IrmaIdentifierSet
)
Distributed
(
store
*
ConfigurationStore
)
bool
{
for
id
:=
range
set
.
SchemeManagers
{
if
store
.
SchemeManagers
[
id
]
.
Distributed
()
{
return
true
}
}
return
false
}
irmago_test.go
View file @
33848ed3
...
...
@@ -29,8 +29,10 @@ func TestMain(m *testing.M) {
type
IgnoringKeyshareHandler
struct
{}
func
(
i
*
IgnoringKeyshareHandler
)
StartRegistration
(
m
*
SchemeManager
,
callback
func
(
e
,
p
string
)
error
)
{
func
(
i
*
IgnoringKeyshareHandler
)
StartRegistration
(
m
*
SchemeManager
,
callback
func
(
e
,
p
string
))
{
}
func
(
i
*
IgnoringKeyshareHandler
)
RegistrationError
(
err
error
)
{}
func
(
i
*
IgnoringKeyshareHandler
)
RegistrationSuccess
()
{}
func
parseStorage
(
t
*
testing
.
T
)
*
CredentialManager
{
exists
,
err
:=
PathExists
(
"testdata/storage/test"
)
...
...
@@ -437,3 +439,19 @@ func TestCredentialRemoval(t *testing.T) {
teardown
(
t
)
}
func
TestDownloadSchemeManager
(
t
*
testing
.
T
)
{
manager
:=
parseStorage
(
t
)
require
.
NoError
(
t
,
manager
.
ConfigurationStore
.
RemoveSchemeManager
(
NewSchemeManagerIdentifier
(
"irma-demo"
)))
url
:=
"https://raw.githubusercontent.com/credentials/irma_configuration/translate/irma-demo"
sm
,
err
:=
manager
.
ConfigurationStore
.
DownloadSchemeManager
(
url
)
require
.
NoError
(
t
,
err
)
require
.
NotNil
(
t
,
sm
)
require
.
NoError
(
t
,
manager
.
ConfigurationStore
.
AddSchemeManager
(
sm
))
jwt
:=
getIssuanceJwt
(
"testip"
,
NewAttributeTypeIdentifier
(
"irma-demo.RU.studentCard.studentID"
))
sessionHelper
(
t
,
jwt
,
"issue"
,
manager
)
teardown
(
t
)
}
keyshare.go
View file @
33848ed3
...
...
@@ -36,7 +36,6 @@ type keyshareSession struct {
keyshareServers
map
[
SchemeManagerIdentifier
]
*
keyshareServer
keyshareServer
*
keyshareServer
// The one keyshare server in use in case of issuance
transports
map
[
SchemeManagerIdentifier
]
*
HTTPTransport
schemeManagers
[]
SchemeManagerIdentifier
}
type
keyshareServer
struct
{
...
...
@@ -99,7 +98,9 @@ type proofPCommitmentMap struct {
// KeyshareHandler is used for asking the user for his email address and PIN,
// for registering at a keyshare server.
type
KeyshareHandler
interface
{
StartRegistration
(
manager
*
SchemeManager
,
registrationCallback
func
(
email
,
pin
string
)
error
)
StartRegistration
(
manager
*
SchemeManager
,
registrationCallback
func
(
email
,
pin
string
))
RegistrationError
(
err
error
)
RegistrationSuccess
()
}
const
(
...
...
@@ -144,9 +145,8 @@ func startKeyshareSession(
store
*
ConfigurationStore
,
keyshareServers
map
[
SchemeManagerIdentifier
]
*
keyshareServer
,
)
{
schemeManagers
:=
session
.
SchemeManagers
()
ksscount
:=
0
for
_
,
managerID
:=
range
schemeManagers
{
for
managerID
:=
range
s
ession
.
Identifiers
()
.
S
chemeManagers
{
if
store
.
SchemeManagers
[
managerID
]
.
Distributed
()
{
ksscount
++
if
_
,
registered
:=
keyshareServers
[
managerID
];
!
registered
{
...
...
@@ -170,12 +170,11 @@ func startKeyshareSession(
pinRequestor
:
pin
,
store
:
store
,
keyshareServers
:
keyshareServers
,
schemeManagers
:
schemeManagers
,
}
requestPin
:=
false
for
_
,
managerID
:=
range
schemeManagers
{
for
managerID
:=
range
s
ession
.
Identifiers
()
.
S
chemeManagers
{
if
!
ks
.
store
.
SchemeManagers
[
managerID
]
.
Distributed
()
{
continue
}
...
...
@@ -243,7 +242,7 @@ func (ks *keyshareSession) VerifyPin(attempts int) {
// - If this or anything else (specified in err) goes wrong, success will be false.
// If all is ok, success will be true.
func
(
ks
*
keyshareSession
)
verifyPinAttempt
(
pin
string
)
(
success
bool
,
tries
int
,
blocked
int
,
err
error
)
{
for
_
,
managerID
:=
range
ks
.
schemeManagers
{
for
managerID
:=
range
ks
.
s
ession
.
Identifiers
()
.
S
chemeManagers
{
if
!
ks
.
store
.
SchemeManagers
[
managerID
]
.
Distributed
()
{
continue
}
...
...
@@ -306,7 +305,7 @@ func (ks *keyshareSession) GetCommitments() {
// Now inform each keyshare server of with respect to which public keys
// we want them to send us commitments
for
_
,
managerID
:=
range
ks
.
schemeManagers
{
for
managerID
:=
range
ks
.
s
ession
.
Identifiers
()
.
S
chemeManagers
{
if
!
ks
.
store
.
SchemeManagers
[
managerID
]
.
Distributed
()
{
continue
}
...
...
@@ -357,7 +356,7 @@ func (ks *keyshareSession) GetProofPs() {
// Post the challenge, obtaining JWT's containing the ProofP's
responses
:=
map
[
SchemeManagerIdentifier
]
string
{}
for
_
,
managerID
:=
range
ks
.
schemeManagers
{
for
managerID
:=
range
ks
.
s
ession
.
Identifiers
()
.
S
chemeManagers
{
transport
,
distributed
:=
ks
.
transports
[
managerID
]
if
!
distributed
{
continue
...
...
manager.go
View file @
33848ed3
...
...
@@ -49,25 +49,13 @@ type CredentialManager struct {
ConfigurationStore
*
ConfigurationStore
irmaConfigurationPath
string
androidStoragePath
string
keyshareHandler
KeyshareHandler
}
type
secretKey
struct
{
Key
*
big
.
Int
}
// IrmaSession is an IRMA session.
type
IrmaSession
interface
{
GetNonce
()
*
big
.
Int
SetNonce
(
*
big
.
Int
)
GetContext
()
*
big
.
Int
SetContext
(
*
big
.
Int
)
ToDisclose
()
AttributeDisjunctionList
DisclosureChoice
()
*
DisclosureChoice
SetDisclosureChoice
(
choice
*
DisclosureChoice
)
Distributed
(
store
*
ConfigurationStore
)
bool
SchemeManagers
()
[]
SchemeManagerIdentifier
}
// NewCredentialManager creates a new CredentialManager that uses the directory
// specified by storagePath for (de)serializing itself. irmaConfigurationPath
// is the path to a (possibly readonly) folder containing irma_configuration;
...
...
@@ -94,25 +82,25 @@ func NewCredentialManager(
return
nil
,
err
}
var
store
*
ConfigurationStore
if
store
,
err
=
NewConfigurationStore
(
storagePath
+
"/irma_configuration"
,
irmaConfigurationPath
);
err
!=
nil
{
return
nil
,
err
}
if
err
=
store
.
ParseFolder
();
err
!=
nil
{
return
nil
,
err
}
cm
:=
&
CredentialManager
{
credentials
:
make
(
map
[
CredentialTypeIdentifier
]
map
[
int
]
*
credential
),
keyshareServers
:
make
(
map
[
SchemeManagerIdentifier
]
*
keyshareServer
),
attributes
:
make
(
map
[
CredentialTypeIdentifier
][]
*
AttributeList
),
irmaConfigurationPath
:
irmaConfigurationPath
,
androidStoragePath
:
androidStoragePath
,
ConfigurationStore
:
store
,
storage
:
storage
{
storagePath
:
storagePath
,
ConfigurationStore
:
store
},
keyshareHandler
:
keyshareHandler
,
}
cm
.
ConfigurationStore
,
err
=
NewConfigurationStore
(
storagePath
+
"/irma_configuration"
,
irmaConfigurationPath
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
=
cm
.
ConfigurationStore
.
ParseFolder
();
err
!=
nil
{
return
nil
,
err
}
// Ensure storage path exists, and populate it with necessary files
cm
.
storage
=
storage
{
storagePath
:
storagePath
,
ConfigurationStore
:
cm
.
ConfigurationStore
}
if
err
=
cm
.
storage
.
EnsureStorageExists
();
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -143,9 +131,7 @@ func NewCredentialManager(
if
keyshareHandler
==
nil
{
return
nil
,
errors
.
New
(
"Keyshare server found but no KeyshareHandler was given"
)
}
keyshareHandler
.
StartRegistration
(
unenrolled
[
0
],
func
(
email
,
pin
string
)
error
{
return
cm
.
KeyshareEnroll
(
unenrolled
[
0
]
.
Identifier
(),
email
,
pin
)
})
cm
.
KeyshareEnroll
(
unenrolled
[
0
],
keyshareHandler
)
default
:
return
nil
,
errors
.
New
(
"Too many keyshare servers"
)
}
...
...
@@ -582,7 +568,20 @@ func (cm *CredentialManager) unenrolledKeyshareServers() []*SchemeManager {
}
// KeyshareEnroll attempts to register at the keyshare server of the specified scheme manager.
func
(
cm
*
CredentialManager
)
KeyshareEnroll
(
managerID
SchemeManagerIdentifier
,
email
,
pin
string
)
error
{
func
(
cm
*
CredentialManager
)
KeyshareEnroll
(
manager
*
SchemeManager
,
handler
KeyshareHandler
)
{
handler
.
StartRegistration
(
manager
,
func
(
email
,
pin
string
)
{
go
func
()
{
err
:=
cm
.
keyshareEnrollWorker
(
manager
.
Identifier
(),
email
,
pin
)
if
err
!=
nil
{
handler
.
RegistrationError
(
err
)
}
else
{
handler
.
RegistrationSuccess
()
}
}()
})
}
func
(
cm
*
CredentialManager
)
keyshareEnrollWorker
(
managerID
SchemeManagerIdentifier
,
email
,
pin
string
)
error
{
manager
,
ok
:=
cm
.
ConfigurationStore
.
SchemeManagers
[
managerID
]
if
!
ok
{
return
errors
.
New
(
"Unknown scheme manager"
)
...
...
messages.go
View file @
33848ed3
...
...
@@ -68,10 +68,11 @@ const (
// Actions
const
(
ActionDisclosing
=
Action
(
"disclosing"
)
ActionSigning
=
Action
(
"signing"
)
ActionIssuing
=
Action
(
"issuing"
)
ActionUnknown
=
Action
(
"unknown"
)
ActionSchemeManager
=
Action
(
"schememanager"
)
ActionDisclosing
=
Action
(
"disclosing"
)
ActionSigning
=
Action
(
"signing"
)
ActionIssuing
=
Action
(
"issuing"
)
ActionUnknown
=
Action
(
"unknown"
)
)
// Protocol errors
...
...
@@ -98,6 +99,8 @@ const (
ErrorApi
=
ErrorType
(
"api"
)
// Server returned unexpected or malformed response
ErrorServerResponse
=
ErrorType
(
"serverResponse"
)
// Error during downloading of credential type, issuer, or public keys
ErrorConfigurationStoreDownload
=
ErrorType
(
"configurationStoreDownload"
)
)
func
(
e
*
SessionError
)
Error
()
string
{
...
...
requests.go
View file @
33848ed3
...
...
@@ -15,9 +15,10 @@ import (
// SessionRequest contains the context and nonce for an IRMA session.
type
SessionRequest
struct
{
Context
*
big
.
Int
`json:"context"`
Nonce
*
big
.
Int
`json:"nonce"`
choice
*
DisclosureChoice
Context
*
big
.
Int
`json:"context"`
Nonce
*
big
.
Int
`json:"nonce"`
choice
*
DisclosureChoice
identifiers
*
IrmaIdentifierSet
}
// DisclosureChoice returns the attributes to be disclosed in this session.
...
...
@@ -102,6 +103,18 @@ type IdentityProviderJwt struct {
Request
IdentityProviderRequest
`json:"iprequest"`
}
// IrmaSession is an IRMA session.
type
IrmaSession
interface
{
GetNonce
()
*
big
.
Int
SetNonce
(
*
big
.
Int
)
GetContext
()
*
big
.
Int
SetContext
(
*
big
.
Int
)
ToDisclose
()
AttributeDisjunctionList
DisclosureChoice
()
*
DisclosureChoice
SetDisclosureChoice
(
choice
*
DisclosureChoice
)
Identifiers
()
*
IrmaIdentifierSet
}
// Timestamp is a time.Time that marshals to Unix timestamps.
type
Timestamp
time
.
Time
...
...
@@ -153,28 +166,35 @@ func newIssuanceState() (*issuanceState, error) {
},
nil
}
// Distributed indicates if a keyshare is involved in this session.
func
(
ir
*
IssuanceRequest
)
Distributed
(
store
*
ConfigurationStore
)
bool
{
for
_
,
manager
:=
range
ir
.
SchemeManagers
()
{
if
store
.
SchemeManagers
[
manager
]
.
Distributed
()
{
return
true
func
(
dr
*
IssuanceRequest
)
Identifiers
()
*
IrmaIdentifierSet
{
if
dr
.
identifiers
==
nil
{
dr
.
identifiers
=
&
IrmaIdentifierSet
{
SchemeManagers
:
map
[
SchemeManagerIdentifier
]
struct
{}{},
Issuers
:
map
[
IssuerIdentifier
]
struct
{}{},
CredentialTypes
:
map
[
CredentialTypeIdentifier
]
struct
{}{},
PublicKeys
:
map
[
IssuerIdentifier
][]
int
{},
}
}
return
false
}
// SchemeManagers returns a list of all scheme managers involved in this session.
func
(
ir
*
IssuanceRequest
)
SchemeManagers
()
[]
SchemeManagerIdentifier
{
list
:=
[]
SchemeManagerIdentifier
{}
for
_
,
cred
:=
range
ir
.
Credentials
{
list
=
append
(
list
,
cred
.
Credential
.
IssuerIdentifier
()
.
SchemeManagerIdentifier
())
}
for
_
,
disjunctions
:=
range
ir
.
Disclose
{
for
_
,
attr
:=
range
disjunctions
.
Attributes
{
list
=
append
(
list
,
attr
.
CredentialTypeIdentifier
()
.
IssuerIdentifier
()
.
SchemeManagerIdentifier
())
for
_
,
credreq
:=
range
dr
.
Credentials
{
issuer
:=
credreq
.
Credential
.
IssuerIdentifier
()
dr
.
identifiers
.
SchemeManagers
[
issuer
.
SchemeManagerIdentifier
()]
=
struct
{}{}
dr
.
identifiers
.
Issuers
[
issuer
]
=
struct
{}{}
dr
.
identifiers
.
CredentialTypes
[
*
credreq
.
Credential
]
=
struct
{}{}
if
dr
.
identifiers
.
PublicKeys
[
issuer
]
==
nil
{
dr
.
identifiers
.
PublicKeys
[
issuer
]
=
[]
int
{}
}
dr
.
identifiers
.
PublicKeys
[
issuer
]
=
append
(
dr
.
identifiers
.
PublicKeys
[
issuer
],
credreq
.
KeyCounter
)
}
for
_
,
disjunction
:=
range
dr
.
Disclose
{