payload.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package handshake
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "math"
  6. "slices"
  7. "google.golang.org/protobuf/encoding/protowire"
  8. )
  9. var (
  10. errInvalidHandshakeMessage = errors.New("invalid handshake message")
  11. errInvalidHandshakeDetails = errors.New("invalid handshake details")
  12. )
  13. // Payload represents the decoded fields of a handshake message.
  14. // Wire format is protobuf-compatible with NebulaHandshake{Details: NebulaHandshakeDetails{...}}.
  15. type Payload struct {
  16. Cert []byte
  17. InitiatorIndex uint32
  18. ResponderIndex uint32
  19. Time uint64
  20. CertVersion uint32
  21. }
  22. // Proto field numbers for NebulaHandshakeDetails
  23. const (
  24. fieldCert = 1 // bytes
  25. fieldInitiatorIndex = 2 // uint32
  26. fieldResponderIndex = 3 // uint32
  27. fieldTime = 5 // uint64
  28. fieldCertVersion = 8 // uint32
  29. )
  30. // MarshalPayload encodes a handshake payload in protobuf wire format compatible
  31. // with NebulaHandshake{Details: NebulaHandshakeDetails{...}}.
  32. // Returns out (which may be nil), with the marshalled Payload appended to it.
  33. func MarshalPayload(out []byte, p Payload) []byte {
  34. // Everything but the certificate fits on the stack, which leaves the
  35. // certificate the only variable size and out grown just once.
  36. var scalars [4 * (1 + binary.MaxVarintLen64)]byte
  37. rest := scalars[:0]
  38. if p.InitiatorIndex != 0 {
  39. rest = protowire.AppendTag(rest, fieldInitiatorIndex, protowire.VarintType)
  40. rest = protowire.AppendVarint(rest, uint64(p.InitiatorIndex))
  41. }
  42. if p.ResponderIndex != 0 {
  43. rest = protowire.AppendTag(rest, fieldResponderIndex, protowire.VarintType)
  44. rest = protowire.AppendVarint(rest, uint64(p.ResponderIndex))
  45. }
  46. if p.Time != 0 {
  47. rest = protowire.AppendTag(rest, fieldTime, protowire.VarintType)
  48. rest = protowire.AppendVarint(rest, p.Time)
  49. }
  50. if p.CertVersion != 0 {
  51. rest = protowire.AppendTag(rest, fieldCertVersion, protowire.VarintType)
  52. rest = protowire.AppendVarint(rest, uint64(p.CertVersion))
  53. }
  54. detailsLen := len(rest)
  55. if len(p.Cert) > 0 {
  56. detailsLen += protowire.SizeTag(fieldCert) + protowire.SizeBytes(len(p.Cert))
  57. }
  58. out = slices.Grow(out, protowire.SizeTag(1)+protowire.SizeBytes(detailsLen))
  59. out = protowire.AppendTag(out, 1, protowire.BytesType)
  60. out = protowire.AppendVarint(out, uint64(detailsLen))
  61. if len(p.Cert) > 0 {
  62. out = protowire.AppendTag(out, fieldCert, protowire.BytesType)
  63. out = protowire.AppendBytes(out, p.Cert)
  64. }
  65. return append(out, rest...)
  66. }
  67. // UnmarshalPayload decodes a protobuf-encoded NebulaHandshake message. The
  68. // returned Cert aliases b.
  69. func UnmarshalPayload(b []byte) (Payload, error) {
  70. var p Payload
  71. for len(b) > 0 {
  72. num, typ, n := protowire.ConsumeTag(b)
  73. if n < 0 {
  74. return p, errInvalidHandshakeMessage
  75. }
  76. b = b[n:]
  77. switch {
  78. case num == 1 && typ == protowire.BytesType:
  79. details, n := protowire.ConsumeBytes(b)
  80. if n < 0 {
  81. return p, errInvalidHandshakeMessage
  82. }
  83. b = b[n:]
  84. if err := unmarshalPayloadDetails(&p, details); err != nil {
  85. return p, err
  86. }
  87. default:
  88. n := protowire.ConsumeFieldValue(num, typ, b)
  89. if n < 0 {
  90. return p, errInvalidHandshakeMessage
  91. }
  92. b = b[n:]
  93. }
  94. }
  95. return p, nil
  96. }
  97. func unmarshalPayloadDetails(p *Payload, b []byte) error {
  98. for len(b) > 0 {
  99. num, typ, n := protowire.ConsumeTag(b)
  100. if n < 0 {
  101. return errInvalidHandshakeDetails
  102. }
  103. b = b[n:]
  104. // For known field numbers, reject any non-matching wire type as a
  105. // hard error rather than silently skipping. The caller will catch
  106. // missing-field cases downstream, but a wire-type mismatch on a tag
  107. // we know is a peer protocol violation worth flagging here.
  108. // Repeated occurrences of a singular field follow proto3 last-wins.
  109. switch num {
  110. case fieldCert:
  111. if typ != protowire.BytesType {
  112. return errInvalidHandshakeDetails
  113. }
  114. v, n := protowire.ConsumeBytes(b)
  115. if n < 0 {
  116. return errInvalidHandshakeDetails
  117. }
  118. p.Cert = v
  119. b = b[n:]
  120. case fieldInitiatorIndex:
  121. if typ != protowire.VarintType {
  122. return errInvalidHandshakeDetails
  123. }
  124. v, n := protowire.ConsumeVarint(b)
  125. if n < 0 || v > math.MaxUint32 {
  126. return errInvalidHandshakeDetails
  127. }
  128. p.InitiatorIndex = uint32(v)
  129. b = b[n:]
  130. case fieldResponderIndex:
  131. if typ != protowire.VarintType {
  132. return errInvalidHandshakeDetails
  133. }
  134. v, n := protowire.ConsumeVarint(b)
  135. if n < 0 || v > math.MaxUint32 {
  136. return errInvalidHandshakeDetails
  137. }
  138. p.ResponderIndex = uint32(v)
  139. b = b[n:]
  140. case fieldTime:
  141. if typ != protowire.VarintType {
  142. return errInvalidHandshakeDetails
  143. }
  144. v, n := protowire.ConsumeVarint(b)
  145. if n < 0 {
  146. return errInvalidHandshakeDetails
  147. }
  148. p.Time = v
  149. b = b[n:]
  150. case fieldCertVersion:
  151. if typ != protowire.VarintType {
  152. return errInvalidHandshakeDetails
  153. }
  154. v, n := protowire.ConsumeVarint(b)
  155. if n < 0 || v > math.MaxUint32 {
  156. return errInvalidHandshakeDetails
  157. }
  158. p.CertVersion = uint32(v)
  159. b = b[n:]
  160. default:
  161. n := protowire.ConsumeFieldValue(num, typ, b)
  162. if n < 0 {
  163. return errInvalidHandshakeDetails
  164. }
  165. b = b[n:]
  166. }
  167. }
  168. return nil
  169. }