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
3a6e8e88
Commit
3a6e8e88
authored
Jul 26, 2017
by
Sietse Ringers
Browse files
Use types for manager, issuer, credential and attribute identifiers
parent
0c761ca8
Changes
6
Hide whitespace changes
Inline
Side-by-side
descriptions.go
View file @
3a6e8e88
...
...
@@ -45,6 +45,20 @@ type CredentialType struct {
XMLName
xml
.
Name
`xml:"IssueSpecification"`
}
// ContainsAttribute tests whether the specified attribute is contained in this
// credentialtype.
func
(
ct
*
CredentialType
)
ContainsAttribute
(
ai
AttributeIdentifier
)
bool
{
if
ai
.
CredentialIdentifier
()
.
String
()
!=
ct
.
Identifier
()
.
String
()
{
return
false
}
for
_
,
desc
:=
range
ct
.
Attributes
{
if
desc
.
ID
==
ai
.
Name
()
{
return
true
}
}
return
false
}
// AttributeDescription is a description of an attribute within a credential type.
type
AttributeDescription
struct
{
ID
string
`xml:"id,attr"`
...
...
@@ -92,18 +106,23 @@ func (ts *TranslatedString) Translation(lang string) string {
}
// Identifier returns the identifier of the specified credential type.
func
(
c
d
*
CredentialType
)
Identifier
()
string
{
return
cd
.
SchemeManagerID
+
"."
+
c
d
.
IssuerID
+
"."
+
c
d
.
ID
func
(
c
t
*
CredentialType
)
Identifier
()
CredentialIdentifier
{
return
NewCredentialIdentifier
(
ct
.
SchemeManagerID
+
"."
+
c
t
.
IssuerID
+
"."
+
c
t
.
ID
)
}
// IssuerIdentifier returns the issuer identifier of the specified credential type.
func
(
c
d
*
CredentialType
)
IssuerIdentifier
()
string
{
return
cd
.
SchemeManagerID
+
"."
+
c
d
.
IssuerID
func
(
c
t
*
CredentialType
)
IssuerIdentifier
()
IssuerIdentifier
{
return
NewIssuerIdentifier
(
ct
.
SchemeManagerID
+
"."
+
c
t
.
IssuerID
)
}
// Identifier returns the identifier of the specified issuer description.
func
(
id
*
Issuer
)
Identifier
()
string
{
return
id
.
SchemeManagerID
+
"."
+
id
.
ID
func
(
id
*
Issuer
)
Identifier
()
IssuerIdentifier
{
return
NewIssuerIdentifier
(
id
.
SchemeManagerID
+
"."
+
id
.
ID
)
}
// Identifier returns the identifier of the specified scheme manager.
func
(
sm
*
SchemeManager
)
Identifier
()
SchemeManagerIdentifier
{
return
NewSchemeManagerIdentifier
(
sm
.
ID
)
}
// CurrentPublicKey returns the latest known public key of the issuer identified by this instance.
...
...
identifiers.go
0 → 100644
View file @
3a6e8e88
package
irmago
import
"strings"
type
objectIdentifier
string
// SchemeManagerIdentifier identifies a scheme manager. Equal to its ID. For example "irma-demo".
type
SchemeManagerIdentifier
struct
{
objectIdentifier
}
// IssuerIdentifier identifies an inssuer. For example "irma-demo.RU".
type
IssuerIdentifier
struct
{
objectIdentifier
}
// CredentialIdentifier identifies a credentialtype. For example "irma-demo.RU.studentCard".
type
CredentialIdentifier
struct
{
objectIdentifier
}
// AttributeIdentifier identifies an attribute. For example "irma-demo.RU.studentCard.studentID".
type
AttributeIdentifier
struct
{
objectIdentifier
}
func
(
oi
objectIdentifier
)
Parent
()
string
{
str
:=
string
(
oi
)
return
str
[
:
strings
.
LastIndex
(
str
,
"/"
)]
}
func
(
oi
objectIdentifier
)
Name
()
string
{
str
:=
string
(
oi
)
return
str
[
strings
.
LastIndex
(
str
,
"/"
)
+
1
:
]
}
func
(
oi
objectIdentifier
)
String
()
string
{
return
string
(
oi
)
}
// NewSchemeManagerIdentifier converts the specified identifier to a SchemeManagerIdentifier.
func
NewSchemeManagerIdentifier
(
id
string
)
SchemeManagerIdentifier
{
return
SchemeManagerIdentifier
{
objectIdentifier
(
id
)}
}
// NewIssuerIdentifier converts the specified identifier to a IssuerIdentifier.
func
NewIssuerIdentifier
(
id
string
)
IssuerIdentifier
{
return
IssuerIdentifier
{
objectIdentifier
(
id
)}
}
// NewCredentialIdentifier converts the specified identifier to a CredentialIdentifier.
func
NewCredentialIdentifier
(
id
string
)
CredentialIdentifier
{
return
CredentialIdentifier
{
objectIdentifier
(
id
)}
}
// NewAttributeIdentifier converts the specified identifier to a AttributeIdentifier.
func
NewAttributeIdentifier
(
id
string
)
AttributeIdentifier
{
return
AttributeIdentifier
{
objectIdentifier
(
id
)}
}
// SchemeManagerIdentifier returns the scheme manager identifer of the issuer.
func
(
id
IssuerIdentifier
)
SchemeManagerIdentifier
()
SchemeManagerIdentifier
{
return
NewSchemeManagerIdentifier
(
id
.
Parent
())
}
// IssuerIdentifier returns the IssuerIdentifier of the credential identifier.
func
(
id
CredentialIdentifier
)
IssuerIdentifier
()
IssuerIdentifier
{
return
NewIssuerIdentifier
(
id
.
Parent
())
}
// CredentialIdentifier returns the CredentialIdentifier of the attribute identifier.
func
(
id
AttributeIdentifier
)
CredentialIdentifier
()
CredentialIdentifier
{
return
NewCredentialIdentifier
(
id
.
Parent
())
}
irmago_test.go
View file @
3a6e8e88
...
...
@@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
...
...
@@ -39,7 +40,7 @@ func parseStorage(t *testing.T) {
func
teardown
(
t
*
testing
.
T
)
{
MetaStore
=
newConfigurationStore
()
Manager
=
newCredentialManager
()
require
.
NoError
(
t
,
os
.
RemoveAll
(
"testdata/storage/test"
))
assert
.
NoError
(
t
,
os
.
RemoveAll
(
"testdata/storage/test"
))
}
// A convenience function for initializing big integers from known correct (10
...
...
@@ -50,16 +51,16 @@ func s2big(s string) (r *big.Int) {
}
func
parseAndroidStorage
(
t
*
testing
.
T
)
{
require
.
NoError
(
t
,
Manager
.
ParseAndroidStorage
(),
"ParseAndroidStorage() failed"
)
assert
.
NoError
(
t
,
Manager
.
ParseAndroidStorage
(),
"ParseAndroidStorage() failed"
)
}
func
verifyStoreIsUnmarshaled
(
t
*
testing
.
T
)
{
cred
,
err
:=
Manager
.
Credential
(
"irma-demo.RU.studentCard"
,
0
)
require
.
NoError
(
t
,
err
,
"could not fetch credential"
)
require
.
NotNil
(
t
,
cred
,
"Credential should exist"
)
require
.
NotNil
(
t
,
cred
.
Attributes
[
0
],
"Metadata attribute of irma-demo.RU.studentCard should not be nil"
)
cred
,
err
:=
Manager
.
Credential
(
NewCredentialIdentifier
(
"irma-demo.RU.studentCard"
)
,
0
)
assert
.
NoError
(
t
,
err
,
"could not fetch credential"
)
assert
.
NotNil
(
t
,
cred
,
"Credential should exist"
)
assert
.
NotNil
(
t
,
cred
.
Attributes
[
0
],
"Metadata attribute of irma-demo.RU.studentCard should not be nil"
)
require
.
True
(
t
,
assert
.
True
(
t
,
cred
.
Signature
.
Verify
(
cred
.
PublicKey
(),
cred
.
Attributes
),
"Credential should be valid"
,
)
...
...
@@ -90,30 +91,30 @@ func TestUnmarshaling(t *testing.T) {
func
TestParseStore
(
t
*
testing
.
T
)
{
parseMetaStore
(
t
)
require
.
NotNil
(
t
,
MetaStore
.
Issuers
[
"irma-demo.RU"
]
.
CurrentPublicKey
()
.
N
,
"irma-demo.RU public key has no modulus"
)
require
.
Equal
(
t
,
assert
.
NotNil
(
t
,
MetaStore
.
Issuers
[
NewIssuerIdentifier
(
"irma-demo.RU"
)
]
.
CurrentPublicKey
()
.
N
,
"irma-demo.RU public key has no modulus"
)
assert
.
Equal
(
t
,
"Irma Demo"
,
MetaStore
.
SchemeManagers
[
"irma-demo"
]
.
Name
.
Translation
(
"en"
),
MetaStore
.
SchemeManagers
[
NewSchemeManagerIdentifier
(
"irma-demo"
)
]
.
Name
.
Translation
(
"en"
),
"irma-demo scheme manager has unexpected name"
)
require
.
Equal
(
t
,
assert
.
Equal
(
t
,
"Radboud Universiteit Nijmegen"
,
MetaStore
.
Issuers
[
"irma-demo.RU"
]
.
Name
.
Translation
(
"en"
),
MetaStore
.
Issuers
[
NewIssuerIdentifier
(
"irma-demo.RU"
)
]
.
Name
.
Translation
(
"en"
),
"irma-demo.RU issuer has unexpected name"
)
require
.
Equal
(
t
,
assert
.
Equal
(
t
,
"Student Card"
,
MetaStore
.
Credentials
[
"irma-demo.RU.studentCard"
]
.
ShortName
.
Translation
(
"en"
),
MetaStore
.
Credentials
[
NewCredentialIdentifier
(
"irma-demo.RU.studentCard"
)
]
.
ShortName
.
Translation
(
"en"
),
"irma-demo.RU.studentCard has unexpected name"
)
require
.
Equal
(
t
,
assert
.
Equal
(
t
,
"studentID"
,
MetaStore
.
Credentials
[
"irma-demo.RU.studentCard"
]
.
Attributes
[
2
]
.
ID
,
MetaStore
.
Credentials
[
NewCredentialIdentifier
(
"irma-demo.RU.studentCard"
)
]
.
Attributes
[
2
]
.
ID
,
"irma-demo.RU.studentCard.studentID has unexpected name"
)
// Hash algorithm pseudocode:
// Base64(SHA256("irma-demo.RU.studentCard")[0:16])
require
.
Contains
(
t
,
MetaStore
.
reverseHashes
,
"1stqlPad5edpfS1Na1U+DA=="
,
assert
.
Contains
(
t
,
MetaStore
.
reverseHashes
,
"1stqlPad5edpfS1Na1U+DA=="
,
"irma-demo.RU.studentCard had improper hash"
)
require
.
Contains
(
t
,
MetaStore
.
reverseHashes
,
"CLjnADMBYlFcuGOT7Z0xRg=="
,
assert
.
Contains
(
t
,
MetaStore
.
reverseHashes
,
"CLjnADMBYlFcuGOT7Z0xRg=="
,
"irma-demo.MijnOverheid.root had improper hash"
)
teardown
(
t
)
...
...
@@ -140,17 +141,17 @@ func TestMetadataCompatibility(t *testing.T) {
// An actual metadata attribute of an IRMA credential extracted from the IRMA app
attr
:=
MetadataFromInt
(
s2big
(
"49043481832371145193140299771658227036446546573739245068"
))
require
.
NotNil
(
t
,
attr
.
CredentialType
(),
"attr.CredentialType() should not be nil"
)
assert
.
NotNil
(
t
,
attr
.
CredentialType
(),
"attr.CredentialType() should not be nil"
)
require
.
Equal
(
t
,
"irma-demo.RU.studentCard"
,
assert
.
Equal
(
t
,
NewCredentialIdentifier
(
"irma-demo.RU.studentCard"
)
,
attr
.
CredentialType
()
.
Identifier
(),
"Metadata credential type was not irma-demo.RU.studentCard"
,
)
require
.
Equal
(
t
,
byte
(
0x02
),
attr
.
Version
(),
"Unexpected metadata version"
)
require
.
Equal
(
t
,
time
.
Unix
(
1499904000
,
0
),
attr
.
SigningDate
(),
"Unexpected signing date"
)
require
.
Equal
(
t
,
time
.
Unix
(
1516233600
,
0
),
attr
.
Expiry
(),
"Unexpected expiry date"
)
require
.
Equal
(
t
,
2
,
attr
.
KeyCounter
(),
"Unexpected key counter"
)
assert
.
Equal
(
t
,
byte
(
0x02
),
attr
.
Version
(),
"Unexpected metadata version"
)
assert
.
Equal
(
t
,
time
.
Unix
(
1499904000
,
0
),
attr
.
SigningDate
(),
"Unexpected signing date"
)
assert
.
Equal
(
t
,
time
.
Unix
(
1516233600
,
0
),
attr
.
Expiry
(),
"Unexpected expiry date"
)
assert
.
Equal
(
t
,
2
,
attr
.
KeyCounter
(),
"Unexpected key counter"
)
teardown
(
t
)
}
manager.go
View file @
3a6e8e88
...
...
@@ -18,13 +18,13 @@ var Manager = newCredentialManager()
type
CredentialManager
struct
{
secretkey
*
big
.
Int
storagePath
string
attributes
map
[
string
][]
*
AttributeList
credentials
map
[
string
]
map
[
int
]
*
Credential
attributes
map
[
CredentialIdentifier
][]
*
AttributeList
credentials
map
[
CredentialIdentifier
]
map
[
int
]
*
Credential
}
func
newCredentialManager
()
*
CredentialManager
{
return
&
CredentialManager
{
credentials
:
make
(
map
[
string
]
map
[
int
]
*
Credential
),
credentials
:
make
(
map
[
CredentialIdentifier
]
map
[
int
]
*
Credential
),
}
}
...
...
@@ -50,7 +50,7 @@ func (cm *CredentialManager) Init(path string) (err error) {
}
// attrs returns cm.attributes[id], initializing it to an empty slice if neccesary
func
(
cm
*
CredentialManager
)
attrs
(
id
string
)
[]
*
AttributeList
{
func
(
cm
*
CredentialManager
)
attrs
(
id
CredentialIdentifier
)
[]
*
AttributeList
{
list
,
exists
:=
cm
.
attributes
[
id
]
if
!
exists
{
list
=
make
([]
*
AttributeList
,
0
,
1
)
...
...
@@ -60,7 +60,7 @@ func (cm *CredentialManager) attrs(id string) []*AttributeList {
}
// creds returns cm.credentials[id], initializing it to an empty map if neccesary
func
(
cm
*
CredentialManager
)
creds
(
id
string
)
map
[
int
]
*
Credential
{
func
(
cm
*
CredentialManager
)
creds
(
id
CredentialIdentifier
)
map
[
int
]
*
Credential
{
list
,
exists
:=
cm
.
credentials
[
id
]
if
!
exists
{
list
=
make
(
map
[
int
]
*
Credential
)
...
...
@@ -70,7 +70,7 @@ func (cm *CredentialManager) creds(id string) map[int]*Credential {
}
// Attributes returns the attribute list of the requested credential, or nil if we do not have it.
func
(
cm
*
CredentialManager
)
Attributes
(
id
string
,
counter
int
)
(
attributes
*
AttributeList
)
{
func
(
cm
*
CredentialManager
)
Attributes
(
id
CredentialIdentifier
,
counter
int
)
(
attributes
*
AttributeList
)
{
list
:=
cm
.
attrs
(
id
)
if
len
(
list
)
<=
counter
{
return
...
...
@@ -79,7 +79,7 @@ func (cm *CredentialManager) Attributes(id string, counter int) (attributes *Att
}
// Credential returns the requested credential, or nil if we do not have it.
func
(
cm
*
CredentialManager
)
Credential
(
id
string
,
counter
int
)
(
cred
*
Credential
,
err
error
)
{
func
(
cm
*
CredentialManager
)
Credential
(
id
CredentialIdentifier
,
counter
int
)
(
cred
*
Credential
,
err
error
)
{
// If the requested credential is not in credential map, we check if its attributes were
// deserialized during Init(). If so, there should be a corresponding signature file,
// so we read that, construct the credential, and add it to the credential map
...
...
storage.go
View file @
3a6e8e88
...
...
@@ -106,15 +106,21 @@ func (cm *CredentialManager) storeSignature(cred *Credential, counter int) (err
}
// TODO existence check
filename
:=
cm
.
signatureFilename
(
cred
.
CredentialType
()
.
Identifier
(),
counter
)
filename
:=
cm
.
signatureFilename
(
cred
.
CredentialType
()
.
Identifier
()
.
String
()
,
counter
)
err
=
ioutil
.
WriteFile
(
filename
,
credbytes
,
0600
)
return
}
func
(
cm
*
CredentialManager
)
storeAttributes
()
(
err
error
)
{
attrbytes
,
err
:=
json
.
Marshal
(
cm
.
attributes
)
// Unfortunately, the type of cm.attributes (map[CredentialIdentifier][]*AttributeList)
// cannot be passed directly to json.Marshal(), so we copy it into a temp list.
temp
:=
make
(
map
[
string
][]
*
AttributeList
)
for
credid
,
list
:=
range
cm
.
attributes
{
temp
[
credid
.
String
()]
=
list
}
attrbytes
,
err
:=
json
.
Marshal
(
temp
)
if
err
!=
nil
{
return
return
err
}
// TODO existence check
...
...
@@ -122,8 +128,8 @@ func (cm *CredentialManager) storeAttributes() (err error) {
return
}
func
(
cm
*
CredentialManager
)
loadSignature
(
id
string
,
counter
int
)
(
signature
*
gabi
.
CLSignature
,
err
error
)
{
path
:=
cm
.
signatureFilename
(
id
,
counter
)
func
(
cm
*
CredentialManager
)
loadSignature
(
id
CredentialIdentifier
,
counter
int
)
(
signature
*
gabi
.
CLSignature
,
err
error
)
{
path
:=
cm
.
signatureFilename
(
id
.
String
()
,
counter
)
exists
,
err
:=
pathExists
(
path
)
if
err
!=
nil
||
!
exists
{
return
...
...
@@ -147,21 +153,22 @@ func (cm *CredentialManager) loadSecretKey() (*big.Int, error) {
return
nil
,
err
}
return
new
(
big
.
Int
)
.
SetBytes
(
bytes
),
nil
}
else
{
sk
,
err
:=
cm
.
generateSecretKey
()
if
err
!=
nil
{
return
nil
,
err
}
err
=
cm
.
storeSecretKey
(
sk
)
if
err
!=
nil
{
return
nil
,
err
}
return
sk
,
nil
}
sk
,
err
:=
cm
.
generateSecretKey
()
if
err
!=
nil
{
return
nil
,
err
}
err
=
cm
.
storeSecretKey
(
sk
)
if
err
!=
nil
{
return
nil
,
err
}
return
sk
,
nil
}
func
(
cm
*
CredentialManager
)
loadAttributes
()
(
list
map
[
string
][]
*
AttributeList
,
err
error
)
{
list
=
make
(
map
[
string
][]
*
AttributeList
)
func
(
cm
*
CredentialManager
)
loadAttributes
()
(
list
map
[
CredentialIdentifier
][]
*
AttributeList
,
err
error
)
{
list
=
make
(
map
[
CredentialIdentifier
][]
*
AttributeList
)
temp
:=
make
(
map
[
string
][]
*
AttributeList
)
exists
,
err
:=
pathExists
(
cm
.
path
(
attributesFile
))
if
err
!=
nil
||
!
exists
{
...
...
@@ -172,6 +179,13 @@ func (cm *CredentialManager) loadAttributes() (list map[string][]*AttributeList,
if
err
!=
nil
{
return
nil
,
err
}
return
list
,
json
.
Unmarshal
(
bytes
,
&
list
)
err
=
json
.
Unmarshal
(
bytes
,
&
temp
)
if
err
!=
nil
{
return
nil
,
err
}
for
credid
,
attrs
:=
range
temp
{
list
[
NewCredentialIdentifier
(
credid
)]
=
attrs
}
return
list
,
nil
}
store.go
View file @
3a6e8e88
...
...
@@ -18,28 +18,28 @@ var MetaStore = newConfigurationStore()
// ConfigurationStore keeps track of scheme managers, issuers, credential types and public keys.
// Use the global MetaStore instance.
type
ConfigurationStore
struct
{
SchemeManagers
map
[
string
]
*
SchemeManager
Issuers
map
[
string
]
*
Issuer
Credentials
map
[
string
]
*
CredentialType
PublicKeys
map
[
string
][]
*
gabi
.
PublicKey
SchemeManagers
map
[
SchemeManagerIdentifier
]
*
SchemeManager
Issuers
map
[
IssuerIdentifier
]
*
Issuer
Credentials
map
[
CredentialIdentifier
]
*
CredentialType
PublicKeys
map
[
IssuerIdentifier
][]
*
gabi
.
PublicKey
reverseHashes
map
[
string
]
string
reverseHashes
map
[
string
]
CredentialIdentifier
initialized
bool
}
func
newConfigurationStore
()
(
store
*
ConfigurationStore
)
{
store
=
&
ConfigurationStore
{
SchemeManagers
:
make
(
map
[
string
]
*
SchemeManager
),
Issuers
:
make
(
map
[
string
]
*
Issuer
),
Credentials
:
make
(
map
[
string
]
*
CredentialType
),
PublicKeys
:
make
(
map
[
string
][]
*
gabi
.
PublicKey
),
reverseHashes
:
make
(
map
[
string
]
string
),
SchemeManagers
:
make
(
map
[
SchemeManagerIdentifier
]
*
SchemeManager
),
Issuers
:
make
(
map
[
IssuerIdentifier
]
*
Issuer
),
Credentials
:
make
(
map
[
CredentialIdentifier
]
*
CredentialType
),
PublicKeys
:
make
(
map
[
IssuerIdentifier
][]
*
gabi
.
PublicKey
),
reverseHashes
:
make
(
map
[
string
]
CredentialIdentifier
),
}
return
}
// PublicKey returns the specified public key, or nil if not present in the ConfigurationStore.
func
(
store
*
ConfigurationStore
)
PublicKey
(
id
string
,
counter
int
)
*
gabi
.
PublicKey
{
func
(
store
*
ConfigurationStore
)
PublicKey
(
id
IssuerIdentifier
,
counter
int
)
*
gabi
.
PublicKey
{
if
list
,
ok
:=
MetaStore
.
PublicKeys
[
id
];
ok
{
if
len
(
list
)
>
counter
{
return
list
[
counter
]
...
...
@@ -48,8 +48,8 @@ func (store *ConfigurationStore) PublicKey(id string, counter int) *gabi.PublicK
return
nil
}
func
(
store
*
ConfigurationStore
)
addReverseHash
(
credid
string
)
{
hash
:=
sha256
.
Sum256
([]
byte
(
credid
))
func
(
store
*
ConfigurationStore
)
addReverseHash
(
credid
CredentialIdentifier
)
{
hash
:=
sha256
.
Sum256
([]
byte
(
credid
.
String
()
))
store
.
reverseHashes
[
base64
.
StdEncoding
.
EncodeToString
(
hash
[
:
16
])]
=
credid
}
...
...
@@ -60,6 +60,7 @@ func (store *ConfigurationStore) hashToCredentialType(hash []byte) *CredentialTy
return
nil
}
// IsInitialized indicates whether this instance has successfully been initialized.
func
(
store
*
ConfigurationStore
)
IsInitialized
()
bool
{
return
store
.
initialized
}
...
...
@@ -74,7 +75,7 @@ func (store *ConfigurationStore) ParseFolder(path string) error {
return
err
}
if
exists
{
MetaStore
.
SchemeManagers
[
manager
.
I
D
]
=
manager
MetaStore
.
SchemeManagers
[
manager
.
I
dentifier
()
]
=
manager
return
store
.
parseIssuerFolders
(
dir
)
}
return
nil
...
...
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