-
Notifications
You must be signed in to change notification settings - Fork 1
/
genkey.go
128 lines (109 loc) · 2.75 KB
/
genkey.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
package hsm
import (
"fmt"
"strings"
"time"
"github.com/go-phorce/dolly/fileutil"
cfsslcli "github.com/cloudflare/cfssl/cli"
"github.com/go-phorce/dolly/algorithms/guid"
"github.com/go-phorce/dolly/cmd/dollypki/cli"
"github.com/go-phorce/dolly/ctl"
"github.com/go-phorce/dolly/xpki/csrprov"
"github.com/juju/errors"
)
// GenKeyFlags specifies flags for GenKey command
type GenKeyFlags struct {
// Algo specifies algorithm
Algo *string
// Size specifies key size in bits
Size *int
// Purpose
Purpose *string
// Label specifies name for generated key
Label *string
// Output specifies the prefix for generated key
// if not set, the output will be printed to STDOUT only
Output *string
// Force to override key file if exists
Force *bool
}
func ensureGenKeyFlags(f *GenKeyFlags) *GenKeyFlags {
var (
emptyString = ""
intVal = 0
falseVal = false
)
if f.Size == nil {
f.Size = &intVal
}
if f.Algo == nil {
f.Algo = &emptyString
}
if f.Label == nil {
f.Label = &emptyString
}
if f.Purpose == nil {
f.Purpose = &emptyString
}
if f.Output == nil {
f.Output = &emptyString
}
if f.Force == nil {
f.Force = &falseVal
}
return f
}
// GenKey generates a key
func GenKey(c ctl.Control, p interface{}) error {
flags := ensureGenKeyFlags(p.(*GenKeyFlags))
cryptoprov := c.(*cli.Cli).CryptoProv()
if !*flags.Force && *flags.Output != "" && fileutil.FileExists(*flags.Output) == nil {
return errors.Errorf("%q file exists, specify --force flag to override", *flags.Output)
}
crypto := cryptoprov.Default()
csr := csrprov.New(cryptoprov.Default())
purpose := csrprov.Signing
switch *flags.Purpose {
case "s", "sign", "signing":
purpose = csrprov.Signing
case "e", "encrypt", "encryption":
purpose = csrprov.Encryption
default:
return errors.Errorf("unsupported purpose: %q", *flags.Purpose)
}
req := csr.NewKeyRequest(prefixKeyLabel(*flags.Label), *flags.Algo, *flags.Size, purpose)
prv, err := req.Generate()
if err != nil {
return errors.Trace(err)
}
keyID, _, err := crypto.IdentifyKey(prv)
if err != nil {
return errors.Trace(err)
}
uri, key, err := crypto.ExportKey(keyID)
if err != nil {
return errors.Trace(err)
}
if key == nil {
key = []byte(uri)
}
if *flags.Output == "" {
cfsslcli.PrintCert(key, nil, nil)
} else {
err = cli.WriteFile(*flags.Output, key, 0600)
if err != nil {
return errors.Trace(err)
}
}
return nil
}
// prefixKeyLabel adds a date prefix to label for a key
func prefixKeyLabel(label string) string {
if strings.HasSuffix(label, "*") {
g := guid.MustCreate()
t := time.Now().UTC()
label = strings.TrimSuffix(label, "*") +
fmt.Sprintf("_%04d%02d%02d%02d%02d%02d_%x", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), g[:4])
}
return label
}