Skip to content

Commit 95a6717

Browse files
committed
Add EncodePublicKeyToPEM, EncodePrivateKeyToPEM helpers and Key,Keys.Configuration() method
1 parent 69a0188 commit 95a6717

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

kid_keys.go

+132
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package jwt
22

33
import (
4+
"crypto/ecdsa"
5+
"crypto/ed25519"
6+
"crypto/rsa"
7+
"crypto/x509"
48
"encoding/hex"
9+
"encoding/pem"
510
"errors"
611
"fmt"
712
"strconv"
@@ -103,6 +108,133 @@ type (
103108
}
104109
)
105110

111+
// Configuration converts a Key to a key configuration.
112+
// It will throw an error if the key includes encryption.
113+
func (key *Key) Configuration() (KeyConfiguration, error) {
114+
if key.Encrypt != nil || key.Decrypt != nil {
115+
return KeyConfiguration{}, errors.New("jwt: cannot export keys with encryption")
116+
}
117+
118+
var privatePEM, publicPEM string
119+
if key.Private != nil {
120+
text, err := EncodePrivateKeyToPEM(key.Private)
121+
if err != nil {
122+
return KeyConfiguration{}, fmt.Errorf("jwt: %w", err)
123+
}
124+
privatePEM = text
125+
}
126+
if key.Public != nil {
127+
text, err := EncodePublicKeyToPEM(key.Public)
128+
if err != nil {
129+
return KeyConfiguration{}, fmt.Errorf("jwt: %w", err)
130+
}
131+
publicPEM = text
132+
}
133+
134+
config := KeyConfiguration{
135+
ID: key.ID,
136+
Alg: key.Alg.Name(),
137+
Private: privatePEM,
138+
Public: publicPEM,
139+
MaxAge: key.MaxAge,
140+
}
141+
142+
return config, nil
143+
}
144+
145+
// Configuration converts Keys to a keys configuration.
146+
// It will throw an error if any key includes encryption.
147+
//
148+
// Useful to construct a KeysConfiguration
149+
// from JWKS#PublicKeys() method.
150+
func (keys Keys) Configuration() (KeysConfiguration, error) {
151+
config := make(KeysConfiguration, 0, len(keys))
152+
for _, key := range keys {
153+
keyConfig, err := key.Configuration()
154+
if err != nil {
155+
return nil, err
156+
}
157+
config = append(config, keyConfig)
158+
}
159+
160+
return config, nil
161+
}
162+
163+
// EncodePrivateKeyToPEM encodes a PrivateKey to a PEM-encoded string.
164+
func EncodePrivateKeyToPEM(key PrivateKey) (string, error) {
165+
var pemBlock *pem.Block
166+
167+
switch k := key.(type) {
168+
case *rsa.PrivateKey:
169+
privBytes := x509.MarshalPKCS1PrivateKey(k)
170+
pemBlock = &pem.Block{
171+
Type: "RSA PRIVATE KEY",
172+
Bytes: privBytes,
173+
}
174+
case *ecdsa.PrivateKey:
175+
privBytes, err := x509.MarshalECPrivateKey(k)
176+
if err != nil {
177+
return "", fmt.Errorf("failed to marshal ECDSA private key: %v", err)
178+
}
179+
pemBlock = &pem.Block{
180+
Type: "EC PRIVATE KEY",
181+
Bytes: privBytes,
182+
}
183+
case ed25519.PrivateKey:
184+
privBytes, err := x509.MarshalPKCS8PrivateKey(k)
185+
if err != nil {
186+
return "", fmt.Errorf("failed to marshal Ed25519 private key: %v", err)
187+
}
188+
pemBlock = &pem.Block{
189+
Type: "PRIVATE KEY",
190+
Bytes: privBytes,
191+
}
192+
default:
193+
return "", fmt.Errorf("unsupported private key type: %T", key)
194+
}
195+
196+
return string(pem.EncodeToMemory(pemBlock)), nil
197+
}
198+
199+
// EncodePublicKeyToPEM encodes a PublicKey to a PEM-encoded string.
200+
func EncodePublicKeyToPEM(key PublicKey) (string, error) {
201+
var pemBlock *pem.Block
202+
203+
switch k := key.(type) {
204+
case *rsa.PublicKey:
205+
pubBytes, err := x509.MarshalPKIXPublicKey(k)
206+
if err != nil {
207+
return "", fmt.Errorf("failed to marshal RSA public key: %v", err)
208+
}
209+
pemBlock = &pem.Block{
210+
Type: "PUBLIC KEY",
211+
Bytes: pubBytes,
212+
}
213+
case *ecdsa.PublicKey:
214+
pubBytes, err := x509.MarshalPKIXPublicKey(k)
215+
if err != nil {
216+
return "", fmt.Errorf("failed to marshal ECDSA public key: %v", err)
217+
}
218+
pemBlock = &pem.Block{
219+
Type: "PUBLIC KEY",
220+
Bytes: pubBytes,
221+
}
222+
case ed25519.PublicKey:
223+
pubBytes, err := x509.MarshalPKIXPublicKey(k)
224+
if err != nil {
225+
return "", fmt.Errorf("failed to marshal Ed25519 public key: %v", err)
226+
}
227+
pemBlock = &pem.Block{
228+
Type: "PUBLIC KEY",
229+
Bytes: pubBytes,
230+
}
231+
default:
232+
return "", fmt.Errorf("unsupported public key type: %T", key)
233+
}
234+
235+
return string(pem.EncodeToMemory(pemBlock)), nil
236+
}
237+
106238
// Clone returns a new copy of the KeyConfiguration.
107239
func (c KeyConfiguration) Clone() KeyConfiguration {
108240
return KeyConfiguration{

0 commit comments

Comments
 (0)