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:
parent
054f9b8f24
commit
e62ddc004c
@ -36,6 +36,53 @@ type clientHelloMsg struct {
|
|||||||
earlyData bool
|
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 {
|
func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||||
m1, ok := i.(*clientHelloMsg)
|
m1, ok := i.(*clientHelloMsg)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -2030,6 +2077,169 @@ func (m *certificateRequestMsg) unmarshal(data []byte) alert {
|
|||||||
return alertSuccess
|
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 {
|
type certificateVerifyMsg struct {
|
||||||
raw []byte
|
raw []byte
|
||||||
hasSignatureAndHash bool
|
hasSignatureAndHash bool
|
||||||
|
@ -20,6 +20,7 @@ var tests = []interface{}{
|
|||||||
|
|
||||||
&certificateMsg{},
|
&certificateMsg{},
|
||||||
&certificateRequestMsg{},
|
&certificateRequestMsg{},
|
||||||
|
&certificateRequestMsg13{},
|
||||||
&certificateVerifyMsg{},
|
&certificateVerifyMsg{},
|
||||||
&certificateStatusMsg{},
|
&certificateStatusMsg{},
|
||||||
&clientKeyExchangeMsg{},
|
&clientKeyExchangeMsg{},
|
||||||
@ -272,6 +273,18 @@ func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value
|
|||||||
return reflect.ValueOf(m)
|
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 {
|
func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||||
m := &certificateVerifyMsg{}
|
m := &certificateVerifyMsg{}
|
||||||
m.signature = randomBytes(rand.Intn(15)+1, rand)
|
m.signature = randomBytes(rand.Intn(15)+1, rand)
|
||||||
|
Loading…
Reference in New Issue
Block a user