| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package handshake
- import (
- "errors"
- "math"
- "google.golang.org/protobuf/encoding/protowire"
- )
- var (
- errInvalidHandshakeMessage = errors.New("invalid handshake message")
- errInvalidHandshakeDetails = errors.New("invalid handshake details")
- )
- // Payload represents the decoded fields of a handshake message.
- // Wire format is protobuf-compatible with NebulaHandshake{Details: NebulaHandshakeDetails{...}}.
- type Payload struct {
- Cert []byte
- InitiatorIndex uint32
- ResponderIndex uint32
- Time uint64
- CertVersion uint32
- }
- // Proto field numbers for NebulaHandshakeDetails
- const (
- fieldCert = 1 // bytes
- fieldInitiatorIndex = 2 // uint32
- fieldResponderIndex = 3 // uint32
- fieldTime = 5 // uint64
- fieldCertVersion = 8 // uint32
- )
- // MarshalPayload encodes a handshake payload in protobuf wire format compatible
- // with NebulaHandshake{Details: NebulaHandshakeDetails{...}}.
- // Returns out (which may be nil), with the marshalled Payload appended to it.
- func MarshalPayload(out []byte, p Payload) []byte {
- var details []byte
- if len(p.Cert) > 0 {
- details = protowire.AppendTag(details, fieldCert, protowire.BytesType)
- details = protowire.AppendBytes(details, p.Cert)
- }
- if p.InitiatorIndex != 0 {
- details = protowire.AppendTag(details, fieldInitiatorIndex, protowire.VarintType)
- details = protowire.AppendVarint(details, uint64(p.InitiatorIndex))
- }
- if p.ResponderIndex != 0 {
- details = protowire.AppendTag(details, fieldResponderIndex, protowire.VarintType)
- details = protowire.AppendVarint(details, uint64(p.ResponderIndex))
- }
- if p.Time != 0 {
- details = protowire.AppendTag(details, fieldTime, protowire.VarintType)
- details = protowire.AppendVarint(details, p.Time)
- }
- if p.CertVersion != 0 {
- details = protowire.AppendTag(details, fieldCertVersion, protowire.VarintType)
- details = protowire.AppendVarint(details, uint64(p.CertVersion))
- }
- out = protowire.AppendTag(out, 1, protowire.BytesType)
- out = protowire.AppendBytes(out, details)
- return out
- }
- // UnmarshalPayload decodes a protobuf-encoded NebulaHandshake message.
- func UnmarshalPayload(b []byte) (Payload, error) {
- var p Payload
- for len(b) > 0 {
- num, typ, n := protowire.ConsumeTag(b)
- if n < 0 {
- return p, errInvalidHandshakeMessage
- }
- b = b[n:]
- switch {
- case num == 1 && typ == protowire.BytesType:
- details, n := protowire.ConsumeBytes(b)
- if n < 0 {
- return p, errInvalidHandshakeMessage
- }
- b = b[n:]
- if err := unmarshalPayloadDetails(&p, details); err != nil {
- return p, err
- }
- default:
- n := protowire.ConsumeFieldValue(num, typ, b)
- if n < 0 {
- return p, errInvalidHandshakeMessage
- }
- b = b[n:]
- }
- }
- return p, nil
- }
- func unmarshalPayloadDetails(p *Payload, b []byte) error {
- for len(b) > 0 {
- num, typ, n := protowire.ConsumeTag(b)
- if n < 0 {
- return errInvalidHandshakeDetails
- }
- b = b[n:]
- // For known field numbers, reject any non-matching wire type as a
- // hard error rather than silently skipping. The caller will catch
- // missing-field cases downstream, but a wire-type mismatch on a tag
- // we know is a peer protocol violation worth flagging here.
- // Repeated occurrences of a singular field follow proto3 last-wins.
- switch num {
- case fieldCert:
- if typ != protowire.BytesType {
- return errInvalidHandshakeDetails
- }
- v, n := protowire.ConsumeBytes(b)
- if n < 0 {
- return errInvalidHandshakeDetails
- }
- p.Cert = append([]byte(nil), v...)
- b = b[n:]
- case fieldInitiatorIndex:
- if typ != protowire.VarintType {
- return errInvalidHandshakeDetails
- }
- v, n := protowire.ConsumeVarint(b)
- if n < 0 || v > math.MaxUint32 {
- return errInvalidHandshakeDetails
- }
- p.InitiatorIndex = uint32(v)
- b = b[n:]
- case fieldResponderIndex:
- if typ != protowire.VarintType {
- return errInvalidHandshakeDetails
- }
- v, n := protowire.ConsumeVarint(b)
- if n < 0 || v > math.MaxUint32 {
- return errInvalidHandshakeDetails
- }
- p.ResponderIndex = uint32(v)
- b = b[n:]
- case fieldTime:
- if typ != protowire.VarintType {
- return errInvalidHandshakeDetails
- }
- v, n := protowire.ConsumeVarint(b)
- if n < 0 {
- return errInvalidHandshakeDetails
- }
- p.Time = v
- b = b[n:]
- case fieldCertVersion:
- if typ != protowire.VarintType {
- return errInvalidHandshakeDetails
- }
- v, n := protowire.ConsumeVarint(b)
- if n < 0 || v > math.MaxUint32 {
- return errInvalidHandshakeDetails
- }
- p.CertVersion = uint32(v)
- b = b[n:]
- default:
- n := protowire.ConsumeFieldValue(num, typ, b)
- if n < 0 {
- return errInvalidHandshakeDetails
- }
- b = b[n:]
- }
- }
- return nil
- }
|