Adds structure for certificate_request in TLS 1.3

* TLS 1.3 requries specific marshalling/unmarshalling of data
* This code should probably be rewritten in order ot use
  a bit cleaner approach for dealing with bytes
This commit is contained in:
Henry Case 2018-03-26 16:13:03 +01:00 committed by Henry Dorsett Case
parent 054f9b8f24
commit e62ddc004c
2 changed files with 223 additions and 0 deletions

View File

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

View File

@ -20,6 +20,7 @@ var tests = []interface{}{
&certificateMsg{},
&certificateRequestMsg{},
&certificateRequestMsg13{},
&certificateVerifyMsg{},
&certificateStatusMsg{},
&clientKeyExchangeMsg{},
@ -272,6 +273,18 @@ func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value
return reflect.ValueOf(m)
}
func (*certificateRequestMsg13) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateRequestMsg13{}
m.requestContext = randomBytes(rand.Intn(5), rand)
m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
numCAs := rand.Intn(100)
m.certificateAuthorities = make([][]byte, numCAs)
for i := 0; i < numCAs; i++ {
m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand)
}
return reflect.ValueOf(m)
}
func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateVerifyMsg{}
m.signature = randomBytes(rand.Intn(15)+1, rand)