on master help sign in
adding in-memory TLS session manager.
commit2327c7e929b729cb8f74104e8711429163305bc0 authorKazu Yamamoto <kazu@iij.ad.jp> dateThu 29 Jun 2017, 12:46 (9 years ago) parent65f18a1
4 files changed+187
tls-session-manager/LICENSE+29 tls-session-manager/Network/TLS/SessionManager.hs+127 tls-session-manager/Setup.hs+2 tls-session-manager/tls-session-manager.cabal+29
tls-session-manager/LICENSEnew file+29
@@ -0,0 +1,29 @@
1+Copyright (c) 2017, IIJ Innovation Institute Inc.
2+All rights reserved.
3+
4+Redistribution and use in source and binary forms, with or without
5+modification, are permitted provided that the following conditions
6+are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+ * Redistributions in binary form must reproduce the above copyright
11+ notice, this list of conditions and the following disclaimer in
12+ the documentation and/or other materials provided with the
13+ distribution.
14+ * Neither the name of the copyright holders nor the names of its
15+ contributors may be used to endorse or promote products derived
16+ from this software without specific prior written permission.
17+
18+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+POSSIBILITY OF SUCH DAMAGE.
tls-session-manager/Network/TLS/SessionManager.hsnew file+127
@@ -0,0 +1,127 @@
1+{-# LANGUAGE BangPatterns #-}
2+
3+-- | In-memory TLS session manager.
4+--
5+-- * Limitation: you can set the maximum size of the session data database.
6+-- * Automatic pruning: old session data over their lifetime are pruned automatically.
7+-- * Replay resistance: each session data is used at most once to prevent replay attacks.
8+-- * Energy saving: no dedicate pruning thread is running when the size of session database is zero.
9+
10+module Network.TLS.SessionManager (
11+ Config(..)
12+ , defaultConfig
13+ , newSessionManager
14+ ) where
15+
16+import Control.Reaper
17+import Data.IORef
18+import Data.List (foldl')
19+import Data.OrdPSQ (OrdPSQ)
20+import qualified Data.OrdPSQ as Q
21+import Data.Time (UTCTime, NominalDiffTime, getCurrentTime, addUTCTime)
22+import Network.TLS (SessionID, SessionData, SessionManager(..))
23+
24+----------------------------------------------------------------
25+
26+-- | Configuration for session managers.
27+data Config = Config {
28+ -- | Ticket lifetime in seconds.
29+ ticketLifetime :: !Int
30+ -- | Pruning delay in seconds. This is set to 'reaperDelay'.
31+ , pruningDelay :: !Int
32+ -- | The limit size of session data entries.
33+ , dbMaxSize :: !Int
34+ }
35+
36+-- | Lifetime: 1 day , delay: 10 minutes, limit: 10,000 entries.
37+defaultConfig :: Config
38+defaultConfig = Config {
39+ ticketLifetime = 86400
40+ , pruningDelay = 6000
41+ , dbMaxSize = 10000
42+ }
43+
44+----------------------------------------------------------------
45+
46+type Value = (SessionData, IORef Availability)
47+type DB = OrdPSQ SessionID UTCTime Value
48+type Item = (SessionID, UTCTime, Value, Operation)
49+
50+data Operation = Add | Del
51+data Availability = Fresh | Used
52+
53+----------------------------------------------------------------
54+
55+-- | Creating a in-memory session manager.
56+newSessionManager :: Config -> IO SessionManager
57+newSessionManager conf = do
58+ let lifetime = fromIntegral $ ticketLifetime conf
59+ maxsiz = dbMaxSize conf
60+ reaper <- mkReaper defaultReaperSettings {
61+ reaperEmpty = Q.empty
62+ , reaperCons = cons maxsiz
63+ , reaperAction = clean
64+ , reaperNull = Q.null
65+ , reaperDelay = pruningDelay conf * 1000000
66+ }
67+ return SessionManager {
68+ sessionResume = resume reaper
69+ , sessionEstablish = establish reaper lifetime
70+ , sessionInvalidate = invalidate reaper
71+ }
72+
73+cons :: Int -> Item -> DB -> DB
74+cons lim (k,t,v,Add) db
75+ | Q.size db == lim = case Q.minView db of
76+ Nothing -> Q.insert k t v Q.empty -- not happens, just in case
77+ Just (_,_,_,db') -> Q.insert k t v db'
78+ | otherwise = Q.insert k t v db
79+cons _ (k,_,_,Del) db = Q.delete k db
80+
81+clean :: DB -> IO (DB -> DB)
82+clean olddb = do
83+ currentTime <- getCurrentTime
84+ let !pruned = snd $ Q.atMostView currentTime olddb
85+ return $ merge pruned
86+ where
87+ ins db (k,p,v) = Q.insert k p v db
88+ -- There is not 'merge' API.
89+ -- We hope that newdb is smaller than pruned.
90+ merge pruned newdb = foldl' ins pruned entries
91+ where
92+ entries = Q.toList newdb
93+
94+----------------------------------------------------------------
95+
96+establish :: Reaper DB Item -> NominalDiffTime
97+ -> SessionID -> SessionData -> IO ()
98+establish reaper lifetime k sd = do
99+ ref <- newIORef Fresh
100+ !p <- addUTCTime lifetime <$> getCurrentTime
101+ let !v = (sd,ref)
102+ reaperAdd reaper (k,p,v,Add)
103+
104+resume :: Reaper DB Item
105+ -> SessionID -> IO (Maybe SessionData)
106+resume reaper k = do
107+ db <- reaperRead reaper
108+ case Q.lookup k db of
109+ Nothing -> return Nothing
110+ Just (p,v@(sd,ref)) -> do
111+ available <- atomicModifyIORef' ref check
112+ reaperAdd reaper (k,p,v,Del)
113+ return $ if available then Just sd else Nothing
114+ where
115+ check Fresh = (Used,True)
116+ check Used = (Used,False)
117+
118+invalidate :: Reaper DB Item
119+ -> SessionID -> IO ()
120+invalidate reaper k = do
121+ -- repaerDelete does not exist
122+ -- So, let's set the entry used and hope that it will be
123+ -- cleaned in the future.
124+ db <- reaperRead reaper
125+ case Q.lookup k db of
126+ Nothing -> return ()
127+ Just (_,(_,ref)) -> atomicModifyIORef' ref $ \_ -> (Used, ())
tls-session-manager/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
tls-session-manager/tls-session-manager.cabalnew file+29
@@ -0,0 +1,29 @@
1+-- Initial tls-session-manager.cabal generated by cabal init. For further
2+-- documentation, see http://haskell.org/cabal/users-guide/
3+
4+name: tls-session-manager
5+version: 0.0.0.0
6+synopsis: In-memory TLS session manager
7+description: TLS session manager with limitation, automatic pruning, replay resistance and energy saving
8+license: BSD3
9+license-file: LICENSE
10+author: Kazu Yamamoto
11+maintainer: kazu@iij.ad.jp
12+-- copyright:
13+category: Web
14+build-type: Simple
15+extra-source-files: ChangeLog.md
16+cabal-version: >= 1.10
17+
18+library
19+ exposed-modules: Network.TLS.SessionManager
20+ -- other-modules:
21+ -- other-extensions:
22+ build-depends: base >= 4.9 && < 5
23+ , auto-update
24+ , time
25+ , tls
26+ , psqueues
27+ -- hs-source-dirs:
28+ default-language: Haskell2010
29+ ghc-options: -Wall