updates.go 3.44 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
15
16
17
18
19
20
21
22
23
24
type update struct {
	When   Timestamp
	Number int
}

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

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

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

42
	bytes, err := ioutil.ReadFile(cardemuXML)
Sietse Ringers's avatar
Sietse Ringers committed
43
44
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
	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 {
85
		cm.secretkey = &secretKey{Key: list[0].Attributes[0]}
Sietse Ringers's avatar
Sietse Ringers committed
86
87
88
89
90
91
92
93
		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]
			}
94
95
96
			var cred *credential
			if cred, err = newCredential(gabicred, cm.Store); err != nil {
				return
97
			}
Sietse Ringers's avatar
Sietse Ringers committed
98
			if cred.CredentialType() == nil {
99
100
				err = errors.New("cannot add unknown credential type")
				return
Sietse Ringers's avatar
Sietse Ringers committed
101
102
			}

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

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

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

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

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