-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcryptoSigningParams.go
More file actions
154 lines (129 loc) · 4.8 KB
/
Copy pathcryptoSigningParams.go
File metadata and controls
154 lines (129 loc) · 4.8 KB
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
package factory
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"os"
"github.com/klever-io/klever-go/common"
"github.com/klever-io/klever-go/core"
"github.com/klever-io/klever-go/crypto"
"github.com/klever-io/klever-go/crypto/signing"
"github.com/klever-io/klever-go/tools"
"github.com/klever-io/klever-go/tools/check"
)
type cryptoSigningParamsLoader struct {
pubkeyConverter core.PubkeyConverter
skIndex int
skPemFileName string
suite crypto.Suite
skPkProviderHandler func() ([]byte, []byte, error)
isInImportMode bool
}
// NewCryptoSigningParamsLoader returns a new instance of cryptoSigningParamsLoader
func NewCryptoSigningParamsLoader(
pubkeyConverter core.PubkeyConverter,
skIndex int,
skPemFileName string,
suite crypto.Suite,
isInImportMode bool,
) (*cryptoSigningParamsLoader, error) {
if check.IfNil(pubkeyConverter) {
return nil, common.ErrNilPubkeyConverter
}
if check.IfNil(suite) {
return nil, crypto.ErrNilSuite
}
cspf := &cryptoSigningParamsLoader{
pubkeyConverter: pubkeyConverter,
skIndex: skIndex,
skPemFileName: skPemFileName,
suite: suite,
isInImportMode: isInImportMode,
}
cspf.skPkProviderHandler = cspf.getSkPk
return cspf, nil
}
// Get returns a key generator, a private key, and a public key
func (cspf *cryptoSigningParamsLoader) Get() (*CryptoParams, error) {
cryptoParams := &CryptoParams{}
cryptoParams.KeyGenerator = signing.NewKeyGenerator(cspf.suite)
if cspf.isInImportMode {
return cspf.generateCryptoParams(cryptoParams)
}
return cspf.readCryptoParams(cryptoParams)
}
func (cspf *cryptoSigningParamsLoader) readCryptoParams(cryptoParams *CryptoParams) (*CryptoParams, error) {
sk, readPk, err := cspf.skPkProviderHandler()
if err != nil {
return nil, err
}
cryptoParams.PrivateKey, err = cryptoParams.KeyGenerator.PrivateKeyFromByteArray(sk)
if err != nil {
return nil, err
}
cryptoParams.PublicKey = cryptoParams.PrivateKey.GeneratePublic()
if len(readPk) > 0 {
cryptoParams.PublicKeyBytes, err = cryptoParams.PublicKey.ToByteArray()
if err != nil {
return nil, err
}
if !bytes.Equal(cryptoParams.PublicKeyBytes, readPk) {
return nil, ErrPublicKeyMismatch
}
}
cryptoParams.PublicKeyString = cspf.pubkeyConverter.Encode(cryptoParams.PublicKeyBytes)
return cryptoParams, nil
}
func (cspf *cryptoSigningParamsLoader) generateCryptoParams(cryptoParams *CryptoParams) (*CryptoParams, error) {
log.Warn("the node is in import mode! Will generate a fresh new BLS key")
cryptoParams.PrivateKey, cryptoParams.PublicKey = cryptoParams.KeyGenerator.GeneratePair()
var err error
cryptoParams.PublicKeyBytes, err = cryptoParams.PublicKey.ToByteArray()
if err != nil {
return nil, err
}
cryptoParams.PublicKeyString = cspf.pubkeyConverter.Encode(cryptoParams.PublicKeyBytes)
return cryptoParams, nil
}
func (cspf *cryptoSigningParamsLoader) getSkPk() ([]byte, []byte, error) {
skIndex := cspf.skIndex
encodedSk, pkString, err := tools.LoadSkPkFromPemFile(cspf.skPemFileName, skIndex, os.Getenv("KEY_PASSWORD"))
if err != nil {
// Only a missing file is recoverable by generating a key. Anything else
// (corrupt pem, wrong KEY_PASSWORD, permissions) must surface here rather
// than fall through and fail later against an empty key.
if !isSkPemFileNotFound(err) {
return nil, nil, fmt.Errorf("loading validator key: %w", err)
}
keyGen := signing.NewKeyGenerator(cspf.suite)
encodedSk, pkString, err = tools.CreateWallet(cspf.skPemFileName, os.Getenv("KEY_PASSWORD"), keyGen, cspf.pubkeyConverter)
if err != nil {
return nil, nil, err
}
// Generating a key here is intentional: it lets an observer start without
// operator-provided key material. It is only a problem when the node was
// meant to run under an already-registered validator identity, which we
// cannot distinguish at this point, so say so rather than staying silent.
log.Warn("no key file found - generated a new node identity",
"file", cspf.skPemFileName,
"public key", pkString,
"note", "expected for a new observer; if this node should run as a registered validator, stop it and restore its key file")
}
skBytes, err := hex.DecodeString(string(encodedSk))
if err != nil {
return nil, nil, fmt.Errorf("%w for encoded secret key", err)
}
pkBytes, err := cspf.pubkeyConverter.Decode(pkString)
if err != nil {
return nil, nil, fmt.Errorf("%w for encoded public key %s", err, pkString)
}
return skBytes, pkBytes, nil
}
// isSkPemFileNotFound reports whether the key file is simply absent. Matched by
// type only: a substring match on the not-found text is satisfied by any error
// carrying a path that happens to contain it, which would send a corrupt key
// file down the generate-and-replace branch.
func isSkPemFileNotFound(err error) bool {
return errors.Is(err, os.ErrNotExist)
}