@@ -6,14 +6,19 @@ import (
66 "crypto/ecdsa"
77 "crypto/ed25519"
88 "crypto/rand"
9+ "encoding/json"
910 "fmt"
1011 "maps"
1112 "time"
1213
14+ gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore"
1315 "golang.org/x/crypto/curve25519"
16+ "google.golang.org/protobuf/proto"
1417
1518 "github.com/ethereum/go-ethereum/crypto"
19+
1620 "github.com/smartcontractkit/chainlink-common/keystore/internal"
21+ "github.com/smartcontractkit/chainlink-common/keystore/serialization"
1722)
1823
1924var (
@@ -52,8 +57,8 @@ type ImportKeysRequest struct {
5257
5358type ImportKeyRequest struct {
5459 KeyName string
55- KeyType KeyType
5660 Data []byte
61+ Enc EncryptionParams
5762}
5863
5964type ImportKeysResponse struct {}
@@ -227,12 +232,91 @@ func (k *keystore) DeleteKeys(ctx context.Context, req DeleteKeysRequest) (Delet
227232 return DeleteKeysResponse {}, nil
228233}
229234
230- func (k * keystore ) ImportKeys (ctx context.Context , req ImportKeysRequest ) (ImportKeysResponse , error ) {
235+ func (ks * keystore ) ImportKeys (ctx context.Context , req ImportKeysRequest ) (ImportKeysResponse , error ) {
236+ ks .mu .Lock ()
237+ defer ks .mu .Unlock ()
238+
239+ ksCopy := maps .Clone (ks .keystore )
240+ for _ , keyReq := range req .Keys {
241+ if err := ValidKeyName (keyReq .KeyName ); err != nil {
242+ return ImportKeysResponse {}, fmt .Errorf ("%w: %s" , ErrInvalidKeyName , err )
243+ }
244+ if _ , ok := ksCopy [keyReq .KeyName ]; ok {
245+ return ImportKeysResponse {}, fmt .Errorf ("%w: %s" , ErrKeyAlreadyExists , keyReq .KeyName )
246+ }
247+ if err := ValidKeyName (keyReq .KeyName ); err != nil {
248+ return ImportKeysResponse {}, fmt .Errorf ("%w: %s" , ErrInvalidKeyName , err )
249+ }
250+ encData := gethkeystore.CryptoJSON {}
251+ err := json .Unmarshal (keyReq .Data , & encData )
252+ if err != nil {
253+ return ImportKeysResponse {}, fmt .Errorf ("key = %s, failed to unmarshal encrypted import data: %w" , keyReq .KeyName , err )
254+ }
255+ decData , err := gethkeystore .DecryptDataV3 (encData , keyReq .Enc .Password )
256+ if err != nil {
257+ return ImportKeysResponse {}, fmt .Errorf ("key = %s, failed to decrypt key: %w" , keyReq .KeyName , err )
258+ }
259+ keypb := & serialization.Key {}
260+ err = proto .Unmarshal (decData , keypb )
261+ if err != nil {
262+ return ImportKeysResponse {}, fmt .Errorf ("key = %s, failed to unmarshal key: %w" , keyReq .KeyName , err )
263+ }
264+ pkRaw := internal .NewRaw (keypb .PrivateKey )
265+ keyType := KeyType (keypb .KeyType )
266+ publicKey , err := publicKeyFromPrivateKey (pkRaw , keyType )
267+ if err != nil {
268+ return ImportKeysResponse {}, fmt .Errorf ("key = %s, failed to get public key from private key: %w" , keyReq .KeyName , err )
269+ }
270+ metadata := keypb .Metadata
271+ if metadata == nil {
272+ metadata = []byte {}
273+ }
274+ ksCopy [keyReq .KeyName ] = newKey (keyType , pkRaw , publicKey , time .Unix (keypb .CreatedAt , 0 ), metadata )
275+ }
276+ // Persist it to storage.
277+ if err := ks .save (ctx , ksCopy ); err != nil {
278+ return ImportKeysResponse {}, fmt .Errorf ("failed to save keystore: %w" , err )
279+ }
280+ // If we succeed to save, update the in memory keystore.
281+ ks .keystore = ksCopy
231282 return ImportKeysResponse {}, nil
232283}
233284
234- func (k * keystore ) ExportKeys (ctx context.Context , req ExportKeysRequest ) (ExportKeysResponse , error ) {
235- return ExportKeysResponse {}, nil
285+ func (ks * keystore ) ExportKeys (_ context.Context , req ExportKeysRequest ) (ExportKeysResponse , error ) {
286+ ks .mu .Lock ()
287+ defer ks .mu .Unlock ()
288+
289+ result := ExportKeysResponse {}
290+ for _ , keyReq := range req .Keys {
291+ if key , ok := ks .keystore [keyReq .KeyName ]; ! ok {
292+ return ExportKeysResponse {}, fmt .Errorf ("%w: %s" , ErrKeyNotFound , keyReq .KeyName )
293+ } else {
294+ keypb := & serialization.Key {
295+ Name : keyReq .KeyName ,
296+ KeyType : string (key .keyType ),
297+ PrivateKey : internal .Bytes (key .privateKey ),
298+ CreatedAt : key .createdAt .Unix (),
299+ Metadata : key .metadata ,
300+ }
301+ serialized , err := proto .Marshal (keypb )
302+ if err != nil {
303+ return ExportKeysResponse {}, fmt .Errorf ("key = %s, failed to marshal key: %w" , keyReq .KeyName , err )
304+ }
305+ encData , err := gethkeystore .EncryptDataV3 (serialized , []byte (keyReq .Enc .Password ), keyReq .Enc .ScryptParams .N , keyReq .Enc .ScryptParams .P )
306+ if err != nil {
307+ return ExportKeysResponse {}, fmt .Errorf ("key = %s, failed to encrypt key: %w" , keyReq .KeyName , err )
308+ }
309+ encDataBytes , err := json .Marshal (encData )
310+ if err != nil {
311+ return ExportKeysResponse {}, fmt .Errorf ("key = %s, failed to marshal encrypted key: %w" , keyReq .KeyName , err )
312+ }
313+ result .Keys = append (result .Keys , ExportKeyResponse {
314+ KeyName : keyReq .KeyName ,
315+ Data : encDataBytes ,
316+ })
317+ }
318+ }
319+ return result , nil
236320}
237321
238322func (ks * keystore ) SetMetadata (ctx context.Context , req SetMetadataRequest ) (SetMetadataResponse , error ) {
0 commit comments