mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-14 10:10:42 -07:00
Support TLS 1.2 RSA signature with PKCS#1 v1.5 padding (#4244)
Cert Store (aka wincert) feature wasn't properly handling TLS 1.2 handshake with TLS 1.2 clients that do not support RSA signature with PSS padding. With this update, Cert Store will perform either PKCS#1 v1.5 or PSS padding for RSA signature depending on what type is negotiated by the TLS 1.2 client. Issue surfaces with the NATS .NET v1 client which supports TLS 1.2 only (.NET 4.6.2 dependency) only when the client application was hosted on Windows 10 Enterprise LTSC 2019 (equivalent also to Windows 10 1809 and Windows Server 2019). If the same client was executed on a more modern Windows 10 release, RSA signature with PSS padding was negotiated and succeeded normally. The Go NATS client as well as any client operating at TLS 1.3 level would not exhibit the issue as TLS 1.3 requires PSS. Fix tested good on Windows 10 Enterprise LTSC 2019 host and in confirmed fixed in user's Windows environment where the issue was originally detected.
This commit is contained in:
@@ -62,6 +62,7 @@ const (
|
||||
|
||||
winNcryptKeySpec = 0xFFFFFFFF // CERT_NCRYPT_KEY_SPEC
|
||||
|
||||
winBCryptPadPKCS1 uintptr = 0x2
|
||||
winBCryptPadPSS uintptr = 0x8 // Modern TLS 1.2+
|
||||
winBCryptPadPSSSalt uint32 = 32 // default 20, 32 optimal for typical SHA256 hash
|
||||
|
||||
@@ -127,6 +128,10 @@ var (
|
||||
winFnGetProperty = winGetProperty
|
||||
)
|
||||
|
||||
type winPKCS1PaddingInfo struct {
|
||||
pszAlgID *uint16
|
||||
}
|
||||
|
||||
type winPSSPaddingInfo struct {
|
||||
pszAlgID *uint16
|
||||
cbSalt uint32
|
||||
@@ -405,7 +410,12 @@ func (k winKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte
|
||||
if !ok {
|
||||
return nil, ErrBadRSAHashAlgorithm
|
||||
}
|
||||
return winSignRSA(k.handle, digest, algID)
|
||||
switch opts.(type) {
|
||||
case *rsa.PSSOptions:
|
||||
return winSignRSAPSSPadding(k.handle, digest, algID)
|
||||
default:
|
||||
return winSignRSAPKCS1Padding(k.handle, digest, algID)
|
||||
}
|
||||
default:
|
||||
return nil, ErrBadSigningAlgorithm
|
||||
}
|
||||
@@ -467,8 +477,44 @@ func winPackECDSASigValue(r io.Reader, digestLength int) ([]byte, error) {
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func winSignRSA(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
|
||||
// PSS padding for TLS 1.2+
|
||||
func winSignRSAPKCS1Padding(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
|
||||
// PKCS#1 v1.5 padding for some TLS 1.2
|
||||
padInfo := winPKCS1PaddingInfo{pszAlgID: algID}
|
||||
var size uint32
|
||||
// Obtain the size of the signature
|
||||
r, _, _ := winNCryptSignHash.Call(
|
||||
kh,
|
||||
uintptr(unsafe.Pointer(&padInfo)),
|
||||
uintptr(unsafe.Pointer(&digest[0])),
|
||||
uintptr(len(digest)),
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
winBCryptPadPKCS1)
|
||||
if r != 0 {
|
||||
return nil, ErrStoreRSASigningError
|
||||
}
|
||||
|
||||
// Obtain the signature data
|
||||
sig := make([]byte, size)
|
||||
r, _, _ = winNCryptSignHash.Call(
|
||||
kh,
|
||||
uintptr(unsafe.Pointer(&padInfo)),
|
||||
uintptr(unsafe.Pointer(&digest[0])),
|
||||
uintptr(len(digest)),
|
||||
uintptr(unsafe.Pointer(&sig[0])),
|
||||
uintptr(size),
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
winBCryptPadPKCS1)
|
||||
if r != 0 {
|
||||
return nil, ErrStoreRSASigningError
|
||||
}
|
||||
|
||||
return sig[:size], nil
|
||||
}
|
||||
|
||||
func winSignRSAPSSPadding(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
|
||||
// PSS padding for TLS 1.3 and some TLS 1.2
|
||||
padInfo := winPSSPaddingInfo{pszAlgID: algID, cbSalt: winBCryptPadPSSSalt}
|
||||
|
||||
var size uint32
|
||||
|
||||
Reference in New Issue
Block a user