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
4140d9cb
Commit
4140d9cb
authored
Oct 05, 2017
by
Sietse Ringers
Browse files
More irma_configuration and manager downloading
parent
2c10dc67
Changes
8
Hide whitespace changes
Inline
Side-by-side
configstore.go
View file @
4140d9cb
...
...
@@ -18,13 +18,14 @@ import (
"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
Credentials
map
[
CredentialTypeIdentifier
]
*
CredentialType
publicKeys
map
[
IssuerIdentifier
]
[
]
*
gabi
.
PublicKey
publicKeys
map
[
IssuerIdentifier
]
map
[
int
]
*
gabi
.
PublicKey
reverseHashes
map
[
string
]
CredentialTypeIdentifier
path
string
initialized
bool
...
...
@@ -37,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
...
...
@@ -62,7 +57,7 @@ func (store *ConfigurationStore) ParseFolder() error {
store
.
SchemeManagers
=
make
(
map
[
SchemeManagerIdentifier
]
*
SchemeManager
)
store
.
Issuers
=
make
(
map
[
IssuerIdentifier
]
*
Issuer
)
store
.
Credentials
=
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
{
...
...
@@ -87,19 +82,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
)
{
...
...
@@ -136,27 +124,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
{}
...
...
@@ -351,19 +345,32 @@ func (store *ConfigurationStore) Download(set *IrmaIdentifierSet) error {
}
for
issid
,
list
:=
range
set
.
PublicKeys
{
for
_
,
count
:=
range
list
{
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
)
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
.
Credentials
[
credid
];
!
contains
{
manager
:=
credid
.
IssuerIdentifier
()
.
SchemeManagerIdentifier
()
suffix
:=
fmt
.
Sprintf
(
"/%s/Issues/%s/description.xml"
,
credid
.
IssuerIdentifier
()
.
Name
(),
credid
.
Name
())
path
:=
fmt
.
Sprintf
(
"%s/%s/%s"
,
store
.
path
,
manager
.
String
(),
suffix
)
transport
.
GetFile
(
store
.
SchemeManagers
[
manager
]
.
URL
+
suffix
,
path
)
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
()),
)
}
}
...
...
descriptions.go
View file @
4140d9cb
...
...
@@ -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
}
...
...
irmago_test.go
View file @
4140d9cb
...
...
@@ -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"
)
...
...
@@ -445,4 +447,11 @@ func TestDownloadSchemeManager(t *testing.T) {
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 @
4140d9cb
...
...
@@ -98,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
(
...
...
manager.go
View file @
4140d9cb
...
...
@@ -131,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"
)
}
...
...
@@ -570,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 @
4140d9cb
...
...
@@ -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
...
...
session.go
View file @
4140d9cb
...
...
@@ -28,6 +28,7 @@ type Handler interface {
AskIssuancePermission
(
request
IssuanceRequest
,
ServerName
string
,
callback
PermissionHandler
)
AskVerificationPermission
(
request
DisclosureRequest
,
ServerName
string
,
callback
PermissionHandler
)
AskSignaturePermission
(
request
SignatureRequest
,
ServerName
string
,
callback
PermissionHandler
)
AskSchemeManagerPermission
(
manager
*
SchemeManager
,
callback
func
(
proceed
bool
))
AskPin
(
remainingAttempts
int
,
callback
func
(
proceed
bool
,
pin
string
))
}
...
...
@@ -45,6 +46,7 @@ type session struct {
irmaSession
IrmaSession
transport
*
HTTPTransport
choice
*
DisclosureChoice
newmanager
*
SchemeManager
}
// We implement the handler for the keyshare protocol
...
...
@@ -111,6 +113,7 @@ func (cm *CredentialManager) NewSession(qr *Qr, handler Handler) {
case
ActionDisclosing
:
// nop
case
ActionSigning
:
// nop
case
ActionIssuing
:
// nop
case
ActionSchemeManager
:
// nop
case
ActionUnknown
:
fallthrough
default
:
...
...
@@ -138,6 +141,11 @@ func (session *session) fail(err *SessionError) {
func
(
session
*
session
)
start
()
{
session
.
Handler
.
StatusUpdate
(
session
.
Action
,
StatusCommunicating
)
if
session
.
Action
==
ActionSchemeManager
{
session
.
managerSession
()
return
}
// Get the first IRMA protocol message and parse it
session
.
info
=
&
SessionInfo
{}
Err
:=
session
.
transport
.
Get
(
"jwt"
,
session
.
info
)
...
...
@@ -300,3 +308,42 @@ func (session *session) sendResponse(message interface{}) {
_
=
session
.
credManager
.
addLogEntry
(
log
)
// TODO err
session
.
Handler
.
Success
(
session
.
Action
)
}
func
(
session
*
session
)
managerSession
()
{
manager
,
err
:=
session
.
credManager
.
ConfigurationStore
.
DownloadSchemeManager
(
session
.
ServerURL
)
if
err
!=
nil
{
session
.
Handler
.
Failure
(
session
.
Action
,
&
SessionError
{
Err
:
err
})
// TODO
return
}
session
.
Handler
.
AskSchemeManagerPermission
(
manager
,
func
(
proceed
bool
)
{
if
!
proceed
{
session
.
Handler
.
Cancelled
(
session
.
Action
)
return
}
session
.
newmanager
=
manager
if
manager
.
Distributed
()
{
session
.
credManager
.
KeyshareEnroll
(
manager
,
KeyshareHandler
(
session
))
}
else
{
session
.
RegistrationSuccess
()
}
})
return
}
func
(
session
*
session
)
StartRegistration
(
manager
*
SchemeManager
,
callback
func
(
email
,
pin
string
))
{
session
.
credManager
.
keyshareHandler
.
StartRegistration
(
manager
,
callback
)
}
func
(
session
*
session
)
RegistrationError
(
err
error
)
{
session
.
Handler
.
Failure
(
session
.
Action
,
&
SessionError
{
Err
:
err
})
// TODO
session
.
credManager
.
keyshareHandler
.
RegistrationError
(
err
)
}
func
(
session
*
session
)
RegistrationSuccess
()
{
if
err
:=
session
.
credManager
.
ConfigurationStore
.
AddSchemeManager
(
session
.
newmanager
);
err
!=
nil
{
session
.
Handler
.
Failure
(
session
.
Action
,
&
SessionError
{})
return
}
session
.
Handler
.
Success
(
session
.
Action
)
session
.
credManager
.
keyshareHandler
.
RegistrationSuccess
()
}
session_test.go
View file @
4140d9cb
...
...
@@ -61,6 +61,9 @@ func (th TestHandler) AskIssuancePermission(request IssuanceRequest, ServerName
func
(
th
TestHandler
)
AskSignaturePermission
(
request
SignatureRequest
,
ServerName
string
,
callback
PermissionHandler
)
{
th
.
AskVerificationPermission
(
request
.
DisclosureRequest
,
ServerName
,
callback
)
}
func
(
th
TestHandler
)
AskSchemeManagerPermission
(
manager
*
SchemeManager
,
callback
func
(
proceed
bool
))
{
callback
(
true
)
}
func
(
th
TestHandler
)
AskPin
(
remainingAttempts
int
,
callback
func
(
proceed
bool
,
pin
string
))
{
callback
(
true
,
"12345"
)
}
...
...
@@ -190,7 +193,7 @@ func registerKeyshareServer(t *testing.T, manager *CredentialManager) {
bytes
:=
make
([]
byte
,
8
,
8
)
rand
.
Read
(
bytes
)
email
:=
fmt
.
Sprintf
(
"%s@example.com"
,
hex
.
EncodeToString
(
bytes
))
require
.
NoError
(
t
,
manager
.
K
eyshareEnroll
(
NewSchemeManagerIdentifier
(
"test"
),
email
,
"12345"
))
require
.
NoError
(
t
,
manager
.
k
eyshareEnroll
Worker
(
NewSchemeManagerIdentifier
(
"test"
),
email
,
"12345"
))
}
// Register a new account at the keyshare server and do an issuance, disclosure,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment