OpenVPN
test_crypto.c
Go to the documentation of this file.
1 /*
2  * OpenVPN -- An application to securely tunnel IP networks
3  * over a single UDP port, with support for SSL/TLS-based
4  * session authentication and key exchange,
5  * packet encryption, packet authentication, and
6  * packet compression.
7  *
8  * Copyright (C) 2016-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2
12  * as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "syshead.h"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <setjmp.h>
35 #include <cmocka.h>
36 
37 #include "crypto.h"
38 #include "options.h"
39 #include "ssl_backend.h"
40 
41 #include "mss.h"
42 #include "test_common.h"
43 
44 static const char testtext[] = "Dummy text to test PEM encoding";
45 
46 static void
48 {
49  struct gc_arena gc = gc_new();
50  struct buffer src_buf;
51  buf_set_read(&src_buf, (void *)testtext, sizeof(testtext));
52 
53  uint8_t dec[sizeof(testtext)];
54  struct buffer dec_buf;
55  buf_set_write(&dec_buf, dec, sizeof(dec));
56 
57  struct buffer pem_buf;
58 
59  assert_true(crypto_pem_encode("TESTKEYNAME", &pem_buf, &src_buf, &gc));
60  assert_true(BLEN(&src_buf) < BLEN(&pem_buf));
61 
62  /* Wrong key name */
63  assert_false(crypto_pem_decode("WRONGNAME", &dec_buf, &pem_buf));
64 
65  assert_true(crypto_pem_decode("TESTKEYNAME", &dec_buf, &pem_buf));
66  assert_int_equal(BLEN(&src_buf), BLEN(&dec_buf));
67  assert_memory_equal(BPTR(&src_buf), BPTR(&dec_buf), BLEN(&src_buf));
68 
69  gc_free(&gc);
70 }
71 
72 static void
73 test_translate_cipher(const char *ciphername, const char *openvpn_name)
74 {
75  bool cipher = cipher_valid(ciphername);
76 
77  /* Empty cipher is fine */
78  if (!cipher)
79  {
80  return;
81  }
82 
83  const char *kt_name = cipher_kt_name(ciphername);
84 
85  assert_string_equal(kt_name, openvpn_name);
86 }
87 
88 static void
89 test_cipher_names(const char *ciphername, const char *openvpn_name)
90 {
91  struct gc_arena gc = gc_new();
92  /* Go through some variants, if the cipher library accepts these, they
93  * should be normalised to the openvpn name */
94  char *upper = string_alloc(ciphername, &gc);
95  char *lower = string_alloc(ciphername, &gc);
96  char *random_case = string_alloc(ciphername, &gc);
97 
98  for (int i = 0; i < strlen(ciphername); i++)
99  {
100  upper[i] = toupper(ciphername[i]);
101  lower[i] = tolower(ciphername[i]);
102  if (rand() & 0x1)
103  {
104  random_case[i] = upper[i];
105  }
106  else
107  {
108  random_case[i] = lower[i];
109  }
110  }
111 
112  if (!openvpn_name)
113  {
114  openvpn_name = upper;
115  }
116 
117  test_translate_cipher(upper, openvpn_name);
118  test_translate_cipher(lower, openvpn_name);
119  test_translate_cipher(random_case, openvpn_name);
120  test_translate_cipher(ciphername, openvpn_name);
121 
122 
123  gc_free(&gc);
124 }
125 
126 static void
128 {
129  /* Test that a number of ciphers to see that they turn out correctly */
130  test_cipher_names("BF-CBC", NULL);
131  test_cipher_names("BLOWFISH-CBC", "BF-CBC");
132  test_cipher_names("Chacha20-Poly1305", NULL);
133  test_cipher_names("AES-128-GCM", NULL);
134  test_cipher_names("AES-128-CBC", NULL);
135  test_cipher_names("CAMELLIA-128-CFB128", "CAMELLIA-128-CFB");
136  test_cipher_names("id-aes256-GCM", "AES-256-GCM");
137 }
138 
139 
140 static uint8_t good_prf[32] = {0xd9, 0x8c, 0x85, 0x18, 0xc8, 0x5e, 0x94, 0x69,
141  0x27, 0x91, 0x6a, 0xcf, 0xc2, 0xd5, 0x92, 0xfb,
142  0xb1, 0x56, 0x7e, 0x4b, 0x4b, 0x14, 0x59, 0xe6,
143  0xa9, 0x04, 0xac, 0x2d, 0xda, 0xb7, 0x2d, 0x67};
144 
145 static const char *ipsumlorem = "Lorem ipsum dolor sit amet, consectetur "
146  "adipisici elit, sed eiusmod tempor incidunt "
147  "ut labore et dolore magna aliqua.";
148 
149 static void
150 crypto_test_tls_prf(void **state)
151 {
152  const char *seedstr = "Quis aute iure reprehenderit in voluptate "
153  "velit esse cillum dolore";
154  const unsigned char *seed = (const unsigned char *)seedstr;
155  const size_t seed_len = strlen(seedstr);
156 
157 
158  const unsigned char *secret = (const unsigned char *) ipsumlorem;
159  size_t secret_len = strlen((const char *)secret);
160 
161 
162  uint8_t out[32];
163  ssl_tls1_PRF(seed, seed_len, secret, secret_len, out, sizeof(out));
164 
165  assert_memory_equal(good_prf, out, sizeof(out));
166 }
167 
168 static uint8_t testkey[20] = {0x0b, 0x00};
169 static uint8_t goodhash[20] = {0x58, 0xea, 0x5a, 0xf0, 0x42, 0x94, 0xe9, 0x17,
170  0xed, 0x84, 0xb9, 0xf0, 0x83, 0x30, 0x23, 0xae,
171  0x8b, 0xa7, 0x7e, 0xb8};
172 
173 static void
174 crypto_test_hmac(void **state)
175 {
176  hmac_ctx_t *hmac = hmac_ctx_new();
177 
178  assert_int_equal(md_kt_size("SHA1"), 20);
179 
180  uint8_t key[20];
181  memcpy(key, testkey, sizeof(key));
182 
183  hmac_ctx_init(hmac, key, "SHA1");
184  hmac_ctx_update(hmac, (const uint8_t *)ipsumlorem, (int) strlen(ipsumlorem));
185  hmac_ctx_update(hmac, (const uint8_t *)ipsumlorem, (int) strlen(ipsumlorem));
186 
187  uint8_t hash[20];
188  hmac_ctx_final(hmac, hash);
189 
190  assert_memory_equal(hash, goodhash, sizeof(hash));
191  memset(hash, 0x00, sizeof(hash));
192 
193  /* try again */
194  hmac_ctx_reset(hmac);
195  hmac_ctx_update(hmac, (const uint8_t *)ipsumlorem, (int) strlen(ipsumlorem));
196  hmac_ctx_update(hmac, (const uint8_t *)ipsumlorem, (int) strlen(ipsumlorem));
197  hmac_ctx_final(hmac, hash);
198 
199  assert_memory_equal(hash, goodhash, sizeof(hash));
200 
201  /* Fill our key with random data to ensure it is not used by hmac anymore */
202  memset(key, 0x55, sizeof(key));
203 
204  hmac_ctx_reset(hmac);
205  hmac_ctx_update(hmac, (const uint8_t *)ipsumlorem, (int) strlen(ipsumlorem));
206  hmac_ctx_update(hmac, (const uint8_t *)ipsumlorem, (int) strlen(ipsumlorem));
207  hmac_ctx_final(hmac, hash);
208 
209  assert_memory_equal(hash, goodhash, sizeof(hash));
210  hmac_ctx_cleanup(hmac);
211  hmac_ctx_free(hmac);
212 }
213 
214 /* This test is in test_crypto as it calls into the functions that calculate
215  * the crypto overhead */
216 static void
218 {
219  struct gc_arena gc = gc_new();
220 
221  struct frame f = { 0 };
222  struct options o = { 0 };
223  size_t linkmtu;
224 
225  /* common defaults */
226  o.ce.tun_mtu = 1400;
227  o.ce.proto = PROTO_UDP;
228 
229  /* No crypto at all */
230  o.ciphername = "none";
231  o.authname = "none";
232  linkmtu = calc_options_string_link_mtu(&o, &f);
233  assert_int_equal(linkmtu, 1400);
234 
235  /* Static key OCC examples */
236  o.shared_secret_file = "not null";
237 
238  /* secret, auth none, cipher none */
239  o.ciphername = "none";
240  o.authname = "none";
241  linkmtu = calc_options_string_link_mtu(&o, &f);
242  assert_int_equal(linkmtu, 1408);
243 
244  /* secret, cipher AES-128-CBC, auth none */
245  o.ciphername = "AES-128-CBC";
246  o.authname = "none";
247  linkmtu = calc_options_string_link_mtu(&o, &f);
248  assert_int_equal(linkmtu, 1440);
249 
250  /* secret, cipher none, auth SHA256 */
251  o.ciphername = "none";
252  o.authname = "SHA256";
253  linkmtu = calc_options_string_link_mtu(&o, &f);
254  assert_int_equal(linkmtu, 1440);
255 
256  /* secret, cipher BF-CBC, auth SHA1 */
257  o.ciphername = "BF-CBC";
258  o.authname = "SHA1";
259  linkmtu = calc_options_string_link_mtu(&o, &f);
260  assert_int_equal(linkmtu, 1444);
261 
262  /* secret, cipher BF-CBC, auth SHA1, tcp-client */
264  linkmtu = calc_options_string_link_mtu(&o, &f);
265  assert_int_equal(linkmtu, 1446);
266 
267  o.ce.proto = PROTO_UDP;
268 
269 #if defined(USE_COMP)
270  o.comp.alg = COMP_ALG_LZO;
271 
272  /* secret, comp-lzo yes, cipher BF-CBC, auth SHA1 */
273  linkmtu = calc_options_string_link_mtu(&o, &f);
274  assert_int_equal(linkmtu, 1445);
275 
276 #if defined(ENABLE_FRAGMENT)
277  /* secret, comp-lzo yes, cipher BF-CBC, auth SHA1, fragment 1200 */
278  o.ce.fragment = 1200;
279  linkmtu = calc_options_string_link_mtu(&o, &f);
280  assert_int_equal(linkmtu, 1449);
281  o.ce.fragment = 0;
282 #endif
283 
284  o.comp.alg = COMP_ALG_UNDEF;
285 #endif
286 
287  /* TLS mode */
288  o.shared_secret_file = NULL;
289  o.tls_client = true;
290  o.pull = true;
291 
292  /* tls client, cipher AES-128-CBC, auth SHA1, tls-auth */
293  o.authname = "SHA1";
294  o.ciphername = "AES-128-CBC";
295  o.tls_auth_file = "dummy";
296 
297  linkmtu = calc_options_string_link_mtu(&o, &f);
298  assert_int_equal(linkmtu, 1457);
299 
300  /* tls client, cipher AES-128-CBC, auth SHA1 */
301  o.tls_auth_file = NULL;
302 
303  linkmtu = calc_options_string_link_mtu(&o, &f);
304  assert_int_equal(linkmtu, 1457);
305 
306  /* tls client, cipher none, auth none */
307  o.authname = "none";
308  o.ciphername = "none";
309 
310  linkmtu = calc_options_string_link_mtu(&o, &f);
311  assert_int_equal(linkmtu, 1405);
312 
313  /* tls client, auth SHA1, cipher AES-256-GCM */
314  o.authname = "SHA1";
315  o.ciphername = "AES-256-GCM";
316  linkmtu = calc_options_string_link_mtu(&o, &f);
317  assert_int_equal(linkmtu, 1449);
318 
319 
320 #if defined(USE_COMP) && defined(ENABLE_FRAGMENT)
321  o.comp.alg = COMP_ALG_LZO;
322 
323  /* tls client, auth SHA1, cipher AES-256-GCM, fragment, comp-lzo yes */
324  o.ce.fragment = 1200;
325  linkmtu = calc_options_string_link_mtu(&o, &f);
326  assert_int_equal(linkmtu, 1454);
327 
328  /* tls client, auth SHA1, cipher AES-256-GCM, fragment, comp-lzo yes, socks */
329  o.ce.socks_proxy_server = "socks.example.com";
330  linkmtu = calc_options_string_link_mtu(&o, &f);
331  assert_int_equal(linkmtu, 1464);
332 #endif
333 
334  gc_free(&gc);
335 }
336 
337 static void
339 {
340  struct gc_arena gc = gc_new();
341 
342  struct frame f = { 0 };
343  struct options o = { 0 };
344 
345  /* common defaults */
346  o.ce.tun_mtu = 1400;
347  o.ce.mssfix = 1000;
348  o.ce.proto = PROTO_UDP;
349 
350  /* No crypto at all */
351  o.ciphername = "none";
352  o.authname = "none";
353  struct key_type kt;
354  init_key_type(&kt, o.ciphername, o.authname, false, false);
355 
356  /* No encryption, just packet id (8) + TCP payload(20) + IP payload(20) */
357  frame_calculate_dynamic(&f, &kt, &o, NULL);
358  assert_int_equal(f.mss_fix, 952);
359 
360  /* Static key OCC examples */
361  o.shared_secret_file = "not null";
362 
363  /* secret, auth none, cipher none */
364  o.ciphername = "none";
365  o.authname = "none";
366  init_key_type(&kt, o.ciphername, o.authname, false, false);
367  frame_calculate_dynamic(&f, &kt, &o, NULL);
368  assert_int_equal(f.mss_fix, 952);
369 
370  /* secret, cipher AES-128-CBC, auth none */
371  o.ciphername = "AES-128-CBC";
372  o.authname = "none";
373  init_key_type(&kt, o.ciphername, o.authname, false, false);
374 
375  for (int i = 990; i <= 1010; i++)
376  {
377  /* 992 - 1008 should end up with the same mssfix value all they
378  * all result in the same CBC block size/padding and <= 991 and >=1008
379  * should be one block less and more respectively */
380  o.ce.mssfix = i;
381  frame_calculate_dynamic(&f, &kt, &o, NULL);
382  if (i <= 991)
383  {
384  assert_int_equal(f.mss_fix, 911);
385  }
386  else if (i >= 1008)
387  {
388  assert_int_equal(f.mss_fix, 943);
389  }
390  else
391  {
392  assert_int_equal(f.mss_fix, 927);
393  }
394  }
395 #ifdef USE_COMP
396  o.comp.alg = COMP_ALG_LZO;
397 
398  /* Same but with compression added. Compression adds one byte extra to the
399  * payload so the payload should be reduced by compared to the no
400  * compression calculation before */
401  for (int i = 990; i <= 1010; i++)
402  {
403  /* 992 - 1008 should end up with the same mssfix value all they
404  * all result in the same CBC block size/padding and <= 991 and >=1008
405  * should be one block less and more respectively */
406  o.ce.mssfix = i;
407  frame_calculate_dynamic(&f, &kt, &o, NULL);
408  if (i <= 991)
409  {
410  assert_int_equal(f.mss_fix, 910);
411  }
412  else if (i >= 1008)
413  {
414  assert_int_equal(f.mss_fix, 942);
415  }
416  else
417  {
418  assert_int_equal(f.mss_fix, 926);
419  }
420  }
421  o.comp.alg = COMP_ALG_UNDEF;
422 #endif /* ifdef USE_COMP */
423 
424  /* tls client, auth SHA1, cipher AES-256-GCM */
425  o.authname = "SHA1";
426  o.ciphername = "AES-256-GCM";
427  o.tls_client = true;
428  o.peer_id = 77;
429  o.use_peer_id = true;
430  init_key_type(&kt, o.ciphername, o.authname, true, false);
431 
432  for (int i = 900; i <= 1200; i++)
433  {
434  /* For stream ciphers, the value should not be influenced by block
435  * sizes or similar but always have the same difference */
436  o.ce.mssfix = i;
437  frame_calculate_dynamic(&f, &kt, &o, NULL);
438 
439  /* 4 byte opcode/peerid, 4 byte pkt ID, 16 byte tag, 40 TCP+IP */
440  assert_int_equal(f.mss_fix, i - 4 - 4 - 16 - 40);
441  }
442 
443  gc_free(&gc);
444 }
445 
446 int
447 main(void)
448 {
450  const struct CMUnitTest tests[] = {
451  cmocka_unit_test(crypto_pem_encode_decode_loopback),
452  cmocka_unit_test(crypto_translate_cipher_names),
453  cmocka_unit_test(crypto_test_tls_prf),
454  cmocka_unit_test(crypto_test_hmac),
455  cmocka_unit_test(test_occ_mtu_calculation),
456  cmocka_unit_test(test_mssfix_mtu_calculation)
457  };
458 
459 #if defined(ENABLE_CRYPTO_OPENSSL)
460  OpenSSL_add_all_algorithms();
461 #endif
462 
463  int ret = cmocka_run_group_tests_name("crypto tests", tests, NULL, NULL);
464 
465 #if defined(ENABLE_CRYPTO_OPENSSL)
466  EVP_cleanup();
467 #endif
468 
469  return ret;
470 }
main
int main(void)
Definition: test_crypto.c:447
cipher_valid
static bool cipher_valid(const char *ciphername)
Returns if the cipher is valid, based on the given cipher name.
Definition: crypto_backend.h:204
hmac_ctx_cleanup
void hmac_ctx_cleanup(hmac_ctx_t *ctx)
connection_entry::mssfix
int mssfix
Definition: options.h:135
compress_options::alg
int alg
Definition: comp.h:66
options::use_peer_id
bool use_peer_id
Definition: options.h:683
ssl_backend.h
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:1031
hmac_ctx_t
mbedtls_md_context_t hmac_ctx_t
Generic HMAC context.
Definition: crypto_mbedtls.h:46
connection_entry::socks_proxy_server
const char * socks_proxy_server
Definition: options.h:114
crypto_test_tls_prf
static void crypto_test_tls_prf(void **state)
Definition: test_crypto.c:150
openvpn_unit_test_setup
static void openvpn_unit_test_setup()
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
Definition: test_common.h:36
hash
Definition: list.h:58
test_common.h
options::authname
const char * authname
Definition: options.h:561
options::tls_client
bool tls_client
Definition: options.h:575
options::shared_secret_file
const char * shared_secret_file
Definition: options.h:553
testtext
static const char testtext[]
Definition: test_crypto.c:44
options::ce
struct connection_entry ce
Definition: options.h:275
hmac_ctx_update
void hmac_ctx_update(hmac_ctx_t *ctx, const uint8_t *src, int src_len)
options.h
cipher_kt_name
const char * cipher_kt_name(const char *ciphername)
Retrieve a normalised string describing the cipher (e.g.
Definition: crypto_openssl.c:638
frame
Packet geometry parameters.
Definition: mtu.h:98
test_occ_mtu_calculation
static void test_occ_mtu_calculation(void **state)
Definition: test_crypto.c:217
key
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:149
ipsumlorem
static const char * ipsumlorem
Definition: test_crypto.c:145
string_alloc
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:693
test_translate_cipher
static void test_translate_cipher(const char *ciphername, const char *openvpn_name)
Definition: test_crypto.c:73
testkey
static uint8_t testkey[20]
Definition: test_crypto.c:168
PROTO_TCP_CLIENT
@ PROTO_TCP_CLIENT
Definition: socket.h:558
test_cipher_names
static void test_cipher_names(const char *ciphername, const char *openvpn_name)
Definition: test_crypto.c:89
BLEN
#define BLEN(buf)
Definition: buffer.h:127
options::comp
struct compress_options comp
Definition: options.h:396
calc_options_string_link_mtu
size_t calc_options_string_link_mtu(const struct options *o, const struct frame *frame)
Calculate the link-mtu to advertise to our peer.
Definition: mtu.c:152
frame_calculate_dynamic
void frame_calculate_dynamic(struct frame *frame, struct key_type *kt, const struct options *options, struct link_socket_info *lsi)
Set the –mssfix option.
Definition: mss.c:335
COMP_ALG_UNDEF
#define COMP_ALG_UNDEF
Definition: comp.h:45
crypto_translate_cipher_names
static void crypto_translate_cipher_names(void **state)
Definition: test_crypto.c:127
options::tls_auth_file
const char * tls_auth_file
Definition: options.h:645
goodhash
static uint8_t goodhash[20]
Definition: test_crypto.c:169
options
Definition: options.h:236
crypto.h
options::gc
struct gc_arena gc
Definition: options.h:238
md_kt_size
unsigned char md_kt_size(const char *mdname)
Returns the size of the message digest, in bytes.
Definition: crypto_openssl.c:1077
crypto_pem_encode_decode_loopback
static void crypto_pem_encode_decode_loopback(void **state)
Definition: test_crypto.c:47
hmac_ctx_final
void hmac_ctx_final(hmac_ctx_t *ctx, uint8_t *dst)
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
hmac_ctx_reset
void hmac_ctx_reset(hmac_ctx_t *ctx)
hmac_ctx_free
void hmac_ctx_free(hmac_ctx_t *ctx)
key_type
Definition: crypto.h:139
syshead.h
BPTR
#define BPTR(buf)
Definition: buffer.h:124
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
crypto_pem_encode
bool crypto_pem_encode(const char *name, struct buffer *dst, const struct buffer *src, struct gc_arena *gc)
Encode binary data as PEM.
Definition: crypto_openssl.c:481
buf_set_write
static void buf_set_write(struct buffer *buf, uint8_t *data, int size)
Definition: buffer.h:331
options::peer_id
uint32_t peer_id
Definition: options.h:684
crypto_pem_decode
bool crypto_pem_decode(const char *name, struct buffer *dst, const struct buffer *src)
Decode a PEM buffer to binary data.
Definition: crypto_openssl.c:509
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1039
mss.h
config.h
hmac_ctx_new
hmac_ctx_t * hmac_ctx_new(void)
Definition: crypto_openssl.c:1169
connection_entry::fragment
int fragment
Definition: options.h:132
connection_entry::proto
int proto
Definition: options.h:99
hmac_ctx_init
void hmac_ctx_init(hmac_ctx_t *ctx, const uint8_t *key, const char *mdname)
init_key_type
void init_key_type(struct key_type *kt, const char *ciphername, const char *authname, bool tls_mode, bool warn)
Initialize a key_type structure with.
Definition: crypto.c:744
crypto_test_hmac
static void crypto_test_hmac(void **state)
Definition: test_crypto.c:174
COMP_ALG_LZO
#define COMP_ALG_LZO
Definition: comp.h:47
connection_entry::tun_mtu
int tun_mtu
Definition: options.h:118
options::ciphername
const char * ciphername
Definition: options.h:557
http-client.f
string f
Definition: http-client.py:6
test_mssfix_mtu_calculation
static void test_mssfix_mtu_calculation(void **state)
Definition: test_crypto.c:338
ssl_tls1_PRF
bool ssl_tls1_PRF(const uint8_t *seed, int seed_len, const uint8_t *secret, int secret_len, uint8_t *output, int output_len)
Calculates the TLS 1.0-1.1 PRF function.
Definition: crypto_openssl.c:1518
buf_set_read
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition: buffer.h:348
options::pull
bool pull
Definition: options.h:540
good_prf
static uint8_t good_prf[32]
Definition: test_crypto.c:140
PROTO_UDP
@ PROTO_UDP
Definition: socket.h:555