-
Notifications
You must be signed in to change notification settings - Fork 0
/
kms.go
136 lines (118 loc) · 3.61 KB
/
kms.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
package kms
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"io/ioutil"
"net"
"time"
vkms "github.com/axieinfinity/ronin-kms-client/message"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
//go:generate protoc --go_out=message --go-grpc_out=message message/message.proto
const SuccessCode = 1
var ErrAccessDenied = errors.New("KMS VM access denied")
type KmsSign struct {
Connection *grpc.ClientConn
KeyToken []byte
Address common.Address
SignTimeout int64
}
type KmsConfig struct {
KeyTokenPath string `json:"keyTokenPath"`
SslCertPath string `json:"sslCertPath"`
KmsServerAddr string `json:"kmsServerAddr"`
KmsSourceAddr string `json:"kmsSourceAddr"`
SignTimeout int64 `json:"signTimeout"`
}
func NewKmsSign(kmsConfig *KmsConfig) (*KmsSign, error) {
keyToken, err := ioutil.ReadFile(kmsConfig.KeyTokenPath)
if err != nil {
log.Error("[KMS] Failed to read token key file", "error", err)
return nil, err
}
sslCert, err := ioutil.ReadFile(kmsConfig.SslCertPath)
if err != nil {
log.Error("[KMS] Failed to read SSL certificate file", "error", err)
return nil, err
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(sslCert)
tlsCfg := &tls.Config{RootCAs: certPool, InsecureSkipVerify: true}
sourceAddr, err := net.ResolveTCPAddr("tcp", kmsConfig.KmsSourceAddr)
if err != nil {
log.Error("[KMS] Failed to resolve source address", "error", err)
return nil, err
}
dialer := net.Dialer{
LocalAddr: sourceAddr,
}
conn, err := grpc.Dial(kmsConfig.KmsServerAddr,
grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg)),
grpc.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) {
return dialer.DialContext(ctx, "tcp", s)
}),
)
if err != nil {
log.Error("[KMS] Failed to dial to KMS VM", "error", err)
return nil, err
}
client := vkms.NewUserClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(kmsConfig.SignTimeout*int64(time.Millisecond)))
defer cancel()
resp, err := client.Sign(
metadata.AppendToOutgoingContext(ctx, "vkms_data_type", "non-ether"),
&vkms.SignRequest{
KeyUsageToken: keyToken,
Data: []byte{},
},
)
if err != nil {
log.Error("[KMS] Failed to request signing", "error", err)
return nil, err
}
if resp.Code != SuccessCode {
log.Error("[KMS] KMS VM access denied")
return nil, err
}
publicKey, err := crypto.SigToPub(crypto.Keccak256([]byte{}), resp.Signature)
if err != nil {
log.Error("[KMS] Failed to get KMS public key")
return nil, err
}
address := crypto.PubkeyToAddress(*publicKey)
log.Info("[KMS] Siging account", "address", address)
return &KmsSign{
Connection: conn,
KeyToken: keyToken,
Address: address,
SignTimeout: kmsConfig.SignTimeout,
}, nil
}
// Sign function receives raw message, not hash of message
func (kmsSign *KmsSign) Sign(message []byte, dataType string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(kmsSign.SignTimeout*int64(time.Millisecond)))
defer cancel()
resp, err := vkms.NewUserClient(kmsSign.Connection).Sign(
metadata.AppendToOutgoingContext(ctx, "vkms_data_type", dataType),
&vkms.SignRequest{
KeyUsageToken: kmsSign.KeyToken,
Data: message,
},
)
if err != nil {
log.Error("[KMS] Failed to request signing", "error", err)
return nil, err
}
if resp.Code != SuccessCode {
log.Error("[KMS] KMS VM access denied")
return nil, ErrAccessDenied
}
return resp.Signature, nil
}