rsa_pss.go raw

   1  //go:build go1.4
   2  // +build go1.4
   3  
   4  package jwt
   5  
   6  import (
   7  	"crypto"
   8  	"crypto/rand"
   9  	"crypto/rsa"
  10  )
  11  
  12  // SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
  13  type 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.
  24  var (
  25  	SigningMethodPS256 *SigningMethodRSAPSS
  26  	SigningMethodPS384 *SigningMethodRSAPSS
  27  	SigningMethodPS512 *SigningMethodRSAPSS
  28  )
  29  
  30  func 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
  85  func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
  86  	var err error
  87  
  88  	// Decode the signature
  89  	var sig []byte
  90  	if sig, err = DecodeSegment(signature); err != nil {
  91  		return err
  92  	}
  93  
  94  	var rsaKey *rsa.PublicKey
  95  	switch k := key.(type) {
  96  	case *rsa.PublicKey:
  97  		rsaKey = k
  98  	default:
  99  		return ErrInvalidKey
 100  	}
 101  
 102  	// Create hasher
 103  	if !m.Hash.Available() {
 104  		return ErrHashUnavailable
 105  	}
 106  	hasher := m.Hash.New()
 107  	hasher.Write([]byte(signingString))
 108  
 109  	opts := m.Options
 110  	if m.VerifyOptions != nil {
 111  		opts = m.VerifyOptions
 112  	}
 113  
 114  	return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
 115  }
 116  
 117  // Sign implements token signing for the SigningMethod.
 118  // For this signing method, key must be an rsa.PrivateKey struct
 119  func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
 120  	var rsaKey *rsa.PrivateKey
 121  
 122  	switch k := key.(type) {
 123  	case *rsa.PrivateKey:
 124  		rsaKey = k
 125  	default:
 126  		return "", ErrInvalidKeyType
 127  	}
 128  
 129  	// Create the hasher
 130  	if !m.Hash.Available() {
 131  		return "", ErrHashUnavailable
 132  	}
 133  
 134  	hasher := m.Hash.New()
 135  	hasher.Write([]byte(signingString))
 136  
 137  	// Sign the string and return the encoded bytes
 138  	if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
 139  		return EncodeSegment(sigBytes), nil
 140  	} else {
 141  		return "", err
 142  	}
 143  }
 144