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.
This commit is contained in:
Henry Case 2018-06-26 14:25:45 +01:00 committed by Henry Dorsett Case
parent 5bdf1af124
commit 03138ec18e
5 changed files with 147 additions and 94 deletions

13
13.go
View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -106,6 +106,7 @@ NextCipherSuite:
hello.vers = VersionTLS12
hello.supportedVersions = config.getSupportedVersions()
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
hello.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
}
return hello, nil

View File

@ -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