Commit 90c9aea5 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

ParseAndroidStorage now also handles irma_configuration

parent 112f7e8f
......@@ -57,7 +57,10 @@ func s2big(s string) (r *big.Int) {
}
func parseAndroidStorage(t *testing.T, manager *CredentialManager) {
require.NoError(t, manager.ParseAndroidStorage(), "ParseAndroidStorage() failed")
oldStoragePath = "testdata/oldstorage"
present, err := manager.ParseAndroidStorage()
require.NoError(t, err, "ParseAndroidStorage() failed")
require.True(t, present, "Android storage not found")
}
func verifyManagerIsUnmarshaled(t *testing.T, manager *CredentialManager) {
......@@ -127,7 +130,13 @@ func verifyKeyshareIsUnmarshaled(t *testing.T, manager *CredentialManager) {
verifyPaillierKey(t, manager.paillierKeyCache)
}
func verifyStoreIsLoaded(t *testing.T, store *ConfigurationStore) {
func verifyStoreIsLoaded(t *testing.T, store *ConfigurationStore, android bool) {
require.Contains(t, store.SchemeManagers, NewSchemeManagerIdentifier("irma-demo"))
require.Contains(t, store.SchemeManagers, NewSchemeManagerIdentifier("test"))
if android {
require.Contains(t, store.SchemeManagers, NewSchemeManagerIdentifier("test2"))
}
pk, err := store.PublicKey(NewIssuerIdentifier("irma-demo.RU"), 0)
require.NoError(t, err)
require.NotNil(t, pk)
......@@ -160,9 +169,9 @@ func verifyStoreIsLoaded(t *testing.T, store *ConfigurationStore) {
func TestAndroidParse(t *testing.T) {
manager := parseStorage(t)
verifyStoreIsLoaded(t, manager.Store)
verifyStoreIsLoaded(t, manager.Store, false)
parseAndroidStorage(t, manager)
verifyStoreIsLoaded(t, manager.Store, true)
verifyManagerIsUnmarshaled(t, manager)
verifyCredentials(t, manager)
verifyKeyshareIsUnmarshaled(t, manager)
......@@ -201,7 +210,7 @@ func TestMetadataAttribute(t *testing.T) {
}
func TestMetadataCompatibility(t *testing.T) {
store := NewConfigurationStore("testdata")
store := NewConfigurationStore("testdata/irma_configuration")
require.NoError(t, store.ParseFolder())
// An actual metadata attribute of an IRMA credential extracted from the IRMA app
......@@ -222,7 +231,7 @@ func TestMetadataCompatibility(t *testing.T) {
}
func TestAttributeDisjunctionMarshaling(t *testing.T) {
store := NewConfigurationStore("testdata")
store := NewConfigurationStore("testdata/irma_configuration")
store.ParseFolder()
disjunction := AttributeDisjunction{}
......
......@@ -21,7 +21,8 @@ type CredentialManager struct {
keyshareServers map[SchemeManagerIdentifier]*keyshareServer
paillierKeyCache *paillierPrivateKey
Store *ConfigurationStore
irmaConfigurationPath string
Store *ConfigurationStore
}
// CredentialInfoList returns a list of information of all contained credentials.
......
......@@ -11,20 +11,21 @@ import (
"github.com/mhe/gabi"
)
var oldStoragePath = "/data/data/org.irmacard.cardemu"
// ParseAndroidStorage parses an Android cardemu.xml shared preferences file
// from the old Android IRMA app, parsing its credentials into the current instance,
// and saving them to storage.
// CAREFUL: this method overwrites any existing secret keys and attributes on storage.
func (cm *CredentialManager) ParseAndroidStorage() (err error) {
exists, err := PathExists(cm.path(cardemuXML))
if err != nil {
func (cm *CredentialManager) ParseAndroidStorage() (present bool, err error) {
cardemuXML := oldStoragePath + "/shared_prefs/cardemu.xml"
present, err = PathExists(cardemuXML)
if err != nil || !present {
return
}
if !exists {
return errors.New("cardemu.xml not found at " + cardemuXML)
}
present = true
bytes, err := ioutil.ReadFile(cm.path(cardemuXML))
bytes, err := ioutil.ReadFile(cardemuXML)
if err != nil {
return
}
......@@ -76,46 +77,46 @@ func (cm *CredentialManager) ParseAndroidStorage() (err error) {
if oldcred.SharedPoints != nil && len(oldcred.SharedPoints) > 0 {
gabicred.Signature.KeyshareP = oldcred.SharedPoints[0]
}
cred, err := newCredential(gabicred, cm.Store)
if err != nil {
return err
var cred *credential
if cred, err = newCredential(gabicred, cm.Store); err != nil {
return
}
if cred.CredentialType() == nil {
return errors.New("cannot add unknown credential type")
err = errors.New("cannot add unknown credential type")
return
}
err = cm.addCredential(cred, false)
if err != nil {
return err
if err = cm.addCredential(cred, false); err != nil {
return
}
}
}
if len(cm.credentials) > 0 {
err = cm.storeAttributes()
if err != nil {
return err
if err = cm.storeAttributes(); err != nil {
return
}
err = cm.storeSecretKey(cm.secretkey)
if err != nil {
return err
if err = cm.storeSecretKey(cm.secretkey); err != nil {
return
}
}
if len(cm.keyshareServers) > 0 {
err = cm.storeKeyshareServers()
if err != nil {
return err
if err = cm.storeKeyshareServers(); err != nil {
return
}
}
err = cm.storePaillierKeys()
if err != nil {
return err
if err = cm.storePaillierKeys(); err != nil {
return
}
if cm.paillierKeyCache == nil {
cm.paillierKey(false) // trigger calculating a new one
}
return
if err = cm.Store.Copy(oldStoragePath+"/app_store/irma_configuration", false); err != nil {
return
}
// Copy from assets again to ensure we have the latest versions
return present, cm.Store.Copy(cm.irmaConfigurationPath, true)
}
......@@ -23,15 +23,8 @@ const (
kssFile = "kss"
paillierFile = "paillier"
signaturesDir = "sigs"
cardemuXML = "../cardemu.xml"
)
type update struct {
when Timestamp
number int
info string
}
// PathExists checks if the specified path exists.
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
......@@ -76,20 +69,21 @@ func NewCredentialManager(
) (*CredentialManager, error) {
var err error
cm := &CredentialManager{
credentials: make(map[CredentialTypeIdentifier]map[int]*credential),
keyshareServers: make(map[SchemeManagerIdentifier]*keyshareServer),
credentials: make(map[CredentialTypeIdentifier]map[int]*credential),
keyshareServers: make(map[SchemeManagerIdentifier]*keyshareServer),
irmaConfigurationPath: irmaConfigurationPath,
Store: NewConfigurationStore(storagePath + "/irma_configuration"),
}
cm.Store = NewConfigurationStore(storagePath)
cm.Store.Copy(irmaConfigurationPath)
if err = cm.Store.ParseFolder(); err != nil {
cm.storagePath = storagePath
if err = cm.ensureStorageExists(); err != nil {
return nil, err
}
cm.storagePath = storagePath
if err = cm.ensureStorageExists(); err != nil {
if err = cm.Store.ParseFolder(); err != nil {
return nil, err
}
if cm.secretkey, err = cm.loadSecretKey(); err != nil {
return nil, err
}
......@@ -133,15 +127,27 @@ func (cm *CredentialManager) signatureFilename(id string, counter int) string {
// NOTE: we do not create the folder if it does not exist!
// Setting it up in a properly protected location (e.g., with automatic
// backups to iCloud/Google disabled) is the responsibility of the user.
func (cm *CredentialManager) ensureStorageExists() (err error) {
func (cm *CredentialManager) ensureStorageExists() error {
exist, err := PathExists(cm.storagePath)
if err != nil {
return
return err
}
if !exist {
return errors.New("credential storage path does not exist")
}
if exist, err = PathExists(cm.Store.path); err != nil {
return err
}
if !exist {
if err = ensureDirectoryExists(cm.Store.path); err != nil {
return err
}
cm.Store.Copy(cm.irmaConfigurationPath, false)
if err = cm.Store.ParseFolder(); err != nil {
return err
}
}
return ensureDirectoryExists(cm.path(signaturesDir))
}
......
......@@ -34,7 +34,7 @@ func NewConfigurationStore(path string) (store *ConfigurationStore) {
Credentials: make(map[CredentialTypeIdentifier]*CredentialType),
publicKeys: make(map[IssuerIdentifier][]*gabi.PublicKey),
reverseHashes: make(map[string]CredentialTypeIdentifier),
path: path + "/irma_configuration",
path: path,
}
return
}
......@@ -42,6 +42,8 @@ func NewConfigurationStore(path string) (store *ConfigurationStore) {
// ParseFolder populates the current store by parsing the storage path,
// listing the containing scheme managers, issuers and credential types.
func (store *ConfigurationStore) ParseFolder() error {
*store = *NewConfigurationStore(store.path) // Init all maps
err := iterateSubfolders(store.path, func(dir string) error {
manager := &SchemeManager{}
exists, err := pathToDescription(dir+"/description.xml", manager)
......@@ -207,13 +209,13 @@ func (store *ConfigurationStore) Contains(cred CredentialTypeIdentifier) bool {
store.Credentials[cred] != nil
}
func (store *ConfigurationStore) Copy(source string) error {
func (store *ConfigurationStore) Copy(source string, parse bool) error {
if err := ensureDirectoryExists(store.path); err != nil {
return err
}
// TODO skip existing scheme managers? individual files?
return filepath.Walk(source, filepath.WalkFunc(
err := filepath.Walk(source, filepath.WalkFunc(
func(path string, info os.FileInfo, err error) error {
if path == source {
return nil
......@@ -236,4 +238,12 @@ func (store *ConfigurationStore) Copy(source string) error {
return nil
}),
)
if err != nil {
return err
}
if parse {
return store.ParseFolder()
}
return nil
}
<InvalidSchemeManager>
An invalid scheme manager. This should raise no error, since it should
never be parsed, since it should be overwritten by the corresponding file
testdata/irma_configuration/test/description.xml from the 'assets' folder.
</InvalidSchemeManager>
\ No newline at end of file
<SchemeManager version="7">
<Id>test2</Id>
<Url>https://privacybydesign.foundation</Url>
<Name>
<en>Test Scheme Manager</en>
<nl>Test scheme manager</nl>
</Name>
<Description>
<en>A test scheme manager with a scheme manager.</en>
<nl>Een test-scheme manager met een keyshare server.</nl>
</Description>
<KeyshareServer></KeyshareServer>
<KeyshareWebsite></KeyshareWebsite>
<KeyshareAttribute></KeyshareAttribute>
<Contact>https://privacybydesign.foundation/</Contact>
</SchemeManager>
<IssueSpecification version="4">
<Name>
<en>MyIRMA login</en>
<nl>MijnIRMA login</nl>
</Name>
<ShortName>
<en>MyIRMA</en>
<nl>MijnIRMA</nl>
</ShortName>
<SchemeManager>test2</SchemeManager>
<IssuerID>test</IssuerID>
<CredentialID>mijnirma</CredentialID>
<Description>
<en>Your MyIRMA login credential</en>
<nl>Uw MijnIRMA login credential</nl>
</Description>
<ShouldBeSingleton>true</ShouldBeSingleton>
<Attributes>
<Attribute id="email">
<Name>
<en>Email address</en>
<nl>E-mailadres</nl>
</Name>
<Description>
<en>Your verified email address</en>
<nl>Uw geverifiëerde e-mailadres</nl>
</Description>
</Attribute>
</Attributes>
</IssueSpecification>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<IssuerPrivateKey xmlns="http://www.zurich.ibm.com/security/idemix" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zurich.ibm.com/security/idemix IssuerPrivateKey.xsd">
<Counter>0</Counter>
<ExpiryDate>1491436800</ExpiryDate>
<References>
<IssuerPublicKey>http://www.irmacard.org/credentials/phase1/MijnOverheid/ipk.xml</IssuerPublicKey>
</References>
<Elements>
<n>96063359353814070257464989369098573470645843347358957127875426328487326540633303185702306359400766259130239226832166456957259123554826741975265634464478609571816663003684533868318795865194004795637221226902067194633407757767792795252414073029114153019362701793292862118990912516058858923030408920700061749321</n>
<p>10436034022637868273483137633548989700482895839559909621411910579140541345632481969613724849214412062500244238926015929148144084368427474551770487566048119</p>
<pPrime>5218017011318934136741568816774494850241447919779954810705955289570270672816240984806862424607206031250122119463007964574072042184213737275885243783024059</pPrime>
<q>9204968012315139729618449685392284928468933831570080795536662422367142181432679739143882888540883909887054345986640656981843559062844656131133512640733759</q>
<qPrime>4602484006157569864809224842696142464234466915785040397768331211183571090716339869571941444270441954943527172993320328490921779531422328065566756320366879</qPrime>
</Elements>
</IssuerPrivateKey>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<IssuerPublicKey xmlns="http://www.zurich.ibm.com/security/idemix" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zurich.ibm.com/security/idemix IssuerPublicKey.xsd">
<Counter>0</Counter>
<ExpiryDate>1491436800</ExpiryDate>
<References>
<GroupParameters>http://www.irmacard.org/credentials/phase1/MijnOverheid/gp.xml</GroupParameters>
</References>
<Elements>
<S>68460510129747727135744503403370273952956360997532594630007762045745171031173231339034881007977792852962667675924510408558639859602742661846943843432940752427075903037429735029814040501385798095836297700111333573975220392538916785564158079116348699773855815825029476864341585033111676283214405517983188761136</S>
<Z>44579327840225837958738167571392618381868336415293109834301264408385784355849790902532728798897199236650711385876328647206143271336410651651791998475869027595051047904885044274040212624547595999947339956165755500019260290516022753290814461070607850420459840370288988976468437318992206695361417725670417150636</Z>
<n>96063359353814070257464989369098573470645843347358957127875426328487326540633303185702306359400766259130239226832166456957259123554826741975265634464478609571816663003684533868318795865194004795637221226902067194633407757767792795252414073029114153019362701793292862118990912516058858923030408920700061749321</n>
<Bases num="6">
<Base_0>75350858539899247205099195870657569095662997908054835686827949842616918065279527697469302927032348256512990413925385972530386004430200361722733856287145745926519366823425418198189091190950415327471076288381822950611094023093577973125683837586451857056904547886289627214081538422503416179373023552964235386251</Base_0>
<Base_1>16493273636283143082718769278943934592373185321248797185217530224336539646051357956879850630049668377952487166494198481474513387080523771033539152347804895674103957881435528189990601782516572803731501616717599698546778915053348741763191226960285553875185038507959763576845070849066881303186850782357485430766</Base_1>
<Base_2>13291821743359694134120958420057403279203178581231329375341327975072292378295782785938004910295078955941500173834360776477803543971319031484244018438746973179992753654070994560440903251579649890648424366061116003693414594252721504213975050604848134539324290387019471337306533127861703270017452296444985692840</Base_2>
<Base_3>86332479314886130384736453625287798589955409703988059270766965934046079318379171635950761546707334446554224830120982622431968575935564538920183267389540869023066259053290969633312602549379541830869908306681500988364676409365226731817777230916908909465129739617379202974851959354453994729819170838277127986187</Base_3>
<Base_4>68324072803453545276056785581824677993048307928855083683600441649711633245772441948750253858697288489650767258385115035336890900077233825843691912005645623751469455288422721175655533702255940160761555155932357171848703103682096382578327888079229101354304202688749783292577993444026613580092677609916964914513</Base_4>
<Base_5>65082646756773276491139955747051924146096222587013375084161255582716233287172212541454173762000144048198663356249316446342046266181487801411025319914616581971563024493732489885161913779988624732795125008562587549337253757085766106881836850538709151996387829026336509064994632876911986826959512297657067426387</Base_5>
</Bases>
</Elements>
<Features>
<Epoch length="432000"/>
</Features>
</IssuerPublicKey>
<Issuer version="4">
<ID>test</ID>
<ShortName>
<en>PbD.f</en>
<nl>PbD.f</nl>
</ShortName>
<Name>
<en>Privacy by Design Foundation</en>
<nl>Stichting Privacy by Design</nl>
</Name>
<SchemeManager>test2</SchemeManager>
<ContactAddress></ContactAddress>
<ContactEMail>info@privacybydesign.foundation</ContactEMail>
<baseURL></baseURL>
</Issuer>
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