forked from mutecomm/mute
-
Notifications
You must be signed in to change notification settings - Fork 0
/
impl.go
163 lines (150 loc) · 4.73 KB
/
impl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package keylookup implements key lookup calls.
package keylookup
import (
"encoding/base64"
"encoding/hex"
"errors"
"strings"
"github.com/agl/ed25519"
"github.com/mutecomm/mute/serviceguard/common/constants"
"github.com/mutecomm/mute/serviceguard/common/keypool"
"github.com/mutecomm/mute/serviceguard/common/signkeys"
"github.com/mutecomm/mute/util/jsonclient"
)
var (
// ErrBadSigner is returned if a verification pubkey list was signed by the wrong signer
ErrBadSigner = errors.New("keylookup: bad signer")
// ErrParams is returned if a call returned bad parameters
ErrParams = errors.New("keylookup: bad RPC parameters")
// ErrBadSignature signals that a packet signature did not verify
ErrBadSignature = errors.New("keylookup: bad signature")
)
// DefaultClientFactory is the default factory for new clients
var DefaultClientFactory = jsonclient.New
// ServiceURL is the default URL for the keylookup service
var ServiceURL = constants.KeyLookupURL
// LookupClient implements a key lookup client
type LookupClient struct {
KeyPool *keypool.KeyPool
ClientFactory func(string, []byte) (*jsonclient.URLClient, error)
ServiceGuardCA []byte // The CA of the serviceguard, if any
PubKey *[ed25519.PublicKeySize]byte
}
// New returns a new key lookup client
func New(keyPool *keypool.KeyPool, cacert []byte, pubKey *[ed25519.PublicKeySize]byte) *LookupClient {
lc := new(LookupClient)
lc.KeyPool = keyPool
lc.ServiceGuardCA = cacert
lc.ClientFactory = DefaultClientFactory
lc.PubKey = pubKey
return lc
}
// GetKey tries to lookup a key from the lookup service
func (klc LookupClient) GetKey(keyid *[signkeys.KeyIDSize]byte) (*signkeys.PublicKey, error) {
keyMarshalled, err := klc.getKey(keyid[:])
if err != nil {
return nil, err
}
loadKey, err := new(signkeys.PublicKey).Unmarshal(keyMarshalled)
if err != nil {
return nil, err
}
return loadKey, nil
}
// getKey fetches a key from lookup
func (klc LookupClient) getKey(keyid []byte) ([]byte, error) {
method := "PublicService.LookupKey"
client, err := klc.ClientFactory(ServiceURL, klc.ServiceGuardCA)
if err != nil {
return nil, err
}
data, err := client.JSONRPCRequest(method, struct{ KeyID string }{KeyID: hex.EncodeToString(keyid)})
if err != nil {
return nil, err
}
if _, ok := data["Key"]; ok {
keyMarshalled, err := base64.StdEncoding.DecodeString(data["Key"].(string))
if err != nil {
return nil, err
}
return keyMarshalled, nil
}
return nil, ErrParams
}
// RegisterStorage adds the lookup client to the keypool storage to accomplish automatic fetches. This should be
// used with great care since it locks the keypool during fetch (which can be many minutes).
func (klc *LookupClient) RegisterStorage() {
fetchfunc := func(keyid []byte) (marshalledKey []byte, err error) {
marshalledKey, err = klc.getKey(keyid)
if err != nil {
return
}
loadKey, err := new(signkeys.PublicKey).Unmarshal(marshalledKey)
if err != nil {
return nil, err
}
keyidX, err := klc.KeyPool.LoadKeyUnsafe(loadKey)
if err != nil && err != keypool.ErrExists {
return nil, err
}
klc.KeyPool.SaveKeyUnsafe(*keyidX)
return
}
klc.KeyPool.RegisterStorage(fetchfunc, nil, nil)
}
// GetVerifyList requests a list of known issuer keys from the lookup service
func (klc LookupClient) GetVerifyList() ([][ed25519.PublicKeySize]byte, error) {
var sig [ed25519.SignatureSize]byte
var pk [ed25519.PublicKeySize]byte
method := "PublicService.VerifyKeys"
client, err := klc.ClientFactory(ServiceURL, klc.ServiceGuardCA)
if err != nil {
return nil, err
}
data, err := client.JSONRPCRequest(method, nil)
if err != nil {
return nil, err
}
if _, ok := data["PublicKey"]; !ok {
return nil, ErrParams
}
if _, ok := data["Signature"]; !ok {
return nil, ErrParams
}
if _, ok := data["KeyList"]; !ok {
return nil, ErrParams
}
pubKey, err := hex.DecodeString(data["PublicKey"].(string))
if err != nil {
return nil, ErrParams
}
copy(pk[:], pubKey)
if pk != *klc.PubKey {
return nil, ErrBadSigner
}
signature, err := hex.DecodeString(data["Signature"].(string))
if err != nil {
return nil, ErrParams
}
copy(sig[:], signature)
keylist := data["KeyList"].(string)
ok := ed25519.Verify(klc.PubKey, []byte(keylist), &sig)
if !ok {
return nil, ErrBadSignature
}
keylistSlice := strings.Split(keylist, ", ")
keylistRet := make([][ed25519.PublicKeySize]byte, 0, len(keylistSlice))
for _, keyS := range keylistSlice {
var keyA [ed25519.PublicKeySize]byte
dk, err := hex.DecodeString(keyS)
if err != nil {
return nil, err
}
copy(keyA[:], dk)
keylistRet = append(keylistRet, keyA)
}
return keylistRet, nil
}