forked from pascaldekloe/jwt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sign.go
159 lines (137 loc) · 4.02 KB
/
sign.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
package jwt
import (
"crypto"
"crypto/ecdsa"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"hash"
"strconv"
)
// ECDSASign calls Sync and returns a new JWT.
// When the algorithm is not in ECDSAAlgs, then the error is ErrAlgUnk.
// The caller must use the correct key for the respective algorithm (P-256 for
// ES256, P-384 for ES384 and P-521 for ES512) or risk malformed token production.
func (c *Claims) ECDSASign(alg string, key *ecdsa.PrivateKey) (token []byte, err error) {
if err := c.Sync(); err != nil {
return nil, err
}
// signature contains pair (r, s) as per RFC 7518 section 3.4
sig := make([]byte, 2*((key.Curve.Params().BitSize+7)/8))
encSigLen := encoding.EncodedLen(len(sig))
hash := ECDSAAlgs[alg]
encHeader, err := c.formatHeader(alg, hash)
if err != nil {
return nil, err
}
digest := hash.New()
token = c.newUnsignedToken(encHeader, encSigLen, digest)
// create signature
r, s, err := ecdsa.Sign(rand.Reader, key, digest.Sum(nil))
if err != nil {
return nil, err
}
// algin right with big-endian order
rBytes, sBytes := r.Bytes(), s.Bytes()
copy(sig[(len(sig)/2)-len(rBytes):], rBytes)
copy(sig[len(sig)-len(sBytes):], sBytes)
// append signature
encoding.Encode(token[len(token)-encSigLen:], sig)
return token, nil
}
// HMACSign calls Sync and returns a new JWT.
// When the algorithm is not in HMACAlgs, then the error is ErrAlgUnk.
func (c *Claims) HMACSign(alg string, secret []byte) (token []byte, err error) {
if err := c.Sync(); err != nil {
return nil, err
}
hash := HMACAlgs[alg]
encHeader, err := c.formatHeader(alg, hash)
if err != nil {
return nil, err
}
digest := hmac.New(hash.New, secret)
encSigLen := encoding.EncodedLen(digest.Size())
token = c.newUnsignedToken(encHeader, encSigLen, digest)
// append signature
encoding.Encode(token[len(token)-encSigLen:], digest.Sum(nil))
return token, nil
}
// RSASign calls Sync and returns a new JWT.
// When the algorithm is not in RSAAlgs, then the error is ErrAlgUnk.
func (c *Claims) RSASign(alg string, key *rsa.PrivateKey) (token []byte, err error) {
if err := c.Sync(); err != nil {
return nil, err
}
hash := RSAAlgs[alg]
encHeader, err := c.formatHeader(alg, hash)
if err != nil {
return nil, err
}
digest := hash.New()
encSigLen := encoding.EncodedLen(key.Size())
token = c.newUnsignedToken(encHeader, encSigLen, digest)
// append signature
sig, err := rsa.SignPKCS1v15(rand.Reader, key, hash, digest.Sum(nil))
if err != nil {
return nil, err
}
encoding.Encode(token[len(token)-encSigLen:], sig)
return token, nil
}
func (c *Claims) newUnsignedToken(encHeader string, encSigLen int, digest hash.Hash) []byte {
encClaimsLen := encoding.EncodedLen(len(c.Raw))
token := make([]byte, len(encHeader)+encClaimsLen+encSigLen+2)
i := copy(token, encHeader)
token[i] = '.'
i++
encoding.Encode(token[i:], c.Raw)
i += encClaimsLen
token[i] = '.'
digest.Write(token[:i])
return token
}
// FormatHeader encodes the JOSE header and validates the hash.
func (c *Claims) formatHeader(alg string, hash crypto.Hash) (encHeader string, err error) {
if hash == 0 {
return "", ErrAlgUnk
}
if !hash.Available() {
return "", errHashLink
}
if kid := c.KeyID; kid != "" {
buf := make([]byte, 7, 24+len(kid))
copy(buf, `{"alg":`)
buf = strconv.AppendQuote(buf, alg)
buf = append(buf, `,"kid":`...)
buf = strconv.AppendQuote(buf, kid)
buf = append(buf, '}')
return encoding.EncodeToString(buf), nil
}
switch alg {
case ES256:
return "eyJhbGciOiJFUzI1NiJ9", nil
case ES384:
return "eyJhbGciOiJFUzM4NCJ9", nil
case ES512:
return "eyJhbGciOiJFUzUxMiJ9", nil
case HS256:
return "eyJhbGciOiJIUzI1NiJ9", nil
case HS384:
return "eyJhbGciOiJIUzM4NCJ9", nil
case HS512:
return "eyJhbGciOiJIUzUxMiJ9", nil
case RS256:
return "eyJhbGciOiJSUzI1NiJ9", nil
case RS384:
return "eyJhbGciOiJSUzM4NCJ9", nil
case RS512:
return "eyJhbGciOiJSUzUxMiJ9", nil
default:
buf := make([]byte, 7, 14)
copy(buf, `{"alg":`)
buf = strconv.AppendQuote(buf, alg)
buf = append(buf, '}')
return encoding.EncodeToString(buf), nil
}
}