|
|
|
@ -6,40 +6,6 @@ package noise
|
|
|
|
|
|
|
|
|
|
import "encoding/binary"
|
|
|
|
|
|
|
|
|
|
// The control protocol wire format is mostly Noise messages
|
|
|
|
|
// encapsulated in a small header describing the payload's type and
|
|
|
|
|
// length. The one place we deviate from pure Noise+header is that we
|
|
|
|
|
// also support sending an unauthenticated plaintext error as payload,
|
|
|
|
|
// to provide an explanation for a connection error that happens
|
|
|
|
|
// before the handshake completes.
|
|
|
|
|
//
|
|
|
|
|
// All frames in our protocol have a 5-byte header:
|
|
|
|
|
//
|
|
|
|
|
// +------+------+------+------+------+
|
|
|
|
|
// | version | type | length |
|
|
|
|
|
// +------+------+------+------+------+
|
|
|
|
|
//
|
|
|
|
|
// 2b: protocol version
|
|
|
|
|
// 1b: message type
|
|
|
|
|
// 2b: payload length (not including the header)
|
|
|
|
|
//
|
|
|
|
|
// Multibyte values are all big-endian on the wire, as is traditional
|
|
|
|
|
// for network protocols.
|
|
|
|
|
//
|
|
|
|
|
// The protocol version is 2 bytes in order to encourage frequent
|
|
|
|
|
// revving of the protocol as needed, without fear of running out of
|
|
|
|
|
// version numbers. At minimum, the version number must change
|
|
|
|
|
// whenever any particulars of the Noise handshake change
|
|
|
|
|
// (e.g. switching from Noise IK to Noise IKpsk1 or Noise XX), and
|
|
|
|
|
// when security-critical aspects of the "uppper" protocol (the one
|
|
|
|
|
// running inside the established base protocol session) change
|
|
|
|
|
// (e.g. how further authentication data is bound to the underlying
|
|
|
|
|
// session).
|
|
|
|
|
|
|
|
|
|
// headerLen is the size of the header that gets prepended to Noise
|
|
|
|
|
// messages.
|
|
|
|
|
const headerLen = 5
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// msgTypeInitiation frames carry a Noise IK handshake initiation message.
|
|
|
|
|
msgTypeInitiation = 1
|
|
|
|
@ -54,20 +20,19 @@ const (
|
|
|
|
|
msgTypeError = 3
|
|
|
|
|
// msgTypeRecord frames carry session data bytes.
|
|
|
|
|
msgTypeRecord = 4
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func setHeader(bs []byte, version uint16, msgType byte, length int) {
|
|
|
|
|
binary.LittleEndian.PutUint16(bs[:2], uint16(version))
|
|
|
|
|
bs[2] = msgType
|
|
|
|
|
binary.LittleEndian.PutUint16(bs[3:5], uint16(length))
|
|
|
|
|
}
|
|
|
|
|
func hdrVersion(bs []byte) uint16 { return binary.LittleEndian.Uint16(bs[:2]) }
|
|
|
|
|
func hdrType(bs []byte) byte { return bs[2] }
|
|
|
|
|
func hdrLen(bs []byte) int { return int(binary.LittleEndian.Uint16(bs[3:5])) }
|
|
|
|
|
// headerLen is the size of the header on all messages except msgTypeInitiation.
|
|
|
|
|
headerLen = 3
|
|
|
|
|
// initiationHeaderLen is the size of the header on all msgTypeInitiation messages.
|
|
|
|
|
initiationHeaderLen = 5
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// initiationMessage is the protocol message sent from a client
|
|
|
|
|
// machine to a control server.
|
|
|
|
|
//
|
|
|
|
|
// 2b: protocol version
|
|
|
|
|
// 1b: message type (0x01)
|
|
|
|
|
// 2b: payload length (96)
|
|
|
|
|
// 5b: header (see headerLen for fields)
|
|
|
|
|
// 32b: client ephemeral public key (cleartext)
|
|
|
|
|
// 48b: client machine public key (encrypted)
|
|
|
|
@ -76,41 +41,48 @@ type initiationMessage [101]byte
|
|
|
|
|
|
|
|
|
|
func mkInitiationMessage() initiationMessage {
|
|
|
|
|
var ret initiationMessage
|
|
|
|
|
setHeader(ret[:], protocolVersion, msgTypeInitiation, len(ret.Payload()))
|
|
|
|
|
binary.BigEndian.PutUint16(ret[:2], uint16(protocolVersion))
|
|
|
|
|
ret[2] = msgTypeInitiation
|
|
|
|
|
binary.BigEndian.PutUint16(ret[3:5], uint16(len(ret.Payload())))
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *initiationMessage) Header() []byte { return m[:headerLen] }
|
|
|
|
|
func (m *initiationMessage) Payload() []byte { return m[headerLen:] }
|
|
|
|
|
func (m *initiationMessage) Header() []byte { return m[:initiationHeaderLen] }
|
|
|
|
|
func (m *initiationMessage) Payload() []byte { return m[initiationHeaderLen:] }
|
|
|
|
|
|
|
|
|
|
func (m *initiationMessage) Version() uint16 { return hdrVersion(m.Header()) }
|
|
|
|
|
func (m *initiationMessage) Type() byte { return hdrType(m.Header()) }
|
|
|
|
|
func (m *initiationMessage) Length() int { return hdrLen(m.Header()) }
|
|
|
|
|
func (m *initiationMessage) Version() uint16 { return binary.BigEndian.Uint16(m[:2]) }
|
|
|
|
|
func (m *initiationMessage) Type() byte { return m[2] }
|
|
|
|
|
func (m *initiationMessage) Length() int { return int(binary.BigEndian.Uint16(m[3:5])) }
|
|
|
|
|
|
|
|
|
|
func (m *initiationMessage) EphemeralPub() []byte { return m[headerLen : headerLen+32] }
|
|
|
|
|
func (m *initiationMessage) MachinePub() []byte { return m[headerLen+32 : headerLen+32+48] }
|
|
|
|
|
func (m *initiationMessage) Tag() []byte { return m[headerLen+32+48:] }
|
|
|
|
|
func (m *initiationMessage) EphemeralPub() []byte {
|
|
|
|
|
return m[initiationHeaderLen : initiationHeaderLen+32]
|
|
|
|
|
}
|
|
|
|
|
func (m *initiationMessage) MachinePub() []byte {
|
|
|
|
|
return m[initiationHeaderLen+32 : initiationHeaderLen+32+48]
|
|
|
|
|
}
|
|
|
|
|
func (m *initiationMessage) Tag() []byte { return m[initiationHeaderLen+32+48:] }
|
|
|
|
|
|
|
|
|
|
// responseMessage is the protocol message sent from a control server
|
|
|
|
|
// to a client machine.
|
|
|
|
|
//
|
|
|
|
|
// 5b: header (see headerLen for fields)
|
|
|
|
|
// 1b: message type (0x02)
|
|
|
|
|
// 2b: payload length (48)
|
|
|
|
|
// 32b: control ephemeral public key (cleartext)
|
|
|
|
|
// 16b: message tag (authenticates the whole message)
|
|
|
|
|
type responseMessage [53]byte
|
|
|
|
|
type responseMessage [51]byte
|
|
|
|
|
|
|
|
|
|
func mkResponseMessage() responseMessage {
|
|
|
|
|
var ret responseMessage
|
|
|
|
|
setHeader(ret[:], protocolVersion, msgTypeResponse, len(ret.Payload()))
|
|
|
|
|
ret[0] = msgTypeResponse
|
|
|
|
|
binary.BigEndian.PutUint16(ret[1:], uint16(len(ret.Payload())))
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *responseMessage) Header() []byte { return m[:headerLen] }
|
|
|
|
|
func (m *responseMessage) Payload() []byte { return m[headerLen:] }
|
|
|
|
|
|
|
|
|
|
func (m *responseMessage) Version() uint16 { return hdrVersion(m.Header()) }
|
|
|
|
|
func (m *responseMessage) Type() byte { return hdrType(m.Header()) }
|
|
|
|
|
func (m *responseMessage) Length() int { return hdrLen(m.Header()) }
|
|
|
|
|
func (m *responseMessage) Type() byte { return m[0] }
|
|
|
|
|
func (m *responseMessage) Length() int { return int(binary.BigEndian.Uint16(m[1:3])) }
|
|
|
|
|
|
|
|
|
|
func (m *responseMessage) EphemeralPub() []byte { return m[headerLen : headerLen+32] }
|
|
|
|
|
func (m *responseMessage) Tag() []byte { return m[headerLen+32:] }
|
|
|
|
|