| //go:build go1.4 |
| // +build go1.4 |
| |
| package jwt |
| |
| import ( |
| "crypto" |
| "crypto/rand" |
| "crypto/rsa" |
| ) |
| |
| // SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods |
| type SigningMethodRSAPSS struct { |
| *SigningMethodRSA |
| Options *rsa.PSSOptions |
| // VerifyOptions is optional. If set overrides Options for rsa.VerifyPPS. |
| // Used to accept tokens signed with rsa.PSSSaltLengthAuto, what doesn't follow |
| // https://tools.ietf.org/html/rfc7518#section-3.5 but was used previously. |
| // See https://github.com/dgrijalva/jwt-go/issues/285#issuecomment-437451244 for details. |
| VerifyOptions *rsa.PSSOptions |
| } |
| |
| // Specific instances for RS/PS and company. |
| var ( |
| SigningMethodPS256 *SigningMethodRSAPSS |
| SigningMethodPS384 *SigningMethodRSAPSS |
| SigningMethodPS512 *SigningMethodRSAPSS |
| ) |
| |
| func init() { |
| // PS256 |
| SigningMethodPS256 = &SigningMethodRSAPSS{ |
| SigningMethodRSA: &SigningMethodRSA{ |
| Name: "PS256", |
| Hash: crypto.SHA256, |
| }, |
| Options: &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthEqualsHash, |
| }, |
| VerifyOptions: &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthAuto, |
| }, |
| } |
| RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod { |
| return SigningMethodPS256 |
| }) |
| |
| // PS384 |
| SigningMethodPS384 = &SigningMethodRSAPSS{ |
| SigningMethodRSA: &SigningMethodRSA{ |
| Name: "PS384", |
| Hash: crypto.SHA384, |
| }, |
| Options: &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthEqualsHash, |
| }, |
| VerifyOptions: &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthAuto, |
| }, |
| } |
| RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod { |
| return SigningMethodPS384 |
| }) |
| |
| // PS512 |
| SigningMethodPS512 = &SigningMethodRSAPSS{ |
| SigningMethodRSA: &SigningMethodRSA{ |
| Name: "PS512", |
| Hash: crypto.SHA512, |
| }, |
| Options: &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthEqualsHash, |
| }, |
| VerifyOptions: &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthAuto, |
| }, |
| } |
| RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod { |
| return SigningMethodPS512 |
| }) |
| } |
| |
| // Verify implements token verification for the SigningMethod. |
| // For this verify method, key must be an rsa.PublicKey struct |
| func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key interface{}) error { |
| var rsaKey *rsa.PublicKey |
| switch k := key.(type) { |
| case *rsa.PublicKey: |
| rsaKey = k |
| default: |
| return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType) |
| } |
| |
| // Create hasher |
| if !m.Hash.Available() { |
| return ErrHashUnavailable |
| } |
| hasher := m.Hash.New() |
| hasher.Write([]byte(signingString)) |
| |
| opts := m.Options |
| if m.VerifyOptions != nil { |
| opts = m.VerifyOptions |
| } |
| |
| return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts) |
| } |
| |
| // Sign implements token signing for the SigningMethod. |
| // For this signing method, key must be an rsa.PrivateKey struct |
| func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byte, error) { |
| var rsaKey *rsa.PrivateKey |
| |
| switch k := key.(type) { |
| case *rsa.PrivateKey: |
| rsaKey = k |
| default: |
| return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType) |
| } |
| |
| // Create the hasher |
| if !m.Hash.Available() { |
| return nil, ErrHashUnavailable |
| } |
| |
| hasher := m.Hash.New() |
| hasher.Write([]byte(signingString)) |
| |
| // Sign the string and return the encoded bytes |
| if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil { |
| return sigBytes, nil |
| } else { |
| return nil, err |
| } |
| } |