185 lines
7.6 KiB
Markdown
185 lines
7.6 KiB
Markdown
# Tapir
|
|
|
|
Designed to replace the old protobuf-based ricochet channels, Tapir provides a
|
|
framework for building anonymous applications.
|
|
|
|
It is divided into a number of layers:
|
|
|
|
* Identity - An ed25519 keypair, required for established a Tor v3 onion service
|
|
and used to maintain a consistent cryptographic identity for a peer.
|
|
* Connections - The raw networking protocol that connects two peers. Connections
|
|
are so far only defined over Tor v3 Onion Services (see: [connectivity](./connectivity.md))
|
|
* Applications - The various logic that enables a particular information flow
|
|
over a connection. Examples include shared cryptographic transcripts
|
|
, authentication, spam guards and token based services. Applications provide
|
|
**Capabilities** which can be referenced by other applications to determine if
|
|
a given peer has the ability to use a given hosted application.
|
|
* Application Stacks - A mechanism for connecting more than one application
|
|
together, e.g. authentication depends on a shared cryptographic transcript
|
|
, and the main [cwtch](./cwtch.md) peer app is based on the authentication
|
|
application.
|
|
|
|
## Primitives
|
|
|
|
### Identity
|
|
|
|
An ed25519 keypair, required for established a Tor v3 onion service
|
|
and used to maintain a consistent cryptographic identity for a peer.
|
|
|
|
* InitializeIdentity - from a known, persistent keypair: \\(i,I\\)
|
|
* InitializeEphemeralIdentity - from a random keypair: \\(i_e, I_e\\)
|
|
|
|
## Applications
|
|
|
|
### Transcript App
|
|
|
|
**Dependencies:** None
|
|
|
|
Initializes a [Merlin](https://merlin.cool)-based cryptographic transcript that
|
|
can be used as the basis of higher level commitment-based protocols
|
|
|
|
Transcript app will panic if an app ever tries to overwrite an existing
|
|
transcript with a new one (enforcing the rule that a session is based on
|
|
one, and only one, transcript.)
|
|
|
|
### Authentication App
|
|
|
|
* **Dependencies**: Transcript App
|
|
* **Capabilities Granted**: *AuthenticationCapability*
|
|
* **Capabilities Required**: *None*
|
|
|
|
Engages in an [ephemeral triple-diffie-hellman handshake](./authentication_protocol.md) to derive a unique,
|
|
authenticated session key.
|
|
|
|
|
|
|
|
### transcript.Commit()
|
|
|
|
The merlin transcript derived challenge is based on all the messages sent in
|
|
the auth flow (and any that were sent prior to the Auth App)
|
|
|
|
// Derive a challenge from the transcript of the public parameters of this authentication protocol
|
|
transcript := ea.Transcript()
|
|
transcript.NewProtocol("auth-app")
|
|
transcript.AddToTranscript("outbound-hostname", []byte(outboundHostname))
|
|
transcript.AddToTranscript("inbound-hostname", []byte(inboundHostname))
|
|
transcript.AddToTranscript("outbound-challenge", outboundAuthMessage)
|
|
transcript.AddToTranscript("inbound-challenge", inboundAuthMessage)
|
|
challengeBytes := transcript.CommitToTranscript("3dh-auth-challenge")
|
|
|
|
#### Asymmetry
|
|
|
|
The client connection is guaranteed to possess the long term identity of the
|
|
server connection through the properties of the underlying tor v3 onion
|
|
connection.
|
|
|
|
As such if the server attempts to send a different long term identity to the
|
|
client we can detect it and terminate the authentication protocol early.
|
|
|
|
|
|
### Token App
|
|
|
|
**Dependencies:** Transcript App
|
|
* **Capabilities Granted**: *HasTokensCapability*
|
|
* **Capabilities Required**: *None* (implicitly guarded)
|
|
|
|
Allows the client to obtain signed, blinded tokens for use in another
|
|
application.
|
|
|
|
While this application has no explicit requirement for any given capability,
|
|
we expect it to be protected via a preceeding app in an `ApplicationChain` e.g.
|
|
|
|
powTokenApp := new(applications.ApplicationChain).
|
|
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
|
|
ChainApplication(tokenApplication, applications.HasTokensCapability)
|
|
|
|
|
|
#### Notes
|
|
|
|
* No direct testing (tested via integration tests and unit tests)
|
|
|
|
### Ephemeral Connections
|
|
|
|
Occasionally it is desirable to have a peer conenct to another / a service
|
|
without using their long term identity (e.g. in the case of connecting to
|
|
a Cwtch Server).
|
|
|
|
In this case we want to enable a convenient way to allow connecting with an
|
|
ephemeral identity.
|
|
|
|
It turns out that doing this securely requires maintaining a completely separate
|
|
set of connections and applications in order to avoid side channel around avoid
|
|
duplicate connections (i.e. if we did mix them up then a service might be able
|
|
to exploit the fact that clients avid duplicate connections by attempting to
|
|
connect to known-online peers and observing if they reject the connection
|
|
because they already have an outbound ephemeral connection open.)
|
|
|
|
Because of this, we don't provide an explicit Ephemeral Connect api and instead
|
|
recommend that peers maintain one long term service and multiple ephemeral
|
|
services.
|
|
|
|
## Known Risks
|
|
|
|
### Impersonation of Peers
|
|
|
|
**Status: Mitigated**
|
|
|
|
By default, tor v3 onion services only provide one-way authentication, that
|
|
is the client can verify a metadata resistant connection to the server by the
|
|
server obtained no information about the client.
|
|
|
|
Tapir provides a peer-to-peer interface over this client-server structure
|
|
through the [Authentication application](https://git.openprivacy.ca/cwtch.im/tapir/src/branch/master/applications/auth.go).
|
|
|
|
The Authentication application implements a 3-way, ephemeral diffie-hellman
|
|
handshake to generate a shared session key. Once generated this session key is
|
|
used to encrypt *all* traffic between the two peers for the duration of the
|
|
session.
|
|
|
|
The session key is used to encrypt a challenge derived from the shared
|
|
cryptographic transcript (based on [merlin](https://merlin.cool))
|
|
|
|
Only if all the above checks pass is the connection maintained open - otherwise
|
|
the peer that detects a failure closes the connection.
|
|
|
|
### Double Connections
|
|
|
|
**Status: Mitigated**
|
|
|
|
Because of the one-way authentication provided by Tor onion services there is a
|
|
window between connection instantiation and the finalization of authentication
|
|
when two valid connections can occur between the same two peers.
|
|
|
|
While these vestigial connections are not harmful, they do have the potential to
|
|
confuse users and interfaces. To avoid ambiguity Tapir attempt to detect and
|
|
close duplicate connections through a number of rules:
|
|
|
|
1. If a connection open is attempted to a hostname that
|
|
already has an open connection the connection attempt is aborted.
|
|
2. After authentication the lookup happens again, and if another connection is
|
|
found the newest connection is closed.
|
|
|
|
There is a small chance both peers will close their initiated connections
|
|
if they also happen to start the connection attempt at exactly the sametime
|
|
. This should be exceedingly rare in practice, and is further mitigated by
|
|
an exponential backoff of connection retries by the [ui](./ui.md)
|
|
|
|
Finally, the Tapir interfaces `WaitForCapabilityOrClose` and `GetConnection` are
|
|
aware of the potential for duplicate connections and have logic that allows the
|
|
handling of such instances (such as returning an error when they are found
|
|
allowing a handling application to retry the request if a connection with a
|
|
given capability isn't returned)
|
|
|
|
## Testing Status
|
|
|
|
Tapir features a number of well-defined integration tests which exercise not
|
|
only the ideal case of two well-formed peers authenticating and messaging each
|
|
other, but also a malicious peer attempting to bypass authentication.
|
|
|
|
In addition, unit tests are defined for a number of the specified
|
|
applications (including Authentication) and many of the
|
|
cryptographic primitives.
|
|
|
|
All tests are also run with the `-race` flag which will cause them to fail if
|
|
race conditions are detected. Both integration tests and unit tests are run
|
|
automatically for every pull request and main branch merge. |