-- |This library simplifies the task of securely connecting two
-- servers to each other. It closely mimicks the regular socket API,
-- and adds the concept of identity: each communicating server has an
-- identity, and connections can only be established between two
-- servers who know each other and expect to be communicating.
--
-- Under the hood, the library takes care of strongly authenticating
-- the connection, and of encrypting all traffic. If you successfully
-- establish a connection using this library, you have the guarantee
-- that the connection is secure.
{-# LANGUAGE NoImplicitPrelude #-}
module Network.Secure
(
-- * Tutorial
-- $tutorial
-- * Internals and caveats
-- $internals
-- * Managing identities
-- ** Authenticating peers
PeerIdentity
, writePeerIdentity
, readPeerIdentity
-- ** Authenticating to peers
, LocalIdentity
, writeLocalIdentity
, readLocalIdentity
, toPeerIdentity
, newLocalIdentity
-- * Communicating
-- ** Connecting to peers
, connect
-- ** Accepting connections from peers
, Socket
, newServer
, accept
-- ** Talking to connected peers
, Connection
, peer
, read
, write
, close
-- ** Misc reexports from 'Network.Socket'
, HostName
, ServiceName
) where
import Network.Secure.Connection
import Network.Secure.Identity
-- $tutorial
--
-- First, each host needs to generate a local identity for itself. A
-- local identity allows a server to authenticate itself to remote
-- peers.
--
-- > do
-- > id <- newLocalIdentity "server1.domain.com" 365
-- > writeLocalIdentity id >>= writeFile "server.key"
--
-- The name is not used at all by the library, it just allows you to
-- identify the key later on if you need to.
--
-- This identity contains secret key material that only the generating
-- host should have. From this, we need to generate a public identity
-- that can be given to other hosts.
--
-- > do
-- > id <- readFile "server.key" >>= readLocalIdentity
-- > writePeerIdentity (toPeerIdentity id) >>= writeFile "server.pub"
--
-- This public file should be distributed to the servers with whom you
-- want to communicate. Once everyone has the public identities of
-- their peers, we can start connecting. First, one host needs to
-- start listening for connections.
--
-- > do
-- > me <- readFile "a.key" >>= readLocalIdentity
-- > you <- readFile "b.pub" >>= readPeerIdentity
-- > server <- newServer (Nothing, "4242")
-- > conn <- accept me [you] server
--
-- Then, another host needs to connect.
--
-- > do
-- > me <- readFile "b.key" >>= readLocalIdentity
-- > you <- readFile "a.pub" >>= readPeerIdentity
-- > conn <- connect me you ("a.com", "4242")
--
-- Et voila! From there on, you can communicate using the usual
-- socket-ish API:
--
-- > do
-- > write conn "hello?"
-- > read conn >>= putStrLn
-- > close conn
-- $internals
--
-- Note that this section gives out internal implementation details
-- which are subject to change! Compatibility breakages will be
-- indicated by appropriate version number bumps for the package, and
-- the internal details of new versions may bear no resemblance
-- whatsoever to the old version.
--
-- The current implementation uses OpenSSL (via HsOpenSSL) for
-- transport security, with the @AES256-SHA@ ciphersuite and 4096 bit
-- RSA keys.
--
-- Due to a current limitation of the HsOpenSSL API, we do not use a
-- ciphersuite that makes use of ephemeral keys for encryption. The
-- consequence is that connections established with this library do
-- not provide perfect forward secrecy.
--
-- That is, if an attacker can compromise the private keys of the
-- communicating servers, she can decrypt all past communications that
-- she has recorded.
--
-- This shortcoming will be fixed at some point, either by adding
-- Diffie-Hellman keying support to HsOpenSSL, or by switching to a
-- different underlying implementation.