OpenVPN 3 Core Library
Loading...
Searching...
No Matches
sess_cache.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
14#include <string>
15#include <map>
16#include <set>
17#include <tuple>
18#include <memory>
19#include <utility>
20
21#include <openssl/ssl.h>
22
23#include <openvpn/common/rc.hpp>
25
26namespace openvpn {
27
28// Client-side session cache.
29// (We don't cache server-side sessions because we use TLS
30// session resumption tickets which are stateless on the server).
31class OpenSSLSessionCache : public RC<thread_unsafe_refcount>
32{
33 public:
35
36 OPENVPN_EXCEPTION(openssl_sess_cache_error);
37
38 // Wrapper for OpenSSL SSL_SESSION pointers that manages reference counts.
39 class Session
40 {
41 public:
42 Session(::SSL_SESSION *sess) // caller must pre-increment refcount on sess
43 : sess_(sess)
44 {
45 }
46
47 Session(Session &&other) noexcept
48 {
49 sess_ = other.sess_;
50 other.sess_ = nullptr;
51 }
52
53 Session &operator=(Session &&other) noexcept
54 {
55 if (sess_)
56 ::SSL_SESSION_free(sess_);
57 sess_ = other.sess_;
58 other.sess_ = nullptr;
59 return *this;
60 }
61
62 ::SSL_SESSION *openssl_session() const
63 {
64 return sess_;
65 }
66
67 bool operator<(const Session &rhs) const // used when Session is a std::set key
68 {
69 return sess_ < rhs.sess_;
70 }
71
72 explicit operator bool() const
73 {
74 return sess_ != nullptr;
75 }
76
78 {
79 if (sess_)
80 ::SSL_SESSION_free(sess_);
81 }
82
83 private:
84 // These methods are deleted because we have no way to increment
85 // an SSL_SESSION refcount until OpenSSL 1.1.
86 Session(const Session &) = delete;
87 Session &operator=(const Session &) = delete;
88
89 ::SSL_SESSION *sess_;
90 };
91
92 class Key
93 {
94 public:
95 typedef std::unique_ptr<Key> UPtr;
96
97 Key(const std::string &key_arg,
99 : key(key_arg),
100 cache(std::move(cache_arg))
101 {
102 // OPENVPN_LOG("OpenSSLSessionCache::Key CONSTRUCT key=" << key);
103 }
104
105 void commit(::SSL_SESSION *sess)
106 {
107 if (!sess)
108 return;
109 auto mi = MSF::find(cache->map, key);
110 if (mi)
111 {
112 /* auto ins = */ mi->second.emplace(sess);
113 // OPENVPN_LOG("OpenSSLSessionCache::Key::commit ADD=" << ins.second << " key=" << key);
114 }
115 else
116 {
117 // OPENVPN_LOG("OpenSSLSessionCache::Key::commit CREATE key=" << key);
118 auto ins = cache->map.emplace(std::piecewise_construct,
119 std::forward_as_tuple(key),
120 std::forward_as_tuple());
121 ins.first->second.emplace(sess);
122 }
123 }
124
125 private:
126 const std::string key;
128 };
129
130 // Remove a session from the map after calling func() on it.
131 // This would be a lot cleaner if we had C++17 std::set::extract().
132 template <typename FUNC>
133 void extract(const std::string &key, FUNC func)
134 {
135 auto mi = MSF::find(map, key);
136 if (mi)
137 {
138 // OPENVPN_LOG("OpenSSLSessionCache::Key::lookup EXISTS key=" << key);
139 SessionSet &ss = mi->second;
140 if (ss.empty())
141 throw openssl_sess_cache_error("internal error: SessionSet is empty");
142 auto ssi = ss.begin();
143 try
144 {
145 func(ssi->openssl_session());
146 }
147 catch (...)
148 {
149 remove_session(mi, ss, ssi);
150 throw;
151 }
152 remove_session(mi, ss, ssi);
153 }
154 else
155 {
156 // OPENVPN_LOG("OpenSSLSessionCache::Key::lookup NOT_FOUND key=" << key);
157 }
158 }
159
160 private:
161 struct SessionSet : public std::set<Session>
162 {
163 };
164
165 typedef std::map<std::string, SessionSet> Map;
166
167 void remove_session(Map::iterator mi, SessionSet &ss, SessionSet::iterator ssi)
168 {
169 ss.erase(ssi);
170 if (ss.empty())
171 map.erase(mi);
172 }
173
175};
176
177} // namespace openvpn
Key(const std::string &key_arg, OpenSSLSessionCache::Ptr cache_arg)
std::unique_ptr< Key > UPtr
OpenSSLSessionCache::Ptr cache
void commit(::SSL_SESSION *sess)
Session & operator=(Session &&other) noexcept
Session & operator=(const Session &)=delete
::SSL_SESSION * openssl_session() const
bool operator<(const Session &rhs) const
Session(Session &&other) noexcept
Session(const Session &)=delete
std::map< std::string, SessionSet > Map
void remove_session(Map::iterator mi, SessionSet &ss, SessionSet::iterator ssi)
RCPtr< OpenSSLSessionCache > Ptr
void extract(const std::string &key, FUNC func)
OPENVPN_EXCEPTION(openssl_sess_cache_error)
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
auto find(MAP_SET &ms, const KEY &k)
Definition msfind.hpp:60
std::set< int > ssi