OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tls_crypt.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// OpenVPN TLS-Crypt classes
13
14#ifndef OPENVPN_CRYPTO_TLSCRYPT_H
15#define OPENVPN_CRYPTO_TLSCRYPT_H
16
17#include <string>
18
21#include <openvpn/common/rc.hpp>
26#include <openvpn/ssl/psid.hpp>
27
28namespace openvpn {
29
30// OpenVPN protocol HMAC usage for HMAC/CTR integrity checking and tls-crypt
31
32// Control packet format when tls-crypt is enabled:
33// [OP] [PSID] [PID] [HMAC] [...]
34
35template <typename CRYPTO_API>
37{
38 public:
39 OPENVPN_SIMPLE_EXCEPTION(ovpn_tls_crypt_context_digest_size);
40 OPENVPN_SIMPLE_EXCEPTION(ovpn_tls_crypt_context_bad_sizing);
41 OPENVPN_SIMPLE_EXCEPTION(ovpn_tls_crypt_wrong_mode);
42
44 : mode(CRYPTO_API::CipherContext::MODE_UNDEF)
45 {
46 }
47
48 TLSCrypt(SSLLib::Ctx libctx, const CryptoAlgs::Type digest, const StaticKey &key_hmac, const CryptoAlgs::Type cipher, const StaticKey &key_crypt, const int mode)
49 {
50 init(libctx, digest, key_hmac, cipher, key_crypt, mode);
51 }
52
53 bool defined() const
54 {
55 return ctx_hmac.is_initialized() && ctx_crypt.is_initialized();
56 }
57
58 // size of out buffer to pass to hmac
59 size_t output_hmac_size() const
60 {
61 return ctx_hmac.size();
62 }
63
64 void init(SSLLib::Ctx libctx, const CryptoAlgs::Type digest, const StaticKey &key_hmac, const CryptoAlgs::Type cipher, const StaticKey &key_crypt, const int mode_arg)
65 {
66 const CryptoAlgs::Alg &alg_hmac = CryptoAlgs::get(digest);
67
68 // check that key is large enough
69 if (key_hmac.size() < alg_hmac.size())
70 throw ovpn_tls_crypt_context_digest_size();
71
72 // initialize HMAC context with digest type and key
73 ctx_hmac.init(digest, key_hmac.data(), alg_hmac.size());
74
75 // initialize Cipher context with cipher, key and mode
76 ctx_crypt.init(libctx, cipher, key_crypt.data(), mode_arg);
77
78 mode = mode_arg;
79 }
80
81 bool hmac_gen(unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
82 {
83 hmac_pre(header, header_len, payload, payload_len);
84 ctx_hmac.final(header + header_len);
85
86 return true;
87 }
88
89 bool hmac_cmp(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
90 {
91 unsigned char local_hmac[CRYPTO_API::HMACContext::MAX_HMAC_SIZE];
92
93 hmac_pre(header, header_len, payload, payload_len);
94 ctx_hmac.final(local_hmac);
95
96 return !crypto::memneq(header + header_len, local_hmac, output_hmac_size());
97 }
98
99 size_t encrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
100 {
101 if (mode != CRYPTO_API::CipherContext::ENCRYPT)
102 throw ovpn_tls_crypt_wrong_mode();
103
104 return encrypt_decrypt(iv, out, olen, in, ilen);
105 }
106
107 size_t decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
108 {
109 if (mode != CRYPTO_API::CipherContext::DECRYPT)
110 throw ovpn_tls_crypt_wrong_mode();
111
112 return encrypt_decrypt(iv, out, olen, in, ilen);
113 }
114
115 private:
116 // assume length check on header has already been performed
117 void hmac_pre(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
118 {
119 ctx_hmac.reset();
120 ctx_hmac.update(header, header_len);
121 ctx_hmac.update(payload, payload_len);
122 }
123
124 size_t encrypt_decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
125 {
126 ctx_crypt.reset(iv);
127
128 size_t outlen = 0;
129
130 if (!ctx_crypt.update(out, olen, in, ilen, outlen))
131 return 0;
132
133 if (!ctx_crypt.final(out + outlen, olen - outlen, outlen))
134 return 0;
135
136 return outlen;
137 }
138
139 typename CRYPTO_API::HMACContext ctx_hmac;
140 typename CRYPTO_API::CipherContext ctx_crypt;
141 int mode;
142};
143
144// OvpnHMAC wrapper API using dynamic polymorphism
145
146class TLSCryptInstance : public RC<thread_unsafe_refcount>
147{
148 public:
150
151 virtual void init(SSLLib::Ctx libctx, const StaticKey &key_hmac, const StaticKey &key_crypt) = 0;
152
153 virtual size_t output_hmac_size() const = 0;
154
155 virtual bool hmac_gen(unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len) = 0;
156
157 virtual bool hmac_cmp(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len) = 0;
158
159 virtual size_t encrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen) = 0;
160
161 virtual size_t decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen) = 0;
162};
163
164class TLSCryptContext : public RC<thread_unsafe_refcount>
165{
166 public:
168
169 virtual size_t digest_size() const = 0;
170
171 virtual size_t cipher_key_size() const = 0;
172
174
176
177 // This is the size of the header in a TLSCrypt-wrapped packets,
178 // excluding the HMAC. Format:
179 //
180 // [OP] [PSID] [PID] [HMAC] [...]
181 //
182
183 constexpr const static size_t hmac_offset = 1 + ProtoSessionID::SIZE + PacketIDControl::idsize;
184};
185
186
187
188class TLSCryptFactory : public RC<thread_unsafe_refcount>
189{
190 public:
192
193 virtual TLSCryptContext::Ptr new_obj(SSLLib::Ctx libctx, const CryptoAlgs::Type digest_type, const CryptoAlgs::Type cipher_type) = 0;
194};
195
196// TLSCrypt wrapper implementation using dynamic polymorphism
197
198template <typename CRYPTO_API>
200{
201 public:
203 const CryptoAlgs::Type digest_arg,
204 const CryptoAlgs::Type cipher_arg,
205 int mode_arg)
206 : digest(digest_arg),
207 cipher(cipher_arg),
208 mode(mode_arg),
209 libctx(libctx_arg)
210 {
211 }
212
213 void init(SSLLib::Ctx libctx, const StaticKey &key_hmac, const StaticKey &key_crypt)
214 {
215 tls_crypt.init(libctx, digest, key_hmac, cipher, key_crypt, mode);
216 }
217
218 size_t output_hmac_size() const
219 {
220 return tls_crypt.output_hmac_size();
221 }
222
223 bool hmac_gen(unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
224 {
225 return tls_crypt.hmac_gen(header, header_len, payload, payload_len);
226 }
227
228 // verify the HMAC generated by hmac_gen, return true if verified
229 bool hmac_cmp(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
230 {
231 return tls_crypt.hmac_cmp(header, header_len, payload, payload_len);
232 }
233
234 size_t encrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
235 {
236 return tls_crypt.encrypt(iv, out, olen, in, ilen);
237 }
238
239 size_t decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
240 {
241 return tls_crypt.decrypt(iv, out, olen, in, ilen);
242 }
243
244 private:
247 int mode;
250};
251
252template <typename CRYPTO_API>
254{
255 public:
256 CryptoTLSCryptContext(SSLLib::Ctx libctx_arg, const CryptoAlgs::Type digest_type, const CryptoAlgs::Type cipher_type)
257 : digest(digest_type),
258 cipher(cipher_type),
259 libctx(libctx_arg)
260 {
261 }
262
263 size_t digest_size() const override
264 {
265 return CryptoAlgs::size(digest);
266 }
267
268 size_t cipher_key_size() const override
269 {
271 }
272
274 {
275 return new CryptoTLSCryptInstance<CRYPTO_API>(libctx, digest, cipher, CRYPTO_API::CipherContext::ENCRYPT);
276 }
277
279 {
280 return new CryptoTLSCryptInstance<CRYPTO_API>(libctx, digest, cipher, CRYPTO_API::CipherContext::DECRYPT);
281 }
282
283 private:
287};
288
289template <typename CRYPTO_API>
291{
292 public:
293 TLSCryptContext::Ptr new_obj(SSLLib::Ctx libctx, const CryptoAlgs::Type digest_type, const CryptoAlgs::Type cipher_type) override
294 {
295 return new CryptoTLSCryptContext<CRYPTO_API>(libctx, digest_type, cipher_type);
296 }
297};
298} // namespace openvpn
299
300#endif
CryptoTLSCryptContext(SSLLib::Ctx libctx_arg, const CryptoAlgs::Type digest_type, const CryptoAlgs::Type cipher_type)
size_t digest_size() const override
TLSCryptInstance::Ptr new_obj_send() override
TLSCryptInstance::Ptr new_obj_recv() override
size_t cipher_key_size() const override
TLSCryptContext::Ptr new_obj(SSLLib::Ctx libctx, const CryptoAlgs::Type digest_type, const CryptoAlgs::Type cipher_type) override
bool hmac_gen(unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
CryptoTLSCryptInstance(SSLLib::Ctx libctx_arg, const CryptoAlgs::Type digest_arg, const CryptoAlgs::Type cipher_arg, int mode_arg)
size_t decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
size_t encrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
TLSCrypt< CRYPTO_API > tls_crypt
bool hmac_cmp(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
void init(SSLLib::Ctx libctx, const StaticKey &key_hmac, const StaticKey &key_crypt)
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
const unsigned char * data() const
size_t size() const
virtual size_t cipher_key_size() const =0
RCPtr< TLSCryptContext > Ptr
virtual TLSCryptInstance::Ptr new_obj_send()=0
virtual TLSCryptInstance::Ptr new_obj_recv()=0
constexpr static const size_t hmac_offset
virtual size_t digest_size() const =0
RCPtr< TLSCryptFactory > Ptr
virtual TLSCryptContext::Ptr new_obj(SSLLib::Ctx libctx, const CryptoAlgs::Type digest_type, const CryptoAlgs::Type cipher_type)=0
virtual bool hmac_cmp(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)=0
virtual size_t output_hmac_size() const =0
virtual bool hmac_gen(unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)=0
virtual size_t encrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)=0
virtual void init(SSLLib::Ctx libctx, const StaticKey &key_hmac, const StaticKey &key_crypt)=0
virtual size_t decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)=0
RCPtr< TLSCryptInstance > Ptr
void init(SSLLib::Ctx libctx, const CryptoAlgs::Type digest, const StaticKey &key_hmac, const CryptoAlgs::Type cipher, const StaticKey &key_crypt, const int mode_arg)
Definition tls_crypt.hpp:64
void hmac_pre(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
size_t encrypt_decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
OPENVPN_SIMPLE_EXCEPTION(ovpn_tls_crypt_wrong_mode)
TLSCrypt(SSLLib::Ctx libctx, const CryptoAlgs::Type digest, const StaticKey &key_hmac, const CryptoAlgs::Type cipher, const StaticKey &key_crypt, const int mode)
Definition tls_crypt.hpp:48
CRYPTO_API::CipherContext ctx_crypt
OPENVPN_SIMPLE_EXCEPTION(ovpn_tls_crypt_context_bad_sizing)
bool defined() const
Definition tls_crypt.hpp:53
bool hmac_gen(unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
Definition tls_crypt.hpp:81
OPENVPN_SIMPLE_EXCEPTION(ovpn_tls_crypt_context_digest_size)
CRYPTO_API::HMACContext ctx_hmac
size_t decrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
size_t encrypt(const unsigned char *iv, unsigned char *out, const size_t olen, const unsigned char *in, const size_t ilen)
Definition tls_crypt.hpp:99
bool hmac_cmp(const unsigned char *header, const size_t header_len, const unsigned char *payload, const size_t payload_len)
Definition tls_crypt.hpp:89
size_t output_hmac_size() const
Definition tls_crypt.hpp:59
const Alg & get(const Type type)
size_t key_length(const Type type)
size_t size(const Type type)
bool memneq(const void *a, const void *b, size_t size)
Definition memneq.hpp:79
static constexpr size_t idsize
static std::stringstream out
Definition test_path.cpp:10