OpenVPN
test_ncp.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) 2019-2021 Arne Schwabe <arne@rfc2549.org>
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 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <setjmp.h>
37 #include <cmocka.h>
38 
39 #include "ssl_ncp.c"
40 
41 /* Defines for use in the tests and the mock parse_line() */
42 
43 const char *bf_chacha = "BF-CBC:CHACHA20-POLY1305";
44 const char *aes_ciphers = "AES-256-GCM:AES-128-GCM";
45 
46 
47 /* Define this function here as dummy since including the ssl_*.c files
48  * leads to having to include even more unrelated code */
49 bool
51  const char* label, size_t label_size,
52  void *ekm, size_t ekm_size)
53 {
54  ASSERT(0);
55 }
56 
57 static void
59 {
60  struct gc_arena gc = gc_new();
61  bool have_chacha = cipher_kt_get("CHACHA20-POLY1305");
62 
63  assert_string_equal(mutate_ncp_cipher_list("none", &gc), "none");
64  assert_string_equal(mutate_ncp_cipher_list("AES-256-GCM:none", &gc),
65  "AES-256-GCM:none");
66 
68 
69  if (have_chacha)
70  {
72  assert_string_equal(mutate_ncp_cipher_list("BF-CBC:CHACHA20-POLY1305", &gc),
73  bf_chacha);
74  }
75  else
76  {
78  }
79 
80  /* For testing that with OpenSSL 1.1.0+ that also accepts ciphers in
81  * a different spelling the normalised cipher output is the same */
82  bool have_chacha_mixed_case = cipher_kt_get("ChaCha20-Poly1305");
83  if (have_chacha_mixed_case)
84  {
85  assert_string_equal(mutate_ncp_cipher_list("BF-CBC:ChaCha20-Poly1305", &gc),
86  bf_chacha);
87  }
88 
89  assert_ptr_equal(mutate_ncp_cipher_list("vollbit", &gc), NULL);
90  assert_ptr_equal(mutate_ncp_cipher_list("AES-256-GCM:vollbit", &gc), NULL);
92 
94  "ChaCha20-Poly1305:ChaCha20-Poly1305:ChaCha20-Poly1305:"
95  "ChaCha20-Poly1305:ChaCha20-Poly1305:ChaCha20-Poly1305:"
96  "ChaCha20-Poly1305", &gc), NULL);
97 
98 #ifdef ENABLE_CRYPTO_OPENSSL
99  assert_string_equal(mutate_ncp_cipher_list("id-aes128-GCM:id-aes256-GCM",
100  &gc), "AES-128-GCM:AES-256-GCM");
101 #else
103  &gc), "BF-CBC");
104 #endif
105  gc_free(&gc);
106 }
107 
108 static void
110 {
111  struct gc_arena gc = gc_new();
112  const char *client_peer_info;
113  const char *peer_list;
114 
115  client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2";
116  peer_list = tls_peer_ncp_list(client_peer_info, &gc);
117  assert_string_equal(aes_ciphers,peer_list);
118  assert_true(tls_peer_supports_ncp(client_peer_info));
119 
120  client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2\nIV_CIPHERS=BF-CBC";
121  peer_list = tls_peer_ncp_list(client_peer_info, &gc);
122  assert_string_equal("BF-CBC", peer_list);
123  assert_true(tls_peer_supports_ncp(client_peer_info));
124 
125  client_peer_info = "IV_NCP=2\nIV_CIPHERS=BF-CBC:FOO-BAR\nIV_BAR=7";
126  peer_list = tls_peer_ncp_list(client_peer_info, &gc);
127  assert_string_equal("BF-CBC:FOO-BAR", peer_list);
128  assert_true(tls_peer_supports_ncp(client_peer_info));
129 
130  client_peer_info = "IV_CIPHERS=BF-CBC:FOO-BAR\nIV_BAR=7";
131  peer_list = tls_peer_ncp_list(client_peer_info, &gc);
132  assert_string_equal("BF-CBC:FOO-BAR", peer_list);
133  assert_true(tls_peer_supports_ncp(client_peer_info));
134 
135  client_peer_info = "IV_YOLO=NO\nIV_BAR=7";
136  peer_list = tls_peer_ncp_list(client_peer_info, &gc);
137  assert_string_equal("", peer_list);
138  assert_false(tls_peer_supports_ncp(client_peer_info));
139 
140  peer_list = tls_peer_ncp_list(NULL, &gc);
141  assert_string_equal("", peer_list);
142  assert_false(tls_peer_supports_ncp(client_peer_info));
143 
144  gc_free(&gc);
145 }
146 
147 static void
148 test_poor_man(void **state)
149 {
150  struct gc_arena gc = gc_new();
151  char *best_cipher;
152 
153  const char *serverlist = "CHACHA20_POLY1305:AES-128-GCM";
154  const char *serverlistbfcbc = "CHACHA20_POLY1305:AES-128-GCM:BF-CBC:none";
155 
156  best_cipher = ncp_get_best_cipher(serverlist,
157  "IV_YOLO=NO\nIV_BAR=7",
158  "BF-CBC", &gc);
159 
160  assert_ptr_equal(best_cipher, NULL);
161 
162 
163  best_cipher = ncp_get_best_cipher(serverlistbfcbc,
164  "IV_YOLO=NO\nIV_BAR=7",
165  "BF-CBC", &gc);
166 
167  assert_string_equal(best_cipher, "BF-CBC");
168 
169 
170  best_cipher = ncp_get_best_cipher(serverlist,
171  "IV_NCP=1\nIV_BAR=7",
172  "AES-128-GCM", &gc);
173 
174  assert_string_equal(best_cipher, "AES-128-GCM");
175 
176  best_cipher = ncp_get_best_cipher(serverlist, NULL,
177  "AES-128-GCM", &gc);
178 
179  assert_string_equal(best_cipher, "AES-128-GCM");
180 
181  best_cipher = ncp_get_best_cipher(serverlist, NULL,
182  "none", &gc);
183  assert_ptr_equal(best_cipher, NULL);
184 
185  best_cipher = ncp_get_best_cipher(serverlistbfcbc, NULL,
186  "none", &gc);
187  assert_string_equal(best_cipher, "none");
188 
189  best_cipher = ncp_get_best_cipher(serverlist, NULL,NULL, &gc);
190  assert_ptr_equal(best_cipher, NULL);
191 
192  gc_free(&gc);
193 }
194 
195 
196 static void
197 test_ncp_best(void **state)
198 {
199  struct gc_arena gc = gc_new();
200  char *best_cipher;
201 
202  const char *serverlist = "CHACHA20_POLY1305:AES-128-GCM:AES-256-GCM";
203 
204  best_cipher = ncp_get_best_cipher(serverlist,
205  "IV_YOLO=NO\nIV_NCP=2\nIV_BAR=7",
206  "BF-CBC", &gc);
207 
208  assert_string_equal(best_cipher, "AES-128-GCM");
209 
210  /* Best cipher is in --cipher of client */
211  best_cipher = ncp_get_best_cipher(serverlist, "IV_NCP=2\nIV_BAR=7",
212  "CHACHA20_POLY1305", &gc);
213 
214  assert_string_equal(best_cipher, "CHACHA20_POLY1305");
215 
216  /* Best cipher is in --cipher of client */
217  best_cipher = ncp_get_best_cipher(serverlist, "IV_CIPHERS=AES-128-GCM",
218  "AES-256-CBC", &gc);
219 
220 
221  assert_string_equal(best_cipher, "AES-128-GCM");
222 
223  /* IV_NCP=2 should be ignored if IV_CIPHERS is sent */
224  best_cipher = ncp_get_best_cipher(serverlist,
225  "IV_FOO=7\nIV_CIPHERS=AES-256-GCM\nIV_NCP=2",
226  "AES-256-CBC", &gc);
227 
228  assert_string_equal(best_cipher, "AES-256-GCM");
229 
230 
231  gc_free(&gc);
232 }
233 
234 
235 
236 const struct CMUnitTest ncp_tests[] = {
241 };
242 
243 
244 int
245 main(void)
246 {
247 #if defined(ENABLE_CRYPTO_OPENSSL)
248  OpenSSL_add_all_algorithms();
249 #endif
250  return cmocka_run_group_tests(ncp_tests, NULL, NULL);
251 }
#define assert_true(c)
Definition: cmocka.h:1045
#define cmocka_unit_test(f)
Initializes a CMUnitTest structure.
Definition: cmocka.h:1653
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
#define assert_ptr_equal(a, b)
Definition: cmocka.h:1136
#define ASSERT(x)
Definition: error.h:204
const char * aes_ciphers
Definition: test_ncp.c:44
bool tls_peer_supports_ncp(const char *peer_info)
Returns whether the client supports NCP either by announcing IV_NCP>=2 or the IV_CIPHERS list...
Definition: ssl_ncp.c:79
#define assert_string_equal(a, b)
Definition: cmocka.h:1214
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
int main(void)
Definition: test_ncp.c:245
bool key_state_export_keying_material(struct tls_session *session, const char *label, size_t label_size, void *ekm, size_t ekm_size)
Keying Material Exporters [RFC 5705] allows additional keying material to be derived from existing TL...
Definition: test_ncp.c:50
char * ncp_get_best_cipher(const char *server_list, const char *peer_info, const char *remote_cipher, struct gc_arena *gc)
Iterates through the ciphers in server_list and return the first cipher that is also supported by the...
Definition: ssl_ncp.c:230
static void test_poor_man(void **state)
Definition: test_ncp.c:148
const struct CMUnitTest ncp_tests[]
Definition: test_ncp.c:236
Security parameter state of a single session within a VPN tunnel.
Definition: ssl_common.h:454
const char * tls_peer_ncp_list(const char *peer_info, struct gc_arena *gc)
Returns the support cipher list from the peer according to the IV_NCP and IV_CIPHER values in peer_in...
Definition: ssl_ncp.c:209
#define cmocka_run_group_tests(group_tests, group_setup, group_teardown)
Definition: cmocka.h:1749
static void test_extract_client_ciphers(void **state)
Definition: test_ncp.c:109
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
const char * bf_chacha
Definition: test_ncp.c:43
static void test_check_ncp_ciphers_list(void **state)
Definition: test_ncp.c:58
static void test_ncp_best(void **state)
Definition: test_ncp.c:197
char * mutate_ncp_cipher_list(const char *list, struct gc_arena *gc)
Check whether the ciphers in the supplied list are supported.
Definition: ssl_ncp.c:97
#define assert_false(c)
Definition: cmocka.h:1063
const cipher_kt_t * cipher_kt_get(const char *ciphername)
Return cipher parameters, based on the given cipher name.