|
|
@@ -36,6 +36,53 @@ type clientHelloMsg struct { |
|
|
|
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 advances data slice and returns it, so that it can be used for further processing |
|
|
|
func marshallExtensionSignatureAlgorithms(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:] |
|
|
|
|
|
|
|
l -= 2 |
|
|
|
data[0] = byte(l >> 8) |
|
|
|
data[1] = byte(l) |
|
|
|
data = data[2:] |
|
|
|
for _, sigAlgo := range sigSchemes { |
|
|
|
data[0] = byte(sigAlgo >> 8) |
|
|
|
data[1] = byte(sigAlgo) |
|
|
|
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. |
|
|
|
// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess |
|
|
|
func unmarshallExtensionSignatureAlgorithms(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 { |
|
|
|
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:] |
|
|
|
} |
|
|
|
return sigSchemes, alertSuccess |
|
|
|
} |
|
|
|
|
|
|
|
func (m *clientHelloMsg) equal(i interface{}) bool { |
|
|
|
m1, ok := i.(*clientHelloMsg) |
|
|
|
if !ok { |
|
|
@@ -2030,6 +2077,169 @@ func (m *certificateRequestMsg) unmarshal(data []byte) alert { |
|
|
|
return alertSuccess |
|
|
|
} |
|
|
|
|
|
|
|
type certificateRequestMsg13 struct { |
|
|
|
raw []byte |
|
|
|
|
|
|
|
requestContext []byte |
|
|
|
supportedSignatureAlgorithms []SignatureScheme |
|
|
|
certificateAuthorities [][]byte |
|
|
|
} |
|
|
|
|
|
|
|
func (m *certificateRequestMsg13) equal(i interface{}) bool { |
|
|
|
m1, ok := i.(*certificateRequestMsg13) |
|
|
|
return ok && |
|
|
|
bytes.Equal(m.raw, m1.raw) && |
|
|
|
bytes.Equal(m.requestContext, m1.requestContext) && |
|
|
|
eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && |
|
|
|
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) |
|
|
|
} |
|
|
|
|
|
|
|
func (m *certificateRequestMsg13) marshal() (x []byte) { |
|
|
|
if m.raw != nil { |
|
|
|
return m.raw |
|
|
|
} |
|
|
|
|
|
|
|
// See https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.3.2 |
|
|
|
length := 1 + len(m.requestContext) |
|
|
|
numExtensions := 1 |
|
|
|
extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms) |
|
|
|
|
|
|
|
casLength := 0 |
|
|
|
if len(m.certificateAuthorities) > 0 { |
|
|
|
for _, ca := range m.certificateAuthorities { |
|
|
|
casLength += 2 + len(ca) |
|
|
|
} |
|
|
|
extensionsLength += 2 + casLength |
|
|
|
numExtensions++ |
|
|
|
} |
|
|
|
|
|
|
|
extensionsLength += 4 * numExtensions |
|
|
|
length += 2 + extensionsLength |
|
|
|
|
|
|
|
x = make([]byte, 4+length) |
|
|
|
x[0] = typeCertificateRequest |
|
|
|
x[1] = uint8(length >> 16) |
|
|
|
x[2] = uint8(length >> 8) |
|
|
|
x[3] = uint8(length) |
|
|
|
|
|
|
|
x[4] = uint8(len(m.requestContext)) |
|
|
|
copy(x[5:], m.requestContext) |
|
|
|
z := x[5+len(m.requestContext):] |
|
|
|
|
|
|
|
z[0] = byte(extensionsLength >> 8) |
|
|
|
z[1] = byte(extensionsLength) |
|
|
|
z = z[2:] |
|
|
|
|
|
|
|
// TODO: this function should be reused by CH |
|
|
|
z = marshallExtensionSignatureAlgorithms(z, m.supportedSignatureAlgorithms) |
|
|
|
// certificate_authorities |
|
|
|
if casLength > 0 { |
|
|
|
z[0] = byte(extensionCAs >> 8) |
|
|
|
z[1] = byte(extensionCAs) |
|
|
|
l := 2 + casLength |
|
|
|
z[2] = byte(l >> 8) |
|
|
|
z[3] = byte(l) |
|
|
|
z = z[4:] |
|
|
|
|
|
|
|
z[0] = uint8(casLength >> 8) |
|
|
|
z[1] = uint8(casLength) |
|
|
|
z = z[2:] |
|
|
|
for _, ca := range m.certificateAuthorities { |
|
|
|
z[0] = uint8(len(ca) >> 8) |
|
|
|
z[1] = uint8(len(ca)) |
|
|
|
z = z[2:] |
|
|
|
copy(z, ca) |
|
|
|
z = z[len(ca):] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
m.raw = x |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (m *certificateRequestMsg13) unmarshal(data []byte) alert { |
|
|
|
m.raw = data |
|
|
|
m.supportedSignatureAlgorithms = nil |
|
|
|
m.certificateAuthorities = nil |
|
|
|
|
|
|
|
if len(data) < 5 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
|
|
|
|
length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) |
|
|
|
if uint32(len(data))-4 != length { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
|
|
|
|
ctxLen := data[4] |
|
|
|
if len(data) < 5+int(ctxLen)+2 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
m.requestContext = data[5 : 5+ctxLen] |
|
|
|
data = data[5+ctxLen:] |
|
|
|
|
|
|
|
extensionsLength := int(data[0])<<8 | int(data[1]) |
|
|
|
data = data[2:] |
|
|
|
if len(data) != extensionsLength { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
|
|
|
|
for len(data) != 0 { |
|
|
|
if len(data) < 4 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
extension := uint16(data[0])<<8 | uint16(data[1]) |
|
|
|
length := int(data[2])<<8 | int(data[3]) |
|
|
|
data = data[4:] |
|
|
|
if len(data) < length { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
|
|
|
|
switch extension { |
|
|
|
case extensionSignatureAlgorithms: |
|
|
|
// TODO: unmarshallExtensionSignatureAlgorithms should be shared with CH and pre-1.3 CV |
|
|
|
// https://tools.ietf.org/html/draft-ietf-tls-tls13-21#section-4.2.3 |
|
|
|
var err alert |
|
|
|
m.supportedSignatureAlgorithms, err = unmarshallExtensionSignatureAlgorithms(data, length) |
|
|
|
if err != alertSuccess { |
|
|
|
return err |
|
|
|
} |
|
|
|
case extensionCAs: |
|
|
|
// TODO DRY: share code with CH |
|
|
|
if length < 2 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
l := int(data[0])<<8 | int(data[1]) |
|
|
|
if l != length-2 || l < 3 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
cas := make([]byte, l) |
|
|
|
copy(cas, data[2:]) |
|
|
|
m.certificateAuthorities = nil |
|
|
|
for len(cas) > 0 { |
|
|
|
if len(cas) < 2 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
caLen := uint16(cas[0])<<8 | uint16(cas[1]) |
|
|
|
cas = cas[2:] |
|
|
|
|
|
|
|
if len(cas) < int(caLen) { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
|
|
|
|
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) |
|
|
|
cas = cas[caLen:] |
|
|
|
} |
|
|
|
} |
|
|
|
data = data[length:] |
|
|
|
} |
|
|
|
|
|
|
|
if len(m.supportedSignatureAlgorithms) == 0 { |
|
|
|
return alertDecodeError |
|
|
|
} |
|
|
|
return alertSuccess |
|
|
|
} |
|
|
|
|
|
|
|
type certificateVerifyMsg struct { |
|
|
|
raw []byte |
|
|
|
hasSignatureAndHash bool |
|
|
|