// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
type clientHelloMsg struct {
raw []byte;
major, minor uint8;
random []byte;
sessionId []byte;
cipherSuites []uint16;
compressionMethods []uint8;
}
func (m *clientHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods);
x := make([]byte, 4+length);
x[0] = typeClientHello;
x[1] = uint8(length >> 16);
x[2] = uint8(length >> 8);
x[3] = uint8(length);
x[4] = m.major;
x[5] = m.minor;
copy(x[6:38], m.random);
x[38] = uint8(len(m.sessionId));
copy(x[39:39+len(m.sessionId)], m.sessionId);
y := x[39+len(m.sessionId):];
y[0] = uint8(len(m.cipherSuites) >> 7);
y[1] = uint8(len(m.cipherSuites) << 1);
for i, suite := range m.cipherSuites {
y[2+i*2] = uint8(suite >> 8);
y[3+i*2] = uint8(suite);
}
z := y[2+len(m.cipherSuites)*2:];
z[0] = uint8(len(m.compressionMethods));
copy(z[1:], m.compressionMethods);
m.raw = x;
return x;
}
func (m *clientHelloMsg) unmarshal(data []byte) bool {
if len(data) < 43 {
return false
}
m.raw = data;
m.major = data[4];
m.minor = data[5];
m.random = data[6:38];
sessionIdLen := int(data[38]);
if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
return false
}
m.sessionId = data[39 : 39+sessionIdLen];
data = data[39+sessionIdLen:];
if len(data) < 2 {
return false
}
// cipherSuiteLen is the number of bytes of cipher suite numbers. Since
// they are uint16s, the number must be even.
cipherSuiteLen := int(data[0])<<8 | int(data[1]);
if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
return false
}
numCipherSuites := cipherSuiteLen / 2;
m.cipherSuites = make([]uint16, numCipherSuites);
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
}
data = data[2+cipherSuiteLen:];
if len(data) < 2 {
return false
}
compressionMethodsLen := int(data[0]);
if len(data) < 1+compressionMethodsLen {
return false
}
m.compressionMethods = data[1 : 1+compressionMethodsLen];
// A ClientHello may be following by trailing data: RFC 4346 section 7.4.1.2
return true;
}
type serverHelloMsg struct {
raw []byte;
major, minor uint8;
random []byte;
sessionId []byte;
cipherSuite uint16;
compressionMethod uint8;
}
func (m *serverHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := 38 + len(m.sessionId);
x := make([]byte, 4+length);
x[0] = typeServerHello;
x[1] = uint8(length >> 16);
x[2] = uint8(length >> 8);
x[3] = uint8(length);
x[4] = m.major;
x[5] = m.minor;
copy(x[6:38], m.random);
x[38] = uint8(len(m.sessionId));
copy(x[39:39+len(m.sessionId)], m.sessionId);
z := x[39+len(m.sessionId):];
z[0] = uint8(m.cipherSuite >> 8);
z[1] = uint8(m.cipherSuite);
z[2] = uint8(m.compressionMethod);
m.raw = x;
return x;
}
func (m *serverHelloMsg) unmarshal(data []byte) bool {
if len(data) < 42 {
return false
}
m.raw = data;
m.major = data[4];
m.minor = data[5];
m.random = data[6:38];
sessionIdLen := int(data[38]);
if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
return false
}
m.sessionId = data[39 : 39+sessionIdLen];
data = data[39+sessionIdLen:];
if len(data) < 3 {
return false
}
m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]);
m.compressionMethod = data[2];
// Trailing data is allowed because extensions may be present.
return true;
}
type certificateMsg struct {
raw []byte;
certificates [][]byte;
}
func (m *certificateMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
var i int;
for _, slice := range m.certificates {
i += len(slice)
}
length := 3 + 3*len(m.certificates) + i;
x = make([]byte, 4+length);
x[0] = typeCertificate;
x[1] = uint8(length >> 16);
x[2] = uint8(length >> 8);
x[3] = uint8(length);
certificateOctets := length - 3;
x[4] = uint8(certificateOctets >> 16);
x[5] = uint8(certificateOctets >> 8);
x[6] = uint8(certificateOctets);
y := x[7:];
for _, slice := range m.certificates {
y[0] = uint8(len(slice) >> 16);
y[1] = uint8(len(slice) >> 8);
y[2] = uint8(len(slice));
copy(y[3:], slice);
y = y[3+len(slice):];
}
m.raw = x;
return;
}
func (m *certificateMsg) unmarshal(data []byte) bool {
if len(data) < 7 {
return false
}
m.raw = data;
certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]);
if uint32(len(data)) != certsLen+7 {
return false
}
numCerts := 0;
d := data[7:];
for certsLen > 0 {
if len(d) < 4 {
return false
}
certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2]);
if uint32(len(d)) < 3+certLen {
return false
}
d = d[3+certLen:];
certsLen -= 3 + certLen;
numCerts++;
}
m.certificates = make([][]byte, numCerts);
d = data[7:];
for i := 0; i < numCerts; i++ {
certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2]);
m.certificates[i] = d[3 : 3+certLen];
d = d[3+certLen:];
}
return true;
}
type serverHelloDoneMsg struct{}
func (m *serverHelloDoneMsg) marshal() []byte {
x := make([]byte, 4);
x[0] = typeServerHelloDone;
return x;
}
func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
return len(data) == 4
}
type clientKeyExchangeMsg struct {
raw []byte;
ciphertext []byte;
}
func (m *clientKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
length := len(m.ciphertext) + 2;
x := make([]byte, length+4);
x[0] = typeClientKeyExchange;
x[1] = uint8(length >> 16);
x[2] = uint8(length >> 8);
x[3] = uint8(length);
x[4] = uint8(len(m.ciphertext) >> 8);
x[5] = uint8(len(m.ciphertext));
copy(x[6:], m.ciphertext);
m.raw = x;
return x;
}
func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
m.raw = data;
if len(data) < 7 {
return false
}
cipherTextLen := int(data[4])<<8 | int(data[5]);
if len(data) != 6+cipherTextLen {
return false
}
m.ciphertext = data[6:];
return true;
}
type finishedMsg struct {
raw []byte;
verifyData []byte;
}
func (m *finishedMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
x = make([]byte, 16);
x[0] = typeFinished;
x[3] = 12;
copy(x[4:], m.verifyData);
m.raw = x;
return;
}
func (m *finishedMsg) unmarshal(data []byte) bool {
m.raw = data;
if len(data) != 4+12 {
return false
}
m.verifyData = data[4:];
return true;
}
|