payload.go 4.6 KB

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