OpenVPN 3 Core Library
Loading...
Searching...
No Matches
ovpnhmac.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 HMAC classes
13
14#ifndef OPENVPN_CRYPTO_OVPNHMAC_H
15#define OPENVPN_CRYPTO_OVPNHMAC_H
16
17#include <string>
18
21#include <openvpn/common/rc.hpp>
25
26namespace openvpn {
27
28// OpenVPN protocol HMAC usage for HMAC/CBC integrity checking and tls-auth
29
30template <typename CRYPTO_API>
32{
33 public:
34 OPENVPN_SIMPLE_EXCEPTION(ovpn_hmac_context_digest_size);
35 OPENVPN_SIMPLE_EXCEPTION(ovpn_hmac_context_bad_sizing);
36
37 public:
38 OvpnHMAC() = default;
39
40 OvpnHMAC(const CryptoAlgs::Type digest, const StaticKey &key)
41 {
42 init(digest, key);
43 }
44
45 bool defined() const
46 {
47 return ctx.is_initialized();
48 }
49
50 // size of out buffer to pass to hmac
51 size_t output_size() const
52 {
53 return ctx.size();
54 }
55
56 void init(const CryptoAlgs::Type digest, const StaticKey &key)
57 {
58 const CryptoAlgs::Alg &alg = CryptoAlgs::get(digest);
59
60 // check that key is large enough
61 if (key.size() < alg.size())
62 throw ovpn_hmac_context_digest_size();
63
64 // initialize HMAC context with digest type and key
65 ctx.init(digest, key.data(), alg.size());
66 }
67
68 void hmac(unsigned char *out,
69 const size_t out_size,
70 const unsigned char *in,
71 const size_t in_size)
72 {
73 ctx.reset();
74 ctx.update(in, in_size);
75 ctx.final(out);
76 }
77
78 // Special HMAC for OpenVPN control packets
79
80 void ovpn_hmac_gen(unsigned char *data,
81 const size_t data_size,
82 const size_t l1,
83 const size_t l2,
84 const size_t l3)
85 {
86 if (ovpn_hmac_pre(data, data_size, l1, l2, l3))
87 ctx.final(data + l1);
88 else
89 throw ovpn_hmac_context_bad_sizing();
90 }
91
92 // verify the HMAC generated by ovpn_hmac_gen, return true if verified
93 bool ovpn_hmac_cmp(const unsigned char *data,
94 const size_t data_size,
95 const size_t l1,
96 const size_t l2,
97 const size_t l3)
98 {
99 unsigned char local_hmac[CRYPTO_API::HMACContext::MAX_HMAC_SIZE];
100 if (ovpn_hmac_pre(data, data_size, l1, l2, l3))
101 {
102 ctx.final(local_hmac);
103 return !crypto::memneq(data + l1, local_hmac, l2);
104 }
105 return false;
106 }
107
108 private:
109 // Convoluting OpenVPN control channel packets for HMAC:
110 // <-- L1 --> <-L2> <L3>
111 // [OP] [PSID] [HMAC] [PID] [...] -> canonical order
112 //
113 // [HMAC] [PID] [OP] [PSID] [...] -> HMAC order
114
115 bool ovpn_hmac_pre(const unsigned char *data,
116 const size_t data_size,
117 const size_t l1,
118 const size_t l2,
119 const size_t l3)
120 {
121 const size_t lsum = l1 + l2 + l3;
122 if (lsum > data_size || l2 != ctx.size())
123 return false;
124 ctx.reset();
125 ctx.update(data + l1 + l2, l3);
126 ctx.update(data, l1);
127 ctx.update(data + lsum, data_size - lsum);
128 return true;
129 }
130
131 typename CRYPTO_API::HMACContext ctx;
132};
133
134// OvpnHMAC wrapper API using dynamic polymorphism
135
136class OvpnHMACInstance : public RC<thread_unsafe_refcount>
137{
138 public:
140
141 virtual void init(const StaticKey &key) = 0;
142
143 virtual size_t output_size() const = 0;
144
145 virtual void ovpn_hmac_gen(unsigned char *data,
146 const size_t data_size,
147 const size_t l1,
148 const size_t l2,
149 const size_t l3) = 0;
150
151 virtual bool ovpn_hmac_cmp(const unsigned char *data,
152 const size_t data_size,
153 const size_t l1,
154 const size_t l2,
155 const size_t l3) = 0;
156};
157
158class OvpnHMACContext : public RC<thread_unsafe_refcount>
159{
160 public:
162
163 virtual size_t size() const = 0;
164
166};
167
168class OvpnHMACFactory : public RC<thread_unsafe_refcount>
169{
170 public:
172
173 virtual OvpnHMACContext::Ptr new_obj(const CryptoAlgs::Type digest_type) = 0;
174};
175
176// OvpnHMAC wrapper implementation using dynamic polymorphism
177
178template <typename CRYPTO_API>
180{
181 public:
183 : digest(digest_arg)
184 {
185 }
186
187 void init(const StaticKey &key) override
188 {
189 ovpn_hmac.init(digest, key);
190 }
191
192 size_t output_size() const override
193 {
194 return ovpn_hmac.output_size();
195 }
196
197 void ovpn_hmac_gen(unsigned char *data,
198 const size_t data_size,
199 const size_t l1,
200 const size_t l2,
201 const size_t l3) override
202 {
203 ovpn_hmac.ovpn_hmac_gen(data, data_size, l1, l2, l3);
204 }
205
206 bool ovpn_hmac_cmp(const unsigned char *data,
207 const size_t data_size,
208 const size_t l1,
209 const size_t l2,
210 const size_t l3) override
211 {
212 return ovpn_hmac.ovpn_hmac_cmp(data, data_size, l1, l2, l3);
213 }
214
215 private:
218};
219
220template <typename CRYPTO_API>
222{
223 public:
225 : digest(digest_type)
226 {
227 }
228
229 size_t size() const override
230 {
231 return CryptoAlgs::size(digest);
232 }
233
238
239 private:
241};
242
243template <typename CRYPTO_API>
245{
246 public:
248 {
249 return new CryptoOvpnHMACContext<CRYPTO_API>(digest_type);
250 }
251};
252
253} // namespace openvpn
254
255#endif
OvpnHMACInstance::Ptr new_obj() override
Definition ovpnhmac.hpp:234
CryptoOvpnHMACContext(const CryptoAlgs::Type digest_type)
Definition ovpnhmac.hpp:224
size_t size() const override
Definition ovpnhmac.hpp:229
OvpnHMACContext::Ptr new_obj(const CryptoAlgs::Type digest_type) override
Definition ovpnhmac.hpp:247
bool ovpn_hmac_cmp(const unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3) override
Definition ovpnhmac.hpp:206
void ovpn_hmac_gen(unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3) override
Definition ovpnhmac.hpp:197
CryptoOvpnHMACInstance(const CryptoAlgs::Type digest_arg)
Definition ovpnhmac.hpp:182
OvpnHMAC< CRYPTO_API > ovpn_hmac
Definition ovpnhmac.hpp:217
void init(const StaticKey &key) override
Definition ovpnhmac.hpp:187
size_t output_size() const override
Definition ovpnhmac.hpp:192
virtual OvpnHMACInstance::Ptr new_obj()=0
virtual size_t size() const =0
virtual OvpnHMACContext::Ptr new_obj(const CryptoAlgs::Type digest_type)=0
virtual void ovpn_hmac_gen(unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3)=0
virtual void init(const StaticKey &key)=0
virtual bool ovpn_hmac_cmp(const unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3)=0
virtual size_t output_size() const =0
bool defined() const
Definition ovpnhmac.hpp:45
bool ovpn_hmac_pre(const unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3)
Definition ovpnhmac.hpp:115
void ovpn_hmac_gen(unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3)
Definition ovpnhmac.hpp:80
size_t output_size() const
Definition ovpnhmac.hpp:51
OPENVPN_SIMPLE_EXCEPTION(ovpn_hmac_context_digest_size)
bool ovpn_hmac_cmp(const unsigned char *data, const size_t data_size, const size_t l1, const size_t l2, const size_t l3)
Definition ovpnhmac.hpp:93
OvpnHMAC()=default
CRYPTO_API::HMACContext ctx
Definition ovpnhmac.hpp:131
void init(const CryptoAlgs::Type digest, const StaticKey &key)
Definition ovpnhmac.hpp:56
OvpnHMAC(const CryptoAlgs::Type digest, const StaticKey &key)
Definition ovpnhmac.hpp:40
void hmac(unsigned char *out, const size_t out_size, const unsigned char *in, const size_t in_size)
Definition ovpnhmac.hpp:68
OPENVPN_SIMPLE_EXCEPTION(ovpn_hmac_context_bad_sizing)
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:908
const unsigned char * data() const
size_t size() const
const Alg & get(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 std::stringstream out
Definition test_path.cpp:10