Tapir provides a framework for building Anonymous / metadata resistant Services
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

service.go 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package tapir
  2. import (
  3. "crypto/rand"
  4. "cwtch.im/tapir/primitives"
  5. "encoding/binary"
  6. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  7. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  8. "golang.org/x/crypto/ed25519"
  9. "golang.org/x/crypto/nacl/secretbox"
  10. "io"
  11. "sync"
  12. )
  13. // Service defines the interface for a Tapir Service
  14. type Service interface {
  15. Init(acn connectivity.ACN, privateKey ed25519.PrivateKey, identity *primitives.Identity)
  16. Connect(hostname string, application Application) (bool, error)
  17. Listen(application Application) error
  18. GetConnection(connectionID string) (Connection, error)
  19. WaitForCapabilityOrClose(connectionID string, capability Capability) (Connection, error)
  20. Shutdown()
  21. }
  22. // Connection Interface
  23. type Connection interface {
  24. Hostname() string
  25. IsOutbound() bool
  26. ID() *primitives.Identity
  27. Expect() []byte
  28. SetHostname(hostname string)
  29. HasCapability(name Capability) bool
  30. SetCapability(name Capability)
  31. SetEncryptionKey(key [32]byte)
  32. Send(message []byte)
  33. Close()
  34. App() Application
  35. SetApp(application Application)
  36. IsClosed() bool
  37. }
  38. // Connection defines a Tapir Connection
  39. type connection struct {
  40. hostname string
  41. conn io.ReadWriteCloser
  42. capabilities sync.Map
  43. encrypted bool
  44. key [32]byte
  45. app Application
  46. identity *primitives.Identity
  47. outbound bool
  48. closed bool
  49. MaxLength int
  50. lock sync.Mutex
  51. }
  52. // NewConnection creates a new Connection
  53. func NewConnection(id *primitives.Identity, hostname string, outbound bool, conn io.ReadWriteCloser, app Application) Connection {
  54. connection := new(connection)
  55. connection.hostname = hostname
  56. connection.conn = conn
  57. connection.app = app
  58. connection.identity = id
  59. connection.outbound = outbound
  60. connection.MaxLength = 1024
  61. go connection.app.Init(connection)
  62. return connection
  63. }
  64. // ID returns an identity.Identity encapsulation (for the purposes of cryptographic protocols)
  65. func (c *connection) ID() *primitives.Identity {
  66. return c.identity
  67. }
  68. // App returns the overarching application using this Connection.
  69. func (c *connection) App() Application {
  70. c.lock.Lock()
  71. defer c.lock.Unlock()
  72. return c.app
  73. }
  74. // App returns the overarching application using this Connection.
  75. func (c *connection) SetApp(application Application) {
  76. c.lock.Lock()
  77. defer c.lock.Unlock()
  78. c.app = application
  79. }
  80. // Hostname returns the hostname of the connection (if the connection has not been authorized it will return the
  81. // temporary hostname identifier)
  82. func (c *connection) Hostname() string {
  83. c.lock.Lock()
  84. defer c.lock.Unlock()
  85. return c.hostname
  86. }
  87. // IsOutbound returns true if this caller was the originator of the connection (i.e. the connection was started
  88. // by calling Connect() rather than Accept()
  89. func (c *connection) IsOutbound() bool {
  90. return c.outbound
  91. }
  92. // IsClosed returns true if the connection is closed (connections cannot be reopened)
  93. func (c *connection) IsClosed() bool {
  94. c.lock.Lock()
  95. defer c.lock.Unlock()
  96. return c.closed
  97. }
  98. // SetHostname sets the hostname on the connection
  99. func (c *connection) SetHostname(hostname string) {
  100. c.lock.Lock()
  101. defer c.lock.Unlock()
  102. log.Debugf("[%v -- %v] Asserting Remote Hostname: %v", c.identity.Hostname(), c.hostname, hostname)
  103. c.hostname = hostname
  104. }
  105. // SetCapability sets a capability on the connection
  106. func (c *connection) SetCapability(name Capability) {
  107. log.Debugf("[%v -- %v] Setting Capability %v", c.identity.Hostname(), c.hostname, name)
  108. c.capabilities.Store(name, true)
  109. }
  110. // HasCapability checks if the connection has a given capability
  111. func (c *connection) HasCapability(name Capability) bool {
  112. _, ok := c.capabilities.Load(name)
  113. return ok
  114. }
  115. // Close forcibly closes the connection
  116. func (c *connection) Close() {
  117. c.lock.Lock()
  118. defer c.lock.Unlock()
  119. c.closed = true
  120. c.conn.Close()
  121. }
  122. // Expect blocks and reads a single Tapir packet , from the connection.
  123. func (c *connection) Expect() []byte {
  124. buffer := make([]byte, c.MaxLength)
  125. n, err := io.ReadFull(c.conn, buffer)
  126. if n != c.MaxLength || err != nil {
  127. log.Errorf("[%v -> %v] Wire Error Reading, Read %d bytes, Error: %v", c.hostname, c.identity.Hostname(), n, err)
  128. c.conn.Close()
  129. c.closed = true
  130. return []byte{}
  131. }
  132. c.lock.Lock()
  133. defer c.lock.Unlock()
  134. if c.encrypted {
  135. var decryptNonce [24]byte
  136. copy(decryptNonce[:], buffer[:24])
  137. decrypted, ok := secretbox.Open(nil, buffer[24:], &decryptNonce, &c.key)
  138. if ok {
  139. copy(buffer, decrypted)
  140. } else {
  141. log.Errorf("[%v -> %v] Error Decrypting Message On Wire", c.hostname, c.identity.Hostname())
  142. c.conn.Close()
  143. c.closed = true
  144. return []byte{}
  145. }
  146. }
  147. length, _ := binary.Uvarint(buffer[0:2])
  148. if length+2 >= uint64(c.MaxLength) {
  149. return []byte{}
  150. }
  151. //cplog.Debugf("[%v -> %v] Wire Receive: (%d) %x", c.hostname, c.ID.Hostname(), len, buffer)
  152. return buffer[2 : length+2]
  153. }
  154. // SetEncryptionKey turns on application-level encryption on the connection using the given key.
  155. func (c *connection) SetEncryptionKey(key [32]byte) {
  156. c.lock.Lock()
  157. defer c.lock.Unlock()
  158. c.key = key
  159. c.encrypted = true
  160. }
  161. // Send writes a given message to a Tapir packet (of 1024 bytes in length).
  162. func (c *connection) Send(message []byte) {
  163. buffer := make([]byte, c.MaxLength)
  164. binary.PutUvarint(buffer[0:2], uint64(len(message)))
  165. copy(buffer[2:], message)
  166. c.lock.Lock()
  167. defer c.lock.Unlock()
  168. if c.encrypted {
  169. var nonce [24]byte
  170. if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
  171. log.Errorf("Could not read sufficient randomness %v. Closing connection", err)
  172. c.conn.Close()
  173. c.closed = true
  174. }
  175. // MaxLength - 40 = MaxLength - 24 nonce bytes and 16 auth tag.
  176. encrypted := secretbox.Seal(nonce[:], buffer[0:c.MaxLength-40], &nonce, &c.key)
  177. copy(buffer, encrypted[0:c.MaxLength])
  178. }
  179. log.Debugf("[%v -> %v] Wire Send %x", c.identity.Hostname(), c.hostname, buffer)
  180. _, err := c.conn.Write(buffer)
  181. if err != nil {
  182. c.conn.Close()
  183. c.closed = true
  184. }
  185. }