rsa_pss.go

  1//go:build go1.4
  2// +build go1.4
  3
  4package jwt
  5
  6import (
  7	"crypto"
  8	"crypto/rand"
  9	"crypto/rsa"
 10)
 11
 12// SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
 13type SigningMethodRSAPSS struct {
 14	*SigningMethodRSA
 15	Options *rsa.PSSOptions
 16	// VerifyOptions is optional. If set overrides Options for rsa.VerifyPPS.
 17	// Used to accept tokens signed with rsa.PSSSaltLengthAuto, what doesn't follow
 18	// https://tools.ietf.org/html/rfc7518#section-3.5 but was used previously.
 19	// See https://github.com/dgrijalva/jwt-go/issues/285#issuecomment-437451244 for details.
 20	VerifyOptions *rsa.PSSOptions
 21}
 22
 23// Specific instances for RS/PS and company.
 24var (
 25	SigningMethodPS256 *SigningMethodRSAPSS
 26	SigningMethodPS384 *SigningMethodRSAPSS
 27	SigningMethodPS512 *SigningMethodRSAPSS
 28)
 29
 30func init() {
 31	// PS256
 32	SigningMethodPS256 = &SigningMethodRSAPSS{
 33		SigningMethodRSA: &SigningMethodRSA{
 34			Name: "PS256",
 35			Hash: crypto.SHA256,
 36		},
 37		Options: &rsa.PSSOptions{
 38			SaltLength: rsa.PSSSaltLengthEqualsHash,
 39		},
 40		VerifyOptions: &rsa.PSSOptions{
 41			SaltLength: rsa.PSSSaltLengthAuto,
 42		},
 43	}
 44	RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
 45		return SigningMethodPS256
 46	})
 47
 48	// PS384
 49	SigningMethodPS384 = &SigningMethodRSAPSS{
 50		SigningMethodRSA: &SigningMethodRSA{
 51			Name: "PS384",
 52			Hash: crypto.SHA384,
 53		},
 54		Options: &rsa.PSSOptions{
 55			SaltLength: rsa.PSSSaltLengthEqualsHash,
 56		},
 57		VerifyOptions: &rsa.PSSOptions{
 58			SaltLength: rsa.PSSSaltLengthAuto,
 59		},
 60	}
 61	RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
 62		return SigningMethodPS384
 63	})
 64
 65	// PS512
 66	SigningMethodPS512 = &SigningMethodRSAPSS{
 67		SigningMethodRSA: &SigningMethodRSA{
 68			Name: "PS512",
 69			Hash: crypto.SHA512,
 70		},
 71		Options: &rsa.PSSOptions{
 72			SaltLength: rsa.PSSSaltLengthEqualsHash,
 73		},
 74		VerifyOptions: &rsa.PSSOptions{
 75			SaltLength: rsa.PSSSaltLengthAuto,
 76		},
 77	}
 78	RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
 79		return SigningMethodPS512
 80	})
 81}
 82
 83// Verify implements token verification for the SigningMethod.
 84// For this verify method, key must be an rsa.PublicKey struct
 85func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key interface{}) error {
 86	var rsaKey *rsa.PublicKey
 87	switch k := key.(type) {
 88	case *rsa.PublicKey:
 89		rsaKey = k
 90	default:
 91		return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType)
 92	}
 93
 94	// Create hasher
 95	if !m.Hash.Available() {
 96		return ErrHashUnavailable
 97	}
 98	hasher := m.Hash.New()
 99	hasher.Write([]byte(signingString))
100
101	opts := m.Options
102	if m.VerifyOptions != nil {
103		opts = m.VerifyOptions
104	}
105
106	return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
107}
108
109// Sign implements token signing for the SigningMethod.
110// For this signing method, key must be an rsa.PrivateKey struct
111func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byte, error) {
112	var rsaKey *rsa.PrivateKey
113
114	switch k := key.(type) {
115	case *rsa.PrivateKey:
116		rsaKey = k
117	default:
118		return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType)
119	}
120
121	// Create the hasher
122	if !m.Hash.Available() {
123		return nil, ErrHashUnavailable
124	}
125
126	hasher := m.Hash.New()
127	hasher.Write([]byte(signingString))
128
129	// Sign the string and return the encoded bytes
130	if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
131		return sigBytes, nil
132	} else {
133		return nil, err
134	}
135}