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
d492d12a
Commit
d492d12a
authored
Jul 24, 2017
by
Sietse Ringers
Browse files
Move metastore & descriptions from gabi
parent
972085b9
Changes
8
Hide whitespace changes
Inline
Side-by-side
attributes.go
View file @
d492d12a
...
...
@@ -2,24 +2,56 @@ package irmago
import
(
"crypto/sha256"
"encoding/binary"
"math/big"
"time"
"github.com/mhe/gabi"
)
const
(
// ExpiryFactor is the precision for the expiry attribute. Value is one week.
ExpiryFactor
=
60
*
60
*
24
*
7
// ValidityDefault is the default validity of new credentials (half a year).
ValidityDefault
=
52
/
2
metadataLength
=
1
+
3
+
2
+
2
+
16
)
var
(
metadataVersion
=
[]
byte
{
0x02
}
versionField
=
MetadataField
{
1
,
0
}
signingDateField
=
MetadataField
{
3
,
1
}
validityField
=
MetadataField
{
2
,
4
}
keyCounterField
=
MetadataField
{
2
,
6
}
credentialID
=
MetadataField
{
16
,
8
}
)
// MetadataField contains the length and offset of a field within a metadata attribute.
type
MetadataField
struct
{
length
int
offset
int
}
// MetadataAttribute represent a metadata attribute. Contains the credential type, signing date, validity, and the public key counter.
type
MetadataAttribute
struct
{
Int
*
big
.
Int
pk
*
gabi
.
PublicKey
}
// AttributeList contains attributes, excluding the secret key,
// providing convenient access to the metadata attribute.
type
AttributeList
struct
{
Ints
[]
*
big
.
Int
strings
[]
string
*
gabi
.
MetadataAttribute
`json:"-"`
Ints
[]
*
big
.
Int
strings
[]
string
*
MetadataAttribute
`json:"-"`
}
// NewAttributeListFromInts initializes a new AttributeList from a list of bigints.
func
NewAttributeListFromInts
(
ints
[]
*
big
.
Int
)
*
AttributeList
{
return
&
AttributeList
{
Ints
:
ints
,
MetadataAttribute
:
gabi
.
MetadataFromInt
(
ints
[
0
]),
MetadataAttribute
:
MetadataFromInt
(
ints
[
0
]),
}
}
...
...
@@ -43,3 +75,137 @@ func (al *AttributeList) Strings() []string {
}
return
al
.
strings
}
// MetadataFromInt wraps the given Int
func
MetadataFromInt
(
i
*
big
.
Int
)
*
MetadataAttribute
{
return
&
MetadataAttribute
{
Int
:
i
}
}
// NewMetadataAttribute constructs a new instance containing the default values:
// 0x02 as versionField
// now as signing date
// 0 as keycounter
// ValidityDefault (half a year) as default validity.
func
NewMetadataAttribute
()
*
MetadataAttribute
{
val
:=
MetadataAttribute
{
new
(
big
.
Int
),
nil
}
val
.
setField
(
versionField
,
metadataVersion
)
val
.
setSigningDate
()
val
.
setKeyCounter
(
0
)
val
.
setValidityDuration
(
ValidityDefault
)
return
&
val
}
// Bytes returns this metadata attribute as a byte slice.
func
(
attr
*
MetadataAttribute
)
Bytes
()
[]
byte
{
bytes
:=
attr
.
Int
.
Bytes
()
if
len
(
bytes
)
<
metadataLength
{
bytes
=
append
(
bytes
,
make
([]
byte
,
metadataLength
-
len
(
bytes
))
...
)
}
return
bytes
}
// PublicKey extracts identifier of the Idemix public key with which this instance was signed,
// and returns this public key.
func
(
attr
*
MetadataAttribute
)
PublicKey
()
*
gabi
.
PublicKey
{
if
attr
.
pk
==
nil
{
attr
.
pk
=
MetaStore
.
PublicKey
(
attr
.
CredentialType
()
.
IssuerIdentifier
(),
attr
.
KeyCounter
())
}
return
attr
.
pk
}
// Version returns the metadata version of this instance
func
(
attr
*
MetadataAttribute
)
Version
()
byte
{
return
attr
.
field
(
versionField
)[
0
]
}
// SigningDate returns the time at which this instance was signed
func
(
attr
*
MetadataAttribute
)
SigningDate
()
time
.
Time
{
bytes
:=
attr
.
field
(
signingDateField
)
bytes
=
bytes
[
1
:
]
// The signing date field is one byte too long
timestamp
:=
int64
(
binary
.
BigEndian
.
Uint16
(
bytes
))
*
ExpiryFactor
return
time
.
Unix
(
timestamp
,
0
)
}
func
(
attr
*
MetadataAttribute
)
setSigningDate
()
{
attr
.
setField
(
signingDateField
,
shortToByte
(
int
(
time
.
Now
()
.
Unix
()
/
ExpiryFactor
)))
}
// KeyCounter return the public key counter of the metadata attribute
func
(
attr
*
MetadataAttribute
)
KeyCounter
()
int
{
return
int
(
binary
.
BigEndian
.
Uint16
(
attr
.
field
(
keyCounterField
)))
}
func
(
attr
*
MetadataAttribute
)
setKeyCounter
(
i
int
)
{
attr
.
setField
(
keyCounterField
,
shortToByte
(
i
))
}
// ValidityDuration returns the amount of epochs during which this instance is valid
func
(
attr
*
MetadataAttribute
)
ValidityDuration
()
int
{
return
int
(
binary
.
BigEndian
.
Uint16
(
attr
.
field
(
validityField
)))
}
func
(
attr
*
MetadataAttribute
)
setValidityDuration
(
weeks
int
)
{
attr
.
setField
(
validityField
,
shortToByte
(
weeks
))
}
// CredentialType returns the credential type of the current instance
// using the MetaStore.
func
(
attr
*
MetadataAttribute
)
CredentialType
()
*
CredentialType
{
return
MetaStore
.
hashToCredentialType
(
attr
.
field
(
credentialID
))
}
func
(
attr
*
MetadataAttribute
)
setCredentialIdentifier
(
id
string
)
{
bytes
:=
sha256
.
Sum256
([]
byte
(
id
))
attr
.
setField
(
credentialID
,
bytes
[
:
16
])
}
// Expiry returns the expiry date of this instance
func
(
attr
*
MetadataAttribute
)
Expiry
()
time
.
Time
{
expiry
:=
attr
.
SigningDate
()
.
Unix
()
+
int64
(
attr
.
ValidityDuration
()
*
ExpiryFactor
)
return
time
.
Unix
(
expiry
,
0
)
}
// IsValidOn returns whether this instance is still valid at the given time
func
(
attr
*
MetadataAttribute
)
IsValidOn
(
t
time
.
Time
)
bool
{
return
attr
.
Expiry
()
.
After
(
t
)
}
// IsValid returns whether this instance is valid.
func
(
attr
*
MetadataAttribute
)
IsValid
()
bool
{
return
attr
.
IsValidOn
(
time
.
Now
())
}
func
(
attr
*
MetadataAttribute
)
field
(
field
MetadataField
)
[]
byte
{
return
attr
.
Bytes
()[
field
.
offset
:
field
.
offset
+
field
.
length
]
}
func
(
attr
*
MetadataAttribute
)
setField
(
field
MetadataField
,
value
[]
byte
)
{
if
len
(
value
)
>
field
.
length
{
panic
(
"Specified metadata field too large"
)
}
bytes
:=
attr
.
Bytes
()
// Push the value to the right within the field. Graphical representation:
// --xxxXXX----
// "-" indicates a byte of another field
// "X" is a byte of the value and "x" of our field
// In this example, our field has offset 2, length 6,
// but the specified value is only 3 bytes long.
startindex
:=
field
.
length
-
len
(
value
)
for
i
:=
0
;
i
<
field
.
length
;
i
++
{
if
i
<
startindex
{
bytes
[
i
+
field
.
offset
]
=
0
}
else
{
bytes
[
i
+
field
.
offset
]
=
value
[
i
-
startindex
]
}
}
attr
.
Int
.
SetBytes
(
bytes
)
}
func
shortToByte
(
x
int
)
[]
byte
{
bytes
:=
make
([]
byte
,
2
)
binary
.
BigEndian
.
PutUint16
(
bytes
,
uint16
(
x
))
return
bytes
}
credential.go
0 → 100644
View file @
d492d12a
package
irmago
import
"github.com/mhe/gabi"
// Credential represents an IRMA credential, whose zeroth attribute
// is always the secret key and the first attribute the metadata attribute.
type
Credential
struct
{
*
gabi
.
Credential
*
MetadataAttribute
}
func
newCredential
(
gabicred
*
gabi
.
Credential
)
(
cred
*
Credential
)
{
cred
=
&
Credential
{}
cred
.
Credential
=
gabicred
cred
.
MetadataAttribute
=
MetadataFromInt
(
gabicred
.
Attributes
[
1
])
return
}
descriptions.go
0 → 100644
View file @
d492d12a
package
irmago
import
(
"encoding/xml"
"github.com/mhe/gabi"
)
// SchemeManager describes a scheme manager.
type
SchemeManager
struct
{
Name
string
`xml:"Id"`
URL
string
`xml:"Contact"`
HRName
TranslatedString
`xml:"Name"`
Description
TranslatedString
KeyshareServer
string
KeyshareWebsite
string
KeyshareAttribute
string
XMLVersion
int
`xml:"version,attr"`
XMLName
xml
.
Name
`xml:"SchemeManager"`
}
// Issuer describes an issuer.
type
Issuer
struct
{
HRName
TranslatedString
`xml:"Name"`
HRShortName
TranslatedString
`xml:"ShortName"`
Name
string
`xml:"ID"`
SchemeManagerName
string
`xml:"SchemeManager"`
ContactAddress
string
ContactEMail
string
URL
string
`xml:"baseURL"`
XMLVersion
int
`xml:"version,attr"`
}
// CredentialType is a description of a credential type, specifying (a.o.) its name, issuer, and attributes.
type
CredentialType
struct
{
HRName
TranslatedString
`xml:"Name"`
HRShortName
TranslatedString
`xml:"ShortName"`
IssuerName
string
`xml:"IssuerID"`
SchemeManagerName
string
`xml:"SchemeManager"`
Name
string
`xml:"CredentialID"`
IsSingleton
bool
`xml:"ShouldBeSingleton"`
Description
TranslatedString
Attributes
[]
AttributeDescription
`xml:"Attributes>Attribute"`
XMLVersion
int
`xml:"version,attr"`
XMLName
xml
.
Name
`xml:"IssueSpecification"`
}
// AttributeDescription is a description of an attribute within a credential type.
type
AttributeDescription
struct
{
ID
string
`xml:"id,attr"`
Name
TranslatedString
Description
TranslatedString
}
// TranslatedString represents an XML tag containing a string translated to multiple languages.
// For example: <Foo id="bla"><Translation lang="en">Hello world</Translation><Translation lang="nl">Hallo wereld</Translation></Foo>
// type TranslatedString struct {
// Translations []struct {
// Language string `xml:"lang,attr"`
// Value string `xml:",chardata"`
// } `xml:"Translation"`
// ID string `xml:"id,attr"`
// }
//
// // Get returns the specified translation
// func (ts TranslatedString) Get(lang string) string {
// for _, l := range ts.Translations {
// if l.Language == lang {
// return l.Value
// }
// }
// return ""
// }
// TranslatedString represents an XML tag containing a string translated to multiple languages.
// For example: <Foo id="bla"><en>Hello world</en><nl>Hallo wereld</nl></Foo>
type
TranslatedString
struct
{
Translations
[]
struct
{
XMLName
xml
.
Name
Text
string
`xml:",chardata"`
}
`xml:",any"`
}
// Translation returns the specified translation.
func
(
ts
*
TranslatedString
)
Translation
(
lang
string
)
string
{
for
_
,
translation
:=
range
ts
.
Translations
{
if
translation
.
XMLName
.
Local
==
lang
{
return
translation
.
Text
}
}
return
""
}
// Identifier returns the identifier of the specified credential type.
func
(
cd
*
CredentialType
)
Identifier
()
string
{
return
cd
.
SchemeManagerName
+
"."
+
cd
.
IssuerName
+
"."
+
cd
.
Name
}
// IssuerIdentifier returns the issuer identifier of the specified credential type.
func
(
cd
*
CredentialType
)
IssuerIdentifier
()
string
{
return
cd
.
SchemeManagerName
+
"."
+
cd
.
IssuerName
}
// Identifier returns the identifier of the specified issuer description.
func
(
id
*
Issuer
)
Identifier
()
string
{
return
id
.
SchemeManagerName
+
"."
+
id
.
Name
}
// CurrentPublicKey returns the latest known public key of the issuer identified by this instance.
func
(
id
*
Issuer
)
CurrentPublicKey
()
*
gabi
.
PublicKey
{
keys
:=
MetaStore
.
PublicKeys
[
id
.
Identifier
()]
if
keys
==
nil
||
len
(
keys
)
==
0
{
return
nil
}
return
keys
[
len
(
keys
)
-
1
]
}
// PublicKey returns the specified public key of the issuer identified by this instance.
func
(
id
*
Issuer
)
PublicKey
(
index
int
)
*
gabi
.
PublicKey
{
keys
:=
MetaStore
.
PublicKeys
[
id
.
Identifier
()]
if
keys
==
nil
||
index
>=
len
(
keys
)
{
return
nil
}
return
keys
[
index
]
}
irmago_test.go
View file @
d492d12a
package
irmago
import
"testing"
import
(
"fmt"
"math/big"
"os"
"testing"
"time"
"fmt"
"github.com/mhe/gabi"
"github.com/stretchr/testify/assert"
)
func
TestMain
(
m
*
testing
.
M
)
{
if
len
(
gabi
.
MetaStore
.
SchemeManagers
)
==
0
{
// FIXME
gabi
.
MetaStore
.
ParseFolder
(
"testdata/irma_configuration"
)
if
len
(
MetaStore
.
SchemeManagers
)
==
0
{
// FIXME
MetaStore
.
ParseFolder
(
"testdata/irma_configuration"
)
}
Manager
=
newCredentialManager
()
err
:=
os
.
RemoveAll
(
"testdata/storage/test"
)
...
...
@@ -36,6 +37,13 @@ func TestMain(m *testing.M) {
os
.
Exit
(
retCode
)
}
// A convenience function for initializing big integers from known correct (10
// base) strings. Use with care, errors are ignored.
func
s2big
(
s
string
)
(
r
*
big
.
Int
)
{
r
,
_
=
new
(
big
.
Int
)
.
SetString
(
s
,
10
)
return
}
func
parseAndroidStorage
(
t
*
testing
.
T
)
{
err
:=
Manager
.
Init
(
"testdata/storage/test"
)
assert
.
NoError
(
t
,
err
,
"Manager.Init() failed"
)
...
...
@@ -68,3 +76,73 @@ func TestUnmarshaling(t *testing.T) {
verifyStoreIsUnmarshaled
(
t
)
}
func
TestParseStore
(
t
*
testing
.
T
)
{
err
:=
MetaStore
.
ParseFolder
(
"testdata/irma_configuration"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
assert
.
NotNil
(
t
,
MetaStore
.
Issuers
[
"irma-demo.RU"
]
.
CurrentPublicKey
()
.
N
,
"irma-demo.RU public key has no modulus"
)
assert
.
Equal
(
t
,
"Irma Demo"
,
MetaStore
.
SchemeManagers
[
"irma-demo"
]
.
HRName
.
Translation
(
"en"
),
"irma-demo scheme manager has unexpected name"
)
assert
.
Equal
(
t
,
"Radboud Universiteit Nijmegen"
,
MetaStore
.
Issuers
[
"irma-demo.RU"
]
.
HRName
.
Translation
(
"en"
),
"irma-demo.RU issuer has unexpected name"
)
assert
.
Equal
(
t
,
"Student Card"
,
MetaStore
.
Credentials
[
"irma-demo.RU.studentCard"
]
.
HRShortName
.
Translation
(
"en"
),
"irma-demo.RU.studentCard has unexpected name"
)
assert
.
Equal
(
t
,
"studentID"
,
MetaStore
.
Credentials
[
"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])
assert
.
Contains
(
t
,
MetaStore
.
reverseHashes
,
"1stqlPad5edpfS1Na1U+DA=="
,
"irma-demo.RU.studentCard had improper hash"
)
assert
.
Contains
(
t
,
MetaStore
.
reverseHashes
,
"CLjnADMBYlFcuGOT7Z0xRg=="
,
"irma-demo.MijnOverheid.root had improper hash"
)
}
func
TestMetadataAttribute
(
t
*
testing
.
T
)
{
metadata
:=
NewMetadataAttribute
()
if
metadata
.
Version
()
!=
0x02
{
t
.
Errorf
(
"Unexpected metadata version: %d"
,
metadata
.
Version
())
}
expiry
:=
metadata
.
SigningDate
()
.
Unix
()
+
int64
(
metadata
.
ValidityDuration
()
*
ExpiryFactor
)
if
!
time
.
Unix
(
expiry
,
0
)
.
Equal
(
metadata
.
Expiry
())
{
t
.
Errorf
(
"Invalid signing date"
)
}
if
metadata
.
KeyCounter
()
!=
0
{
t
.
Errorf
(
"Unexpected key counter"
)
}
}
func
TestMetadataCompatibility
(
t
*
testing
.
T
)
{
err
:=
MetaStore
.
ParseFolder
(
"testdata/irma_configuration"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// An actual metadata attribute of an IRMA credential extracted from the IRMA app
attr
:=
MetadataFromInt
(
s2big
(
"49043481832371145193140299771658227036446546573739245068"
))
assert
.
NotNil
(
t
,
attr
.
CredentialType
(),
"attr.CredentialType() should not be nil"
)
assert
.
Equal
(
t
,
"irma-demo.RU.studentCard"
,
attr
.
CredentialType
()
.
Identifier
(),
"Metadata credential type was not irma-demo.RU.studentCard"
,
)
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"
)
}
manager.go
View file @
d492d12a
...
...
@@ -19,12 +19,12 @@ type CredentialManager struct {
secretkey
*
big
.
Int
storagePath
string
attributes
map
[
string
][]
*
AttributeList
credentials
map
[
string
]
map
[
int
]
*
gabi
.
Credential
credentials
map
[
string
]
map
[
int
]
*
Credential
}
func
newCredentialManager
()
*
CredentialManager
{
return
&
CredentialManager
{
credentials
:
make
(
map
[
string
]
map
[
int
]
*
gabi
.
Credential
),
credentials
:
make
(
map
[
string
]
map
[
int
]
*
Credential
),
}
}
...
...
@@ -60,10 +60,10 @@ 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
]
*
gabi
.
Credential
{
func
(
cm
*
CredentialManager
)
creds
(
id
string
)
map
[
int
]
*
Credential
{
list
,
exists
:=
cm
.
credentials
[
id
]
if
!
exists
{
list
=
make
(
map
[
int
]
*
gabi
.
Credential
)
list
=
make
(
map
[
int
]
*
Credential
)
cm
.
credentials
[
id
]
=
list
}
return
list
...
...
@@ -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
*
gabi
.
Credential
,
err
error
)
{
func
(
cm
*
CredentialManager
)
Credential
(
id
string
,
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
...
...
@@ -97,7 +97,11 @@ func (cm *CredentialManager) Credential(id string, counter int) (cred *gabi.Cred
err
=
errors
.
New
(
"signature file not found"
)
return
nil
,
err
}
cred
:=
gabi
.
NewCredential
(
ints
,
sig
,
nil
)
cred
:=
newCredential
(
&
gabi
.
Credential
{
Attributes
:
ints
,
Signature
:
sig
,
Pk
:
nil
,
// TODO
})
cm
.
credentials
[
id
][
counter
]
=
cred
}
...
...
@@ -135,9 +139,8 @@ func (cm *CredentialManager) ParseAndroidStorage() (err error) {
for
_
,
list
:=
range
parsedjson
{
cm
.
secretkey
=
list
[
0
]
.
Attributes
[
0
]
for
i
,
cred
:=
range
list
{
// TODO move this metadata initialisation somehow into gabi.Credential?
cred
.
MetadataAttribute
=
gabi
.
MetadataFromInt
(
cred
.
Attributes
[
1
])
for
i
,
gabicred
:=
range
list
{
cred
:=
newCredential
(
gabicred
)
if
cred
.
CredentialType
()
==
nil
{
return
errors
.
New
(
"cannot add unknown credential type"
)
}
...
...
@@ -164,19 +167,19 @@ func (cm *CredentialManager) ParseAndroidStorage() (err error) {
return
}
func
(
cm
*
CredentialManager
)
addCredential
(
cred
*
gabi
.
Credential
)
{
func
(
cm
*
CredentialManager
)
addCredential
(
cred
*
Credential
)
{
id
:=
cred
.
CredentialType
()
.
Identifier
()
cm
.
attributes
[
id
]
=
append
(
cm
.
attrs
(
id
),
NewAttributeListFromInts
(
cred
.
Attributes
[
1
:
]))
if
_
,
exists
:=
cm
.
credentials
[
id
];
!
exists
{
cm
.
credentials
[
id
]
=
make
(
map
[
int
]
*
gabi
.
Credential
)
cm
.
credentials
[
id
]
=
make
(
map
[
int
]
*
Credential
)
}
counter
:=
len
(
cm
.
attributes
[
id
])
-
1
cm
.
credentials
[
id
][
counter
]
=
cred
}
// Add adds the specified credential to the CredentialManager.
func
(
cm
*
CredentialManager
)
Add
(
cred
*
gabi
.
Credential
)
(
err
error
)
{
func
(
cm
*
CredentialManager
)
Add
(
cred
*
Credential
)
(
err
error
)
{
if
cred
.
CredentialType
()
==
nil
{
return
errors
.
New
(
"cannot add unknown credential type"
)
}
...
...
storage.go
View file @
d492d12a
...
...
@@ -9,9 +9,10 @@ import (
"crypto/rand"
"encoding/hex"
"github.com/mhe/gabi"
"math/big"
"path"
"github.com/mhe/gabi"
)
// Filenames in which we store stuff
...
...
@@ -94,7 +95,7 @@ func (cm *CredentialManager) saveFile(filepath string, content []byte) (err erro
return
os
.
Rename
(
dir
+
"/"
+
tempfilename
,
filepath
)
}
func
(
cm
*
CredentialManager
)
storeSignature
(
cred
*
gabi
.
Credential
,
counter
int
)
(
err
error
)
{
func
(
cm
*
CredentialManager
)
storeSignature
(
cred
*
Credential
,
counter
int
)
(
err
error
)
{
if
cred
.
CredentialType
()
==
nil
{
return
errors
.
New
(
"cannot add unknown credential type"
)
}
...
...
store.go
0 → 100644
View file @
d492d12a
package
irmago
import
(
"crypto/sha256"
"encoding/base64"
"encoding/xml"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"github.com/mhe/gabi"
)
// MetaStore is the global instance of ConfigurationStore
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
reverseHashes
map
[
string
]
string
}
func
newConfigurationStore
()
(
store
*
ConfigurationStore
)
{
store
=
&
ConfigurationStore
{
make
(
map
[
string
]
*
SchemeManager
),
make
(
map
[
string
]
*
Issuer
),
make
(
map
[
string
]
*
CredentialType
),
make
(
map
[
string
][]
*
gabi
.
PublicKey
),
make
(
map
[
string
]
string
),
}
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
{
if
list
,
ok
:=
MetaStore
.
PublicKeys
[
id
];
ok
{
if
len
(
list
)
>
counter
{
return
list
[
counter
]
}
}
return
nil
}
func
(
store
*
ConfigurationStore
)
addReverseHash
(
credid
string
)
{
hash
:=
sha256
.
Sum256
([]
byte
(
credid
))
store
.
reverseHashes
[
base64
.
StdEncoding
.
EncodeToString
(
hash
[
:
16
])]
=
credid
}
func
(
store
*
ConfigurationStore
)
hashToCredentialType
(
hash
[]
byte
)
*
CredentialType
{
if
str
,
exists
:=
store
.
reverseHashes
[
base64
.
StdEncoding
.
EncodeToString
(
hash
)];
exists
{
return
store
.
Credentials
[
str
]
}
return
nil
}
// ParseFolder populates the current store by parsing the specified irma_configuration folder,
// listing the containing scheme managers, issuers, credential types and public keys.
func
(
store
*
ConfigurationStore
)
ParseFolder
(
path
string
)
error
{
return
iterateSubfolders
(
path
,
func
(
dir
string
)
error
{
manager
:=
&
SchemeManager
{}
exists
,
err
:=
pathToDescription
(
dir
+
"/description.xml"
,
manager
)
if
err
!=
nil
{
return
err