updates.go 3.51 KB
Newer Older
Sietse Ringers's avatar
Sietse Ringers committed
1
2
3
4
5
6
7
8
9
package irmago

import (
	"encoding/json"
	"encoding/xml"
	"html"
	"io/ioutil"
	"math/big"

Sietse Ringers's avatar
Sietse Ringers committed
10
	"github.com/go-errors/errors"
Sietse Ringers's avatar
Sietse Ringers committed
11
12
13
	"github.com/mhe/gabi"
)

14
type update struct {
15
16
17
18
	When    Timestamp
	Number  int
	Success bool
	Error   *string
19
20
21
22
23
24
25
26
}

var credentialManagerUpdates = []func(manager *CredentialManager) error{
	func(manager *CredentialManager) error {
		_, err := manager.ParseAndroidStorage()
		return err
	},
}
27

Sietse Ringers's avatar
Sietse Ringers committed
28
29
30
31
// 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.
32
func (cm *CredentialManager) ParseAndroidStorage() (present bool, err error) {
33
34
35
36
37
	if cm.androidStoragePath == "" {
		return false, nil
	}

	cardemuXML := cm.androidStoragePath + "/shared_prefs/cardemu.xml"
38
39
	present, err = PathExists(cardemuXML)
	if err != nil || !present {
Sietse Ringers's avatar
Sietse Ringers committed
40
41
		return
	}
42
	present = true
Sietse Ringers's avatar
Sietse Ringers committed
43

44
	bytes, err := ioutil.ReadFile(cardemuXML)
Sietse Ringers's avatar
Sietse Ringers committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
	if err != nil {
		return
	}
	parsedxml := struct {
		Strings []struct {
			Name    string `xml:"name,attr"`
			Content string `xml:",chardata"`
		} `xml:"string"`
	}{}
	xml.Unmarshal(bytes, &parsedxml)

	parsedjson := make(map[string][]*struct {
		Signature    *gabi.CLSignature `json:"signature"`
		Pk           *gabi.PublicKey   `json:"-"`
		Attributes   []*big.Int        `json:"attributes"`
		SharedPoints []*big.Int        `json:"public_sks"`
	})
	cm.keyshareServers = make(map[SchemeManagerIdentifier]*keyshareServer)
	for _, xmltag := range parsedxml.Strings {
		if xmltag.Name == "credentials" {
			jsontag := html.UnescapeString(xmltag.Content)
			if err = json.Unmarshal([]byte(jsontag), &parsedjson); err != nil {
				return
			}
		}
		if xmltag.Name == "keyshare" {
			jsontag := html.UnescapeString(xmltag.Content)
			if err = json.Unmarshal([]byte(jsontag), &cm.keyshareServers); err != nil {
				return
			}
		}
		if xmltag.Name == "KeyshareKeypairs" {
			jsontag := html.UnescapeString(xmltag.Content)
			keys := make([]*paillierPrivateKey, 0, 3)
			if err = json.Unmarshal([]byte(jsontag), &keys); err != nil {
				return
			}
			cm.paillierKeyCache = keys[0]
		}
	}

	for _, list := range parsedjson {
87
		cm.secretkey = &secretKey{Key: list[0].Attributes[0]}
Sietse Ringers's avatar
Sietse Ringers committed
88
89
90
91
92
93
94
95
		for _, oldcred := range list {
			gabicred := &gabi.Credential{
				Attributes: oldcred.Attributes,
				Signature:  oldcred.Signature,
			}
			if oldcred.SharedPoints != nil && len(oldcred.SharedPoints) > 0 {
				gabicred.Signature.KeyshareP = oldcred.SharedPoints[0]
			}
96
			var cred *credential
97
			if cred, err = newCredential(gabicred, cm.ConfigurationStore); err != nil {
98
				return
99
			}
Sietse Ringers's avatar
Sietse Ringers committed
100
			if cred.CredentialType() == nil {
101
102
				err = errors.New("cannot add unknown credential type")
				return
Sietse Ringers's avatar
Sietse Ringers committed
103
104
			}

105
106
			if err = cm.addCredential(cred, false); err != nil {
				return
Sietse Ringers's avatar
Sietse Ringers committed
107
108
109
110
111
			}
		}
	}

	if len(cm.credentials) > 0 {
112
113
		if err = cm.storeAttributes(); err != nil {
			return
Sietse Ringers's avatar
Sietse Ringers committed
114
		}
115
116
		if err = cm.storeSecretKey(cm.secretkey); err != nil {
			return
Sietse Ringers's avatar
Sietse Ringers committed
117
118
119
120
		}
	}

	if len(cm.keyshareServers) > 0 {
121
122
		if err = cm.storeKeyshareServers(); err != nil {
			return
Sietse Ringers's avatar
Sietse Ringers committed
123
124
125
		}
	}

126
127
	if err = cm.storePaillierKeys(); err != nil {
		return
Sietse Ringers's avatar
Sietse Ringers committed
128
129
130
131
132
	}
	if cm.paillierKeyCache == nil {
		cm.paillierKey(false) // trigger calculating a new one
	}

133
	if err = cm.ConfigurationStore.Copy(cm.androidStoragePath+"/app_store/irma_configuration", false); err != nil {
134
135
136
		return
	}
	// Copy from assets again to ensure we have the latest versions
137
	return present, cm.ConfigurationStore.Copy(cm.irmaConfigurationPath, true)
Sietse Ringers's avatar
Sietse Ringers committed
138
}