1package jwt
2
3import (
4	"crypto/rsa"
5	"crypto/x509"
6	"encoding/pem"
7	"errors"
8)
9
10var (
11	ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key")
12	ErrNotRSAPrivateKey    = errors.New("key is not a valid RSA private key")
13	ErrNotRSAPublicKey     = errors.New("key is not a valid RSA public key")
14)
15
16// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key
17func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
18	var err error
19
20	// Parse PEM block
21	var block *pem.Block
22	if block, _ = pem.Decode(key); block == nil {
23		return nil, ErrKeyMustBePEMEncoded
24	}
25
26	var parsedKey interface{}
27	if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
28		if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
29			return nil, err
30		}
31	}
32
33	var pkey *rsa.PrivateKey
34	var ok bool
35	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
36		return nil, ErrNotRSAPrivateKey
37	}
38
39	return pkey, nil
40}
41
42// ParseRSAPrivateKeyFromPEMWithPassword parses a PEM encoded PKCS1 or PKCS8 private key protected with password
43//
44// Deprecated: This function is deprecated and should not be used anymore. It uses the deprecated x509.DecryptPEMBlock
45// function, which was deprecated since RFC 1423 is regarded insecure by design. Unfortunately, there is no alternative
46// in the Go standard library for now. See https://github.com/golang/go/issues/8860.
47func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
48	var err error
49
50	// Parse PEM block
51	var block *pem.Block
52	if block, _ = pem.Decode(key); block == nil {
53		return nil, ErrKeyMustBePEMEncoded
54	}
55
56	var parsedKey interface{}
57
58	var blockDecrypted []byte
59	if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
60		return nil, err
61	}
62
63	if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
64		if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
65			return nil, err
66		}
67	}
68
69	var pkey *rsa.PrivateKey
70	var ok bool
71	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
72		return nil, ErrNotRSAPrivateKey
73	}
74
75	return pkey, nil
76}
77
78// ParseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
79func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
80	var err error
81
82	// Parse PEM block
83	var block *pem.Block
84	if block, _ = pem.Decode(key); block == nil {
85		return nil, ErrKeyMustBePEMEncoded
86	}
87
88	// Parse the key
89	var parsedKey interface{}
90	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
91		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
92			parsedKey = cert.PublicKey
93		} else {
94			return nil, err
95		}
96	}
97
98	var pkey *rsa.PublicKey
99	var ok bool
100	if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
101		return nil, ErrNotRSAPublicKey
102	}
103
104	return pkey, nil
105}
106