OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tlsprf.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// Implement the TLS-PRF function, used by ProtoContext.
13
14#ifndef OPENVPN_SSL_TLSPRF_H
15#define OPENVPN_SSL_TLSPRF_H
16
17#include <cstring> // for std::strlen and others
18
19#include <string>
20#include <sstream>
21
24#include <openvpn/common/rc.hpp>
31#include <openvpn/ssl/psid.hpp>
33
34namespace openvpn {
35
36template <typename CRYPTO_API>
37class TLSPRF
38{
39 public:
40 OPENVPN_SIMPLE_EXCEPTION(tlsprf_uninitialized);
41 OPENVPN_SIMPLE_EXCEPTION(tlsprf_client_server_mismatch);
42 OPENVPN_SIMPLE_EXCEPTION(tlsprf_tlsprf_failed);
43 enum
44 {
46 };
47
48 TLSPRF(const bool server)
49 : initialized_(false), server_(server)
50 {
51 }
52
54 {
55 if (!server_)
56 rng.rand_bytes(pre_master, sizeof(pre_master));
57 rng.rand_bytes(random1, sizeof(random1));
58 rng.rand_bytes(random2, sizeof(random2));
59 initialized_ = true;
60 }
61
62 void read(Buffer &buf)
63 {
64 if (!server_)
65 buf.read(pre_master, sizeof(pre_master));
66 buf.read(random1, sizeof(random1));
67 buf.read(random2, sizeof(random2));
68 initialized_ = true;
69 }
70
72 {
73 size_t need = sizeof(random1) + sizeof(random2);
74 if (!server_)
75 need += sizeof(pre_master);
76 if (!bc.advance(need))
77 return false;
78 return true;
79 }
80
81 void write(Buffer &buf)
82 {
84 if (!server_)
85 buf.write(pre_master, sizeof(pre_master));
86 buf.write(random1, sizeof(random1));
87 buf.write(random2, sizeof(random2));
88 }
89
91 const TLSPRF &peer,
92 const ProtoSessionID &psid_self,
93 const ProtoSessionID &psid_peer) const
94 {
95 if (server_ == peer.server_)
96 throw tlsprf_client_server_mismatch();
97 if (server_)
98 gen_exp(dest, peer, psid_peer, *this, psid_self);
99 else
100 gen_exp(dest, *this, psid_self, peer, psid_peer);
101 }
102
103 void erase()
104 {
105 if (initialized_)
106 {
107 if (!server_)
108 std::memset(pre_master, 0, sizeof(pre_master));
109 std::memset(random1, 0, sizeof(random1));
110 std::memset(random2, 0, sizeof(random2));
111 initialized_ = false;
112 }
113 }
114
115 std::string dump(const char *title)
116 {
117 std::ostringstream out;
118 out << "*** TLSPRF " << title << " pre_master: " << render_hex(pre_master, sizeof(pre_master)) << std::endl;
119 out << "*** TLSPRF " << title << " random1: " << render_hex(random1, sizeof(random1)) << std::endl;
120 out << "*** TLSPRF " << title << " random2: " << render_hex(random2, sizeof(random2)) << std::endl;
121 return out.str();
122 }
123
125 {
126 erase();
127 }
128
129 static void openvpn_PRF(const unsigned char *secret,
130 const size_t secret_len,
131 const char *label,
132 const unsigned char *client_seed,
133 const size_t client_seed_len,
134 const unsigned char *server_seed,
135 const size_t server_seed_len,
136 const ProtoSessionID *client_sid,
137 const ProtoSessionID *server_sid,
138 unsigned char *output,
139 const size_t output_len)
140 {
141 const size_t label_len = std::strlen(label);
142 // GCC is bad at optimizing this, so give it a hint
143 if (client_seed_len != SIZE_OF_RANDOM || server_seed_len != SIZE_OF_RANDOM)
144 unreachable();
145 BufferAllocated seed(label_len
146 + client_seed_len
147 + server_seed_len
150 seed.write((unsigned char *)label, label_len);
151 seed.write(client_seed, client_seed_len);
152 seed.write(server_seed, server_seed_len);
153 if (client_sid)
154 client_sid->write(seed);
155 if (server_sid)
156 server_sid->write(seed);
157
158 // compute PRF
159 if (!CRYPTO_API::TLS1PRF::PRF(seed.data(),
160 seed.size(),
161 secret,
162 secret_len,
163 output,
164 output_len))
165 {
166 throw tlsprf_tlsprf_failed();
167 }
168 }
169
170 private:
171 static void gen_exp(OpenVPNStaticKey &dest,
172 const TLSPRF &client,
173 const ProtoSessionID &psid_client,
174 const TLSPRF &server,
175 const ProtoSessionID &psid_server)
176 {
177 static const char master_secret_id[] = "OpenVPN master secret";
178 static const char key_expansion_id[] = "OpenVPN key expansion";
179
180 unsigned char master[48];
181
182 client.verify_initialized();
183 server.verify_initialized();
184
185 // compute master secret
186 openvpn_PRF(client.pre_master,
187 sizeof(client.pre_master),
188 master_secret_id,
189 client.random1,
190 sizeof(client.random1),
191 server.random1,
192 sizeof(server.random1),
193 nullptr,
194 nullptr,
195 master,
196 sizeof(master));
197
198 // compute key expansion */
199 openvpn_PRF(master,
200 sizeof(master),
201 key_expansion_id,
202 client.random2,
203 sizeof(client.random2),
204 server.random2,
205 sizeof(server.random2),
206 &psid_client,
207 &psid_server,
208 dest.raw_alloc(),
210
211 std::memset(master, 0, sizeof(master));
212 }
213
215 {
216 if (!initialized_)
217 throw tlsprf_uninitialized();
218 }
219
222 unsigned char pre_master[48]; // client generated
223 unsigned char random1[SIZE_OF_RANDOM]; // generated by both client and server
224 unsigned char random2[SIZE_OF_RANDOM]; // generated by both client and server
225};
226
227// TLSPRF wrapper API using dynamic polymorphism
228
229class TLSPRFInstance : public RC<thread_unsafe_refcount>
230{
231 public:
233
234 virtual void self_randomize(StrongRandomAPI &rng) = 0;
235 virtual void self_write(Buffer &buf) = 0;
236 virtual void peer_read(Buffer &buf) = 0;
237 virtual bool peer_read_complete(BufferComplete &bc) = 0;
238 virtual void erase() = 0;
239
240 // clang-format off
242 const ProtoSessionID &psid_self,
243 const ProtoSessionID &psid_peer) const = 0;
244 // clang-format on
245};
246
247class TLSPRFFactory : public RC<thread_unsafe_refcount>
248{
249 public:
251
252 virtual TLSPRFInstance::Ptr new_obj(const bool self_is_server) = 0;
253};
254
255// TLSPRF wrapper implementation using dynamic polymorphism
256
257template <typename CRYPTO_API>
259{
260 public:
261 CryptoTLSPRFInstance(const bool self_is_server)
262 : self(self_is_server),
263 peer(!self_is_server)
264 {
265 }
266
267 void self_randomize(StrongRandomAPI &rng) override
268 {
269 self.randomize(rng);
270 }
271
272 void self_write(Buffer &buf) override
273 {
274 self.write(buf);
275 }
276
277 void peer_read(Buffer &buf) override
278 {
279 peer.read(buf);
280 }
281
283 {
284 return peer.read_complete(bc);
285 }
286
287 void erase() override
288 {
289 self.erase();
290 peer.erase();
291 }
292
294 const ProtoSessionID &psid_self,
295 const ProtoSessionID &psid_peer) const override
296 {
297 self.generate_key_expansion(dest, peer, psid_self, psid_peer);
298 }
299
300 private:
303};
304
305template <typename CRYPTO_API>
307{
308 public:
309 TLSPRFInstance::Ptr new_obj(const bool self_is_server) override
310 {
311 return new CryptoTLSPRFInstance<CRYPTO_API>(self_is_server);
312 }
313};
314
315} // namespace openvpn
316
317#endif // OPENVPN_SSL_TLSPRF_H
bool advance(size_t size)
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1450
void write(const T *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1563
void read(NCT *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1331
TLSPRFInstance::Ptr new_obj(const bool self_is_server) override
Definition tlsprf.hpp:309
void self_randomize(StrongRandomAPI &rng) override
Definition tlsprf.hpp:267
TLSPRF< CRYPTO_API > self
Definition tlsprf.hpp:301
void generate_key_expansion(OpenVPNStaticKey &dest, const ProtoSessionID &psid_self, const ProtoSessionID &psid_peer) const override
Definition tlsprf.hpp:293
void self_write(Buffer &buf) override
Definition tlsprf.hpp:272
void peer_read(Buffer &buf) override
Definition tlsprf.hpp:277
TLSPRF< CRYPTO_API > peer
Definition tlsprf.hpp:302
CryptoTLSPRFInstance(const bool self_is_server)
Definition tlsprf.hpp:261
bool peer_read_complete(BufferComplete &bc) override
Definition tlsprf.hpp:282
unsigned char * raw_alloc()
void write(Buffer &buf) const
Definition psid.hpp:65
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
virtual void rand_bytes(unsigned char *buf, size_t size)=0
Fill a buffer with random bytes.
Abstract base class for cryptographically strong random number generators.
Definition randapi.hpp:228
RCPtr< TLSPRFFactory > Ptr
Definition tlsprf.hpp:250
virtual TLSPRFInstance::Ptr new_obj(const bool self_is_server)=0
virtual void self_write(Buffer &buf)=0
RCPtr< TLSPRFInstance > Ptr
Definition tlsprf.hpp:232
virtual void peer_read(Buffer &buf)=0
virtual void self_randomize(StrongRandomAPI &rng)=0
virtual void erase()=0
virtual void generate_key_expansion(OpenVPNStaticKey &dest, const ProtoSessionID &psid_self, const ProtoSessionID &psid_peer) const =0
virtual bool peer_read_complete(BufferComplete &bc)=0
void verify_initialized() const
Definition tlsprf.hpp:214
void randomize(StrongRandomAPI &rng)
Definition tlsprf.hpp:53
void read(Buffer &buf)
Definition tlsprf.hpp:62
unsigned char pre_master[48]
Definition tlsprf.hpp:222
OPENVPN_SIMPLE_EXCEPTION(tlsprf_uninitialized)
OPENVPN_SIMPLE_EXCEPTION(tlsprf_tlsprf_failed)
static void openvpn_PRF(const unsigned char *secret, const size_t secret_len, const char *label, const unsigned char *client_seed, const size_t client_seed_len, const unsigned char *server_seed, const size_t server_seed_len, const ProtoSessionID *client_sid, const ProtoSessionID *server_sid, unsigned char *output, const size_t output_len)
Definition tlsprf.hpp:129
void generate_key_expansion(OpenVPNStaticKey &dest, const TLSPRF &peer, const ProtoSessionID &psid_self, const ProtoSessionID &psid_peer) const
Definition tlsprf.hpp:90
bool read_complete(BufferComplete &bc)
Definition tlsprf.hpp:71
unsigned char random1[SIZE_OF_RANDOM]
Definition tlsprf.hpp:223
std::string dump(const char *title)
Definition tlsprf.hpp:115
static void gen_exp(OpenVPNStaticKey &dest, const TLSPRF &client, const ProtoSessionID &psid_client, const TLSPRF &server, const ProtoSessionID &psid_server)
Definition tlsprf.hpp:171
void write(Buffer &buf)
Definition tlsprf.hpp:81
TLSPRF(const bool server)
Definition tlsprf.hpp:48
unsigned char random2[SIZE_OF_RANDOM]
Definition tlsprf.hpp:224
OPENVPN_SIMPLE_EXCEPTION(tlsprf_client_server_mismatch)
constexpr BufferFlags DESTRUCT_ZERO(1u<< 1)
if enabled, destructor will zero data before deletion
std::string render_hex(const unsigned char *data, size_t size, const bool caps=false)
Definition hexstr.hpp:135
void unreachable()
Implementation of the base classes for random number generators.
static std::stringstream out
Definition test_path.cpp:10