-- |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
      Identity(..)
    , PeerIdentity
    , LocalIdentity

    , toPeerIdentity
    , newLocalIdentity

      -- * Communicating

      -- ** Connecting to peers
    , connect

      -- ** Accepting connections from peers
    , Socket
    , newServer
    , accept

      -- ** Talking to connected peers
    , Connection
    , peer  
    , read
    , readPtr
    , write
    , writePtr
    , 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
-- >   writeIdentity 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" >>= readIdentity
-- >   writeIdentity (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" >>= readIdentity
-- >   you    <- readFile "b.pub" >>= readIdentity
-- >   server <- newServer (Nothing, "4242")
-- >   conn   <- accept me [you] server
--
-- Then, another host needs to connect.
--
-- > do
-- >   me   <- readFile "b.key" >>= readIdentity
-- >   you  <- readFile "a.pub" >>= readIdentity
-- >   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 128 >>= putStrLn
-- >   close conn
--
-- N.B. The program should start with 'withOpenSSL' in order to initialize SSL
-- (@main = withOpenSSL $ do@).

-- $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.
