//go:build go1.4
// +build go1.4

package jwt

import (
	
	
	
)

// 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 ( *SigningMethodRSAPSS) (,  string,  interface{}) error {
	var  error

	// Decode the signature
	var  []byte
	if ,  = DecodeSegment();  != nil {
		return 
	}

	var  *rsa.PublicKey
	switch k := .(type) {
	case *rsa.PublicKey:
		 = 
	default:
		return ErrInvalidKey
	}

	// Create hasher
	if !.Hash.Available() {
		return ErrHashUnavailable
	}
	 := .Hash.New()
	.Write([]byte())

	 := .Options
	if .VerifyOptions != nil {
		 = .VerifyOptions
	}

	return rsa.VerifyPSS(, .Hash, .Sum(nil), , )
}

// Sign implements token signing for the SigningMethod.
// For this signing method, key must be an rsa.PrivateKey struct
func ( *SigningMethodRSAPSS) ( string,  interface{}) (string, error) {
	var  *rsa.PrivateKey

	switch k := .(type) {
	case *rsa.PrivateKey:
		 = 
	default:
		return "", ErrInvalidKeyType
	}

	// Create the hasher
	if !.Hash.Available() {
		return "", ErrHashUnavailable
	}

	 := .Hash.New()
	.Write([]byte())

	// Sign the string and return the encoded bytes
	if ,  := rsa.SignPSS(rand.Reader, , .Hash, .Sum(nil), .Options);  == nil {
		return EncodeSegment(), nil
	} else {
		return "", 
	}
}