-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathecdsa_role.go
167 lines (141 loc) · 3.4 KB
/
ecdsa_role.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
package jwt
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
JWT "github.com/dgrijalva/jwt-go"
)
var _ Role = (*ECDSARole)(nil)
type ECDSARole struct {
RoleName string `json:"name"`
Key ecdsaKey `json:"key"`
SignMethod string `json:"alg"`
JWTClaims JWT.MapClaims `json:"claims"`
}
func newECDSARole(roleName string, alg string, claims JWT.MapClaims, rawKey []byte) (Role, error) {
var key *ecdsa.PrivateKey
if rawKey != nil {
// Key is specified, use it
rkey, err := parseECDSAKey(rawKey)
if err != nil {
return nil, fmt.Errorf("failed to parse ECDSA key: %w", err)
}
key = rkey
} else {
// Key isn't specified - generate one
var curve elliptic.Curve
switch alg {
case JWT.SigningMethodES256.Alg():
curve = elliptic.P256()
case JWT.SigningMethodES384.Alg():
curve = elliptic.P384()
case JWT.SigningMethodES512.Alg():
curve = elliptic.P521()
default:
return nil, fmt.Errorf("unable to generate ECDSA key: unsupported curve type")
}
rkey, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, fmt.Errorf("failed to generate RSA key: %w", err)
}
key = rkey
}
role := &ECDSARole{
RoleName: roleName,
Key: ecdsaKey{key},
SignMethod: alg,
JWTClaims: claims,
}
return role, nil
}
func ecdsaRole() Role {
return &ECDSARole{}
}
func (r *ECDSARole) SetClaims(claims JWT.MapClaims) error {
r.JWTClaims = claims
return nil
}
func (r *ECDSARole) Name() string {
return r.RoleName
}
func (r *ECDSARole) Claims() JWT.MapClaims {
return r.JWTClaims
}
func (r *ECDSARole) SigningMethod() string {
return r.SignMethod
}
func (r *ECDSARole) KeyString() string {
marshalled, err := x509.MarshalPKIXPublicKey(&r.Key.PublicKey)
if err != nil {
// TODO: Logging
return "<unable to get public key>"
}
block := &pem.Block{
Type: "EC PUBLIC KEY",
Bytes: marshalled,
}
b := pem.EncodeToMemory(block)
return string(b)
}
func (r *ECDSARole) SigningKey() interface{} {
return r.Key.PrivateKey
}
func (r *ECDSARole) Validate() JWT.Keyfunc {
return func(t *JWT.Token) (interface{}, error) {
return r.Key.Public(), nil
}
}
type ecdsaKey struct {
*ecdsa.PrivateKey
}
func (k ecdsaKey) MarshalJSON() ([]byte, error) {
bts, err := x509.MarshalPKCS8PrivateKey(k.PrivateKey)
if err != nil {
return nil, fmt.Errorf("unable to marshal key: %w", err)
}
block := &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: bts,
}
b := pem.EncodeToMemory(block)
enc, err := json.Marshal(string(b))
if err != nil {
return nil, err
}
return enc, nil
}
func (k *ecdsaKey) UnmarshalJSON(b []byte) error {
var str string
err := json.Unmarshal(b, &str)
if err != nil {
return fmt.Errorf("failed to unmarshal key: %w", err)
}
key, err := parseECDSAKey([]byte(str))
if err != nil {
return err
}
k.PrivateKey = key
return nil
}
func parseECDSAKey(b []byte) (*ecdsa.PrivateKey, error) {
block, _ := pem.Decode(b)
if block == nil {
return nil, fmt.Errorf("invalid pem block")
}
if block.Type != "EC PRIVATE KEY" {
return nil, fmt.Errorf("pem block is not 'EC PRIVATE KEY'")
}
rawKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse private key: %w", err)
}
key, ok := rawKey.(*ecdsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("invalid private key in storage: is a %T", rawKey)
}
return key, nil
}