1package cliutil
2
3import (
4 "crypto/ecdsa"
5 "crypto/elliptic"
6 "crypto/rand"
7 "encoding/json"
8 "fmt"
9 "os"
10 "path/filepath"
11
12 "github.com/lestrrat-go/jwx/v2/jwa"
13 "github.com/lestrrat-go/jwx/v2/jwk"
14 "github.com/whyrusleeping/go-did"
15)
16
17// LoadKeyFromFile reads the private key from file
18func LoadKeyFromFile(kfile string) (*did.PrivKey, error) {
19 kb, err := os.ReadFile(kfile)
20 if err != nil {
21 return nil, err
22 }
23
24 sk, err := jwk.ParseKey(kb)
25 if err != nil {
26 return nil, err
27 }
28
29 var spk ecdsa.PrivateKey
30 if err := sk.Raw(&spk); err != nil {
31 return nil, err
32 }
33 curve, ok := sk.Get("crv")
34 if !ok {
35 return nil, fmt.Errorf("need a curve set")
36 }
37
38 var out string
39 kts := string(curve.(jwa.EllipticCurveAlgorithm))
40 switch kts {
41 case "P-256":
42 out = did.KeyTypeP256
43 default:
44 return nil, fmt.Errorf("unrecognized key type: %s", kts)
45 }
46
47 return &did.PrivKey{
48 Raw: &spk,
49 Type: out,
50 }, nil
51}
52
53// GenerateKeyToFile makes the private key and store it into the file
54func GenerateKeyToFile(fname string) error {
55 raw, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
56 if err != nil {
57 return fmt.Errorf("failed to generate new ECDSA private key: %s", err)
58 }
59
60 key, err := jwk.FromRaw(raw)
61 if err != nil {
62 return fmt.Errorf("failed to create ECDSA key: %s", err)
63 }
64
65 if _, ok := key.(jwk.ECDSAPrivateKey); !ok {
66 return fmt.Errorf("expected jwk.ECDSAPrivateKey, got %T", key)
67 }
68
69 key.Set(jwk.KeyIDKey, "mykey")
70
71 buf, err := json.MarshalIndent(key, "", " ")
72 if err != nil {
73 return fmt.Errorf("failed to marshal key into JSON: %w", err)
74 }
75
76 // ensure data directory exists; won't error if it does
77 os.MkdirAll(filepath.Dir(fname), os.ModePerm)
78
79 return os.WriteFile(fname, buf, 0664)
80}