/
keyreq.go
193 lines (171 loc) · 4.63 KB
/
keyreq.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package csrprov
import (
"crypto"
"crypto/elliptic"
"crypto/x509"
"github.com/go-phorce/dolly/xpki/cryptoprov"
"github.com/juju/errors"
)
const (
// CurveP256 specifies curve P-256 for ESDCA
CurveP256 = 256
// CurveP384 specifies curve P-384 for ESDCA
CurveP384 = 384
// CurveP521 specifies curve P-521 for ESDCA
CurveP521 = 521
)
// KeyPurpose declares the purpose for keys
type KeyPurpose int
const (
// Undefined purpose of key
Undefined KeyPurpose = 0
// Signing specifies the purpose of key to be used in signing/verification operations
Signing KeyPurpose = 1
// Encryption specifies the purpose of key to be used in encryption/decryption operations
Encryption KeyPurpose = 2
)
// KeyRequest contains the algorithm and key size for a new private key.
type KeyRequest interface {
Algo() string
Label() string
Size() int
Generate() (crypto.PrivateKey, error)
SigAlgo() x509.SignatureAlgorithm
Purpose() int
}
// keyRequest contains the algorithm and key size for a new private key.
type keyRequest struct {
L string `json:"label"`
A string `json:"algo"`
S int `json:"size"`
P KeyPurpose `json:"purpose"`
prov cryptoprov.Provider
}
// Label returns the requested key label.
func (kr *keyRequest) Label() string {
return kr.L
}
// Algo returns the requested key algorithm represented as a string.
func (kr *keyRequest) Algo() string {
return kr.A
}
// Size returns the requested key size.
func (kr *keyRequest) Size() int {
return kr.S
}
// Purpose returns the purpose of the key .
func (kr *keyRequest) Purpose() int {
return int(kr.P)
}
// SigAlgo returns an appropriate X.509 signature algorithm given the
// key request's type and size.
func (kr *keyRequest) SigAlgo() x509.SignatureAlgorithm {
return SigAlgo(kr.Algo(), kr.Size())
}
// Generate generates a key as specified in the request. Currently,
// only ECDSA and RSA are supported.
func (kr *keyRequest) Generate() (crypto.PrivateKey, error) {
switch algo := kr.Algo(); algo {
case "rsa", "RSA":
err := validateRSAKeyPairInfoHandler(kr.Size())
if err != nil {
return nil, errors.Annotate(err, "validate RSA key")
}
pk, err := kr.prov.GenerateRSAKey(kr.Label(), kr.Size(), kr.Purpose())
if err != nil {
return nil, errors.Annotate(err, "generate RSA key")
}
return pk, nil
case "ecdsa", "ECDSA":
err := validateECDSAKeyPairCurveInfoHandler(kr.Size())
if err != nil {
return nil, errors.Annotate(err, "validate ECDSA key")
}
var curve elliptic.Curve
switch kr.Size() {
case CurveP256:
curve = elliptic.P256()
case CurveP384:
curve = elliptic.P384()
case CurveP521:
curve = elliptic.P521()
default:
return nil, errors.New("invalid curve")
}
pk, err := kr.prov.GenerateECDSAKey(kr.Label(), curve)
if err != nil {
return nil, errors.Annotate(err, "generate ECDSA key")
}
return pk, nil
default:
return nil, errors.Errorf("invalid algorithm: %s", algo)
}
}
// NewKeyRequest returns KeyRequest from given parameters
func (c *Provider) NewKeyRequest(label, algo string, keySize int, purpose KeyPurpose) KeyRequest {
return &keyRequest{
L: label,
A: algo,
S: keySize,
P: purpose,
prov: c.provider,
}
}
// NewKeyRequest returns KeyRequest from given parameters
func NewKeyRequest(prov cryptoprov.Provider, label, algo string, keySize int, purpose KeyPurpose) KeyRequest {
return &keyRequest{
L: label,
A: algo,
S: keySize,
P: purpose,
prov: prov,
}
}
// validateRSAKeyPairInfoHandler validates size of the RSA key
func validateRSAKeyPairInfoHandler(size int) error {
if size < 2048 {
return errors.Errorf("RSA key is too weak: %d", size)
}
if size > 8192 {
return errors.Errorf("RSA key size too large: %d", size)
}
return nil
}
// validateECDSAKeyPairCurveInfoHandler validates size of the ECDSA key
func validateECDSAKeyPairCurveInfoHandler(size int) error {
switch size {
case CurveP256, CurveP384, CurveP521:
return nil
}
return errors.Errorf("invalid curve size: %d", size)
}
// SigAlgo returns signature algorithm for the given algorithm name and key size
// TODO: use oid pkg
func SigAlgo(algo string, size int) x509.SignatureAlgorithm {
switch algo {
case "rsa", "RSA":
switch {
case size >= 4096:
return x509.SHA512WithRSA
case size >= 3072:
return x509.SHA384WithRSA
case size >= 2048:
return x509.SHA256WithRSA
default:
return x509.SHA1WithRSA
}
case "ecdsa", "ECDSA":
switch size {
case CurveP521:
return x509.ECDSAWithSHA512
case CurveP384:
return x509.ECDSAWithSHA384
case CurveP256:
return x509.ECDSAWithSHA256
default:
return x509.ECDSAWithSHA1
}
default:
return x509.UnknownSignatureAlgorithm
}
}