TLSv1.3 -draft23: Implementation of signature_algorithms_cert
Tris uses signature_algorithms_cert in order to advertise that it doesn't support RSA-PSS. See GH#86 for more detailed discussion.
Cette révision appartient à :
Parent
5bdf1af124
révision
03138ec18e
13
13.go
13
13.go
@ -225,6 +225,7 @@ CurvePreferenceLoop:
|
||||
certReq := new(certificateRequestMsg13)
|
||||
// extension 'signature_algorithms' MUST be specified
|
||||
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
|
||||
certReq.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
|
||||
hs.keySchedule.write(certReq.marshal())
|
||||
if _, err := hs.c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
|
||||
return err
|
||||
@ -1114,3 +1115,15 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
||||
c.in.setCipher(c.vers, appServerCipher)
|
||||
return nil
|
||||
}
|
||||
|
||||
// supportedSigAlgorithmsCert iterates over schemes and filters out those algorithms
|
||||
// which are not supported for certificate verification.
|
||||
func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureScheme) {
|
||||
for _, sig := range schemes {
|
||||
// X509 doesn't support PSS signatures
|
||||
if !signatureSchemeIsPSS(sig) {
|
||||
ret = append(ret, sig)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
33
common.go
33
common.go
@ -80,22 +80,23 @@ const (
|
||||
|
||||
// TLS extension numbers
|
||||
const (
|
||||
extensionServerName uint16 = 0
|
||||
extensionStatusRequest uint16 = 5
|
||||
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
|
||||
extensionSupportedPoints uint16 = 11
|
||||
extensionSignatureAlgorithms uint16 = 13
|
||||
extensionALPN uint16 = 16
|
||||
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
|
||||
extensionSessionTicket uint16 = 35
|
||||
extensionPreSharedKey uint16 = 41
|
||||
extensionEarlyData uint16 = 42
|
||||
extensionSupportedVersions uint16 = 43
|
||||
extensionPSKKeyExchangeModes uint16 = 45
|
||||
extensionCAs uint16 = 47
|
||||
extensionKeyShare uint16 = 51
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
extensionServerName uint16 = 0
|
||||
extensionStatusRequest uint16 = 5
|
||||
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
|
||||
extensionSupportedPoints uint16 = 11
|
||||
extensionSignatureAlgorithms uint16 = 13
|
||||
extensionALPN uint16 = 16
|
||||
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
|
||||
extensionSessionTicket uint16 = 35
|
||||
extensionPreSharedKey uint16 = 41
|
||||
extensionEarlyData uint16 = 42
|
||||
extensionSupportedVersions uint16 = 43
|
||||
extensionPSKKeyExchangeModes uint16 = 45
|
||||
extensionCAs uint16 = 47
|
||||
extensionSignatureAlgorithmsCert uint16 = 50
|
||||
extensionKeyShare uint16 = 51
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
)
|
||||
|
||||
// TLS signaling cipher suite values
|
||||
|
@ -155,8 +155,8 @@ func ExampleConfig_keyLogWriter_TLS13() {
|
||||
// preferences.
|
||||
|
||||
// Output:
|
||||
// CLIENT_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 ab02b68658d18ef1a4056b3094fe511b43084d40e9a6518753a7f832da724292
|
||||
// SERVER_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 d2e96648d170e2524bee07b651f4cca932a52247493ca33cc0714260a7424b2d
|
||||
// SERVER_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 371fab23269e3cd73496e0e78f3dbc487f7cd5a563cc9f8c1a71be242268c375
|
||||
// CLIENT_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 ca30484e48ec9a6f3b05b41c7492dbed8dea8e92d2abece2824a96052ac8ed8d
|
||||
// CLIENT_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 a829dab06ccbe9323e0ad6cf331cd64d9a499f7f4b1e0b52d0dfaba90c07f275
|
||||
// SERVER_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 5f6a288b5b5aba5cfc65d9966b279e911ac58bd7f81abbb67b10427106f01940
|
||||
// SERVER_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 1f202d1c1d43e74a8c4f46a56eae2cef9de417ff9f5f3927195eacc168f459b3
|
||||
// CLIENT_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 67ece7874ec4f661fe1f06fb4240decd25f54062d78f0784844bf222d1967c20
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ NextCipherSuite:
|
||||
hello.vers = VersionTLS12
|
||||
hello.supportedVersions = config.getSupportedVersions()
|
||||
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
|
||||
hello.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
|
||||
}
|
||||
|
||||
return hello, nil
|
||||
|
@ -6,81 +6,97 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// signAlgosCertList helper function returns either list of signature algorithms in case
|
||||
// signature_algorithms_cert extension should be marshalled or nil in the other case.
|
||||
// signAlgos is a list of algorithms from signature_algorithms extension. signAlgosCert is a list
|
||||
// of algorithms from signature_algorithms_cert extension.
|
||||
func signAlgosCertList(signAlgos, signAlgosCert []SignatureScheme) []SignatureScheme {
|
||||
if eqSignatureAlgorithms(signAlgos, signAlgosCert) {
|
||||
// ensure that only supported_algorithms extension is send if supported_algorithms_cert
|
||||
// has identical content
|
||||
return nil
|
||||
}
|
||||
return signAlgosCert
|
||||
}
|
||||
|
||||
type clientHelloMsg struct {
|
||||
raw []byte
|
||||
rawTruncated []byte // for PSK binding
|
||||
vers uint16
|
||||
random []byte
|
||||
sessionId []byte
|
||||
cipherSuites []uint16
|
||||
compressionMethods []uint8
|
||||
nextProtoNeg bool
|
||||
serverName string
|
||||
ocspStapling bool
|
||||
scts bool
|
||||
supportedCurves []CurveID
|
||||
supportedPoints []uint8
|
||||
ticketSupported bool
|
||||
sessionTicket []uint8
|
||||
supportedSignatureAlgorithms []SignatureScheme
|
||||
secureRenegotiation []byte
|
||||
secureRenegotiationSupported bool
|
||||
alpnProtocols []string
|
||||
keyShares []keyShare
|
||||
supportedVersions []uint16
|
||||
psks []psk
|
||||
pskKeyExchangeModes []uint8
|
||||
earlyData bool
|
||||
raw []byte
|
||||
rawTruncated []byte // for PSK binding
|
||||
vers uint16
|
||||
random []byte
|
||||
sessionId []byte
|
||||
cipherSuites []uint16
|
||||
compressionMethods []uint8
|
||||
nextProtoNeg bool
|
||||
serverName string
|
||||
ocspStapling bool
|
||||
scts bool
|
||||
supportedCurves []CurveID
|
||||
supportedPoints []uint8
|
||||
ticketSupported bool
|
||||
sessionTicket []uint8
|
||||
supportedSignatureAlgorithms []SignatureScheme
|
||||
supportedSignatureAlgorithmsCert []SignatureScheme
|
||||
secureRenegotiation []byte
|
||||
secureRenegotiationSupported bool
|
||||
alpnProtocols []string
|
||||
keyShares []keyShare
|
||||
supportedVersions []uint16
|
||||
psks []psk
|
||||
pskKeyExchangeModes []uint8
|
||||
earlyData bool
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
// Marshalling of signature_algorithms extension see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
||||
// for more details. Extension is serialized in data buffer
|
||||
// Function used for signature_algorithms and signature_algorithrms_cert extensions only
|
||||
// (for more details, see TLS 1.3 draft 28, 4.2.3)
|
||||
// Function advances data slice and returns it, so that it can be used for further processing
|
||||
func marshalExtensionSignatureAlgorithms(data []byte, sigSchemes []SignatureScheme) []byte {
|
||||
data[0] = byte(extensionSignatureAlgorithms >> 8)
|
||||
data[1] = byte(extensionSignatureAlgorithms)
|
||||
l := 2 + 2*len(sigSchemes)
|
||||
data[2] = byte(l >> 8)
|
||||
data[3] = byte(l)
|
||||
data = data[4:]
|
||||
func marshalExtensionSignatureAlgorithms(extension uint16, data []byte, schemes []SignatureScheme) []byte {
|
||||
algNum := uint16(len(schemes))
|
||||
if algNum == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
l -= 2
|
||||
data[0] = byte(l >> 8)
|
||||
data[1] = byte(l)
|
||||
binary.BigEndian.PutUint16(data, extension)
|
||||
data = data[2:]
|
||||
for _, sigAlgo := range sigSchemes {
|
||||
data[0] = byte(sigAlgo >> 8)
|
||||
data[1] = byte(sigAlgo)
|
||||
binary.BigEndian.PutUint16(data, (2*algNum)+2) // +1 for length
|
||||
data = data[2:]
|
||||
binary.BigEndian.PutUint16(data, (2 * algNum))
|
||||
data = data[2:]
|
||||
|
||||
for _, algo := range schemes {
|
||||
binary.BigEndian.PutUint16(data, uint16(algo))
|
||||
data = data[2:]
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// Unmrshalling of signature_algorithms extension see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
||||
// for more details.
|
||||
// Function used for unmarshalling signature_algorithms or signature_algorithms_cert extensions only
|
||||
// (for more details, see TLS 1.3 draft 28, 4.2.3)
|
||||
// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess
|
||||
func unmarshalExtensionSignatureAlgorithms(data []byte, length int) ([]SignatureScheme, alert) {
|
||||
|
||||
if length < 2 || length&1 != 0 {
|
||||
return nil, alertDecodeError
|
||||
}
|
||||
|
||||
l := int(data[0])<<8 | int(data[1])
|
||||
if l != length-2 {
|
||||
algLen := binary.BigEndian.Uint16(data)
|
||||
idx := 2
|
||||
|
||||
if int(algLen) != length-2 {
|
||||
return nil, alertDecodeError
|
||||
}
|
||||
n := l / 2
|
||||
d := data[2:]
|
||||
sigSchemes := make([]SignatureScheme, n)
|
||||
for i := range sigSchemes {
|
||||
sigSchemes[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1])
|
||||
d = d[2:]
|
||||
|
||||
schemes := make([]SignatureScheme, algLen/2)
|
||||
for i := range schemes {
|
||||
schemes[i] = SignatureScheme(binary.BigEndian.Uint16(data[idx:]))
|
||||
idx += 2
|
||||
}
|
||||
return sigSchemes, alertSuccess
|
||||
return schemes, alertSuccess
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
@ -104,6 +120,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
m.ticketSupported == m1.ticketSupported &&
|
||||
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
|
||||
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
|
||||
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) &&
|
||||
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
|
||||
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
|
||||
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
|
||||
@ -120,6 +137,8 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
|
||||
numExtensions := 0
|
||||
extensionsLength := 0
|
||||
|
||||
// Indicates wether to send signature_algorithms_cert extension
|
||||
if m.nextProtoNeg {
|
||||
numExtensions++
|
||||
}
|
||||
@ -147,6 +166,10 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms)
|
||||
numExtensions++
|
||||
}
|
||||
if m.getSignatureAlgorithmsCert() != nil {
|
||||
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
|
||||
numExtensions++
|
||||
}
|
||||
if m.secureRenegotiationSupported {
|
||||
extensionsLength += 1 + len(m.secureRenegotiation)
|
||||
numExtensions++
|
||||
@ -305,26 +328,15 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
copy(z, m.sessionTicket)
|
||||
z = z[len(m.sessionTicket):]
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithms) > 0 {
|
||||
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
||||
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
|
||||
z[0] = byte(extensionSignatureAlgorithms >> 8)
|
||||
z[1] = byte(extensionSignatureAlgorithms)
|
||||
l := 2 + 2*len(m.supportedSignatureAlgorithms)
|
||||
z[2] = byte(l >> 8)
|
||||
z[3] = byte(l)
|
||||
z = z[4:]
|
||||
|
||||
l -= 2
|
||||
z[0] = byte(l >> 8)
|
||||
z[1] = byte(l)
|
||||
z = z[2:]
|
||||
for _, sigAlgo := range m.supportedSignatureAlgorithms {
|
||||
z[0] = byte(sigAlgo >> 8)
|
||||
z[1] = byte(sigAlgo)
|
||||
z = z[2:]
|
||||
}
|
||||
if len(m.supportedSignatureAlgorithms) > 0 {
|
||||
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
|
||||
}
|
||||
if m.getSignatureAlgorithmsCert() != nil {
|
||||
// Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same
|
||||
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
|
||||
}
|
||||
|
||||
if m.secureRenegotiationSupported {
|
||||
z[0] = byte(extensionRenegotiationInfo >> 8)
|
||||
z[1] = byte(extensionRenegotiationInfo & 0xff)
|
||||
@ -743,6 +755,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
|
||||
return alertSuccess
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) getSignatureAlgorithmsCert() []SignatureScheme {
|
||||
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
|
||||
}
|
||||
|
||||
type serverHelloMsg struct {
|
||||
raw []byte
|
||||
vers uint16
|
||||
@ -2074,15 +2090,17 @@ func (m *certificateRequestMsg) unmarshal(data []byte) alert {
|
||||
if len(data) != 0 {
|
||||
return alertDecodeError
|
||||
}
|
||||
|
||||
return alertSuccess
|
||||
}
|
||||
|
||||
type certificateRequestMsg13 struct {
|
||||
raw []byte
|
||||
|
||||
requestContext []byte
|
||||
supportedSignatureAlgorithms []SignatureScheme
|
||||
certificateAuthorities [][]byte
|
||||
requestContext []byte
|
||||
supportedSignatureAlgorithms []SignatureScheme
|
||||
supportedSignatureAlgorithmsCert []SignatureScheme
|
||||
certificateAuthorities [][]byte
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsg13) equal(i interface{}) bool {
|
||||
@ -2091,7 +2109,8 @@ func (m *certificateRequestMsg13) equal(i interface{}) bool {
|
||||
bytes.Equal(m.raw, m1.raw) &&
|
||||
bytes.Equal(m.requestContext, m1.requestContext) &&
|
||||
eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
|
||||
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms)
|
||||
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
|
||||
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert)
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsg13) marshal() (x []byte) {
|
||||
@ -2104,6 +2123,11 @@ func (m *certificateRequestMsg13) marshal() (x []byte) {
|
||||
numExtensions := 1
|
||||
extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms)
|
||||
|
||||
if m.getSignatureAlgorithmsCert() != nil {
|
||||
numExtensions += 1
|
||||
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
|
||||
}
|
||||
|
||||
casLength := 0
|
||||
if len(m.certificateAuthorities) > 0 {
|
||||
for _, ca := range m.certificateAuthorities {
|
||||
@ -2131,7 +2155,11 @@ func (m *certificateRequestMsg13) marshal() (x []byte) {
|
||||
z = z[2:]
|
||||
|
||||
// TODO: this function should be reused by CH
|
||||
z = marshalExtensionSignatureAlgorithms(z, m.supportedSignatureAlgorithms)
|
||||
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
|
||||
|
||||
if m.getSignatureAlgorithmsCert() != nil {
|
||||
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
|
||||
}
|
||||
// certificate_authorities
|
||||
if casLength > 0 {
|
||||
z[0] = byte(extensionCAs >> 8)
|
||||
@ -2204,6 +2232,12 @@ func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
|
||||
if err != alertSuccess {
|
||||
return err
|
||||
}
|
||||
case extensionSignatureAlgorithmsCert:
|
||||
var err alert
|
||||
m.supportedSignatureAlgorithmsCert, err = unmarshalExtensionSignatureAlgorithms(data, length)
|
||||
if err != alertSuccess {
|
||||
return err
|
||||
}
|
||||
case extensionCAs:
|
||||
// TODO DRY: share code with CH
|
||||
if length < 2 {
|
||||
@ -2240,6 +2274,10 @@ func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
|
||||
return alertSuccess
|
||||
}
|
||||
|
||||
func (m *certificateRequestMsg13) getSignatureAlgorithmsCert() []SignatureScheme {
|
||||
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
|
||||
}
|
||||
|
||||
type certificateVerifyMsg struct {
|
||||
raw []byte
|
||||
hasSignatureAndHash bool
|
||||
|
Chargement…
Référencer dans un nouveau ticket
Block a user