]>
Commit | Line | Data |
---|---|---|
1828f9c1 AS |
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 | * | |
1800d77e | 8 | * Copyright (C) 2019-2022 Arne Schwabe <arne@rfc2549.org> |
1828f9c1 AS |
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> | |
1828f9c1 AS |
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"; | |
c07f95f3 | 44 | const char *aes_chacha = "AES-128-CBC:CHACHA20-POLY1305"; |
1828f9c1 AS |
45 | const char *aes_ciphers = "AES-256-GCM:AES-128-GCM"; |
46 | ||
8c72d798 AS |
47 | |
48 | /* Define this function here as dummy since including the ssl_*.c files | |
49 | * leads to having to include even more unrelated code */ | |
50 | bool | |
51 | key_state_export_keying_material(struct tls_session *session, | |
abe49856 | 52 | const char *label, size_t label_size, |
8c72d798 AS |
53 | void *ekm, size_t ekm_size) |
54 | { | |
55 | ASSERT(0); | |
56 | } | |
57 | ||
1828f9c1 AS |
58 | static void |
59 | test_check_ncp_ciphers_list(void **state) | |
60 | { | |
be453156 | 61 | struct gc_arena gc = gc_new(); |
ce2954a0 AS |
62 | bool have_chacha = cipher_valid("CHACHA20-POLY1305"); |
63 | bool have_blowfish = cipher_valid("BF-CBC"); | |
1828f9c1 | 64 | |
c018fc00 AS |
65 | assert_string_equal(mutate_ncp_cipher_list("none", &gc), "none"); |
66 | assert_string_equal(mutate_ncp_cipher_list("AES-256-GCM:none", &gc), | |
67 | "AES-256-GCM:none"); | |
be453156 AS |
68 | |
69 | assert_string_equal(mutate_ncp_cipher_list(aes_ciphers, &gc), aes_ciphers); | |
70 | ||
71 | if (have_chacha) | |
c07f95f3 AS |
72 | { |
73 | assert_string_equal(mutate_ncp_cipher_list(aes_chacha, &gc), aes_chacha); | |
74 | } | |
75 | ||
76 | if (have_chacha && have_blowfish) | |
be453156 AS |
77 | { |
78 | assert_string_equal(mutate_ncp_cipher_list(bf_chacha, &gc), bf_chacha); | |
79 | assert_string_equal(mutate_ncp_cipher_list("BF-CBC:CHACHA20-POLY1305", &gc), | |
80 | bf_chacha); | |
81 | } | |
82 | else | |
83 | { | |
84 | assert_ptr_equal(mutate_ncp_cipher_list(bf_chacha, &gc), NULL); | |
85 | } | |
86 | ||
76604450 AS |
87 | /* Check that optional ciphers work */ |
88 | assert_string_equal(mutate_ncp_cipher_list("AES-256-GCM:?vollbit:AES-128-GCM", &gc), | |
89 | aes_ciphers); | |
90 | ||
91 | /* Check that optional ciphers work */ | |
92 | assert_string_equal(mutate_ncp_cipher_list("?AES-256-GCM:?AES-128-GCM", &gc), | |
93 | aes_ciphers); | |
94 | ||
95 | /* All unsupported should still yield an empty list */ | |
96 | assert_ptr_equal(mutate_ncp_cipher_list("?kugelfisch:?grasshopper", &gc), NULL); | |
97 | ||
86843385 AS |
98 | /* If the last is optional, previous invalid ciphers should be ignored */ |
99 | assert_ptr_equal(mutate_ncp_cipher_list("Vollbit:Littlebit:AES-256-CBC:BF-CBC:?nixbit", &gc), NULL); | |
100 | ||
be453156 | 101 | /* For testing that with OpenSSL 1.1.0+ that also accepts ciphers in |
da1574ef | 102 | * a different spelling the normalised cipher output is the same */ |
ce2954a0 | 103 | bool have_chacha_mixed_case = cipher_valid("ChaCha20-Poly1305"); |
be453156 AS |
104 | if (have_chacha_mixed_case) |
105 | { | |
c07f95f3 AS |
106 | assert_string_equal(mutate_ncp_cipher_list("AES-128-CBC:ChaCha20-Poly1305", &gc), |
107 | aes_chacha); | |
be453156 AS |
108 | } |
109 | ||
110 | assert_ptr_equal(mutate_ncp_cipher_list("vollbit", &gc), NULL); | |
111 | assert_ptr_equal(mutate_ncp_cipher_list("AES-256-GCM:vollbit", &gc), NULL); | |
112 | assert_ptr_equal(mutate_ncp_cipher_list("", &gc), NULL); | |
113 | ||
114 | assert_ptr_equal(mutate_ncp_cipher_list( | |
115 | "ChaCha20-Poly1305:ChaCha20-Poly1305:ChaCha20-Poly1305:" | |
116 | "ChaCha20-Poly1305:ChaCha20-Poly1305:ChaCha20-Poly1305:" | |
117 | "ChaCha20-Poly1305", &gc), NULL); | |
118 | ||
119 | #ifdef ENABLE_CRYPTO_OPENSSL | |
120 | assert_string_equal(mutate_ncp_cipher_list("id-aes128-GCM:id-aes256-GCM", | |
121 | &gc), "AES-128-GCM:AES-256-GCM"); | |
122 | #else | |
0e075c0e MF |
123 | if (have_blowfish) |
124 | { | |
125 | assert_string_equal(mutate_ncp_cipher_list("BLOWFISH-CBC", | |
126 | &gc), "BF-CBC"); | |
127 | } | |
be453156 AS |
128 | #endif |
129 | gc_free(&gc); | |
1828f9c1 AS |
130 | } |
131 | ||
132 | static void | |
133 | test_extract_client_ciphers(void **state) | |
134 | { | |
135 | struct gc_arena gc = gc_new(); | |
136 | const char *client_peer_info; | |
137 | const char *peer_list; | |
138 | ||
139 | client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2"; | |
140 | peer_list = tls_peer_ncp_list(client_peer_info, &gc); | |
141 | assert_string_equal(aes_ciphers,peer_list); | |
142 | assert_true(tls_peer_supports_ncp(client_peer_info)); | |
143 | ||
144 | client_peer_info = "foo=bar\nIV_foo=y\nIV_NCP=2\nIV_CIPHERS=BF-CBC"; | |
145 | peer_list = tls_peer_ncp_list(client_peer_info, &gc); | |
146 | assert_string_equal("BF-CBC", peer_list); | |
147 | assert_true(tls_peer_supports_ncp(client_peer_info)); | |
148 | ||
149 | client_peer_info = "IV_NCP=2\nIV_CIPHERS=BF-CBC:FOO-BAR\nIV_BAR=7"; | |
150 | peer_list = tls_peer_ncp_list(client_peer_info, &gc); | |
151 | assert_string_equal("BF-CBC:FOO-BAR", peer_list); | |
152 | assert_true(tls_peer_supports_ncp(client_peer_info)); | |
153 | ||
154 | client_peer_info = "IV_CIPHERS=BF-CBC:FOO-BAR\nIV_BAR=7"; | |
155 | peer_list = tls_peer_ncp_list(client_peer_info, &gc); | |
156 | assert_string_equal("BF-CBC:FOO-BAR", peer_list); | |
157 | assert_true(tls_peer_supports_ncp(client_peer_info)); | |
158 | ||
159 | client_peer_info = "IV_YOLO=NO\nIV_BAR=7"; | |
160 | peer_list = tls_peer_ncp_list(client_peer_info, &gc); | |
161 | assert_string_equal("", peer_list); | |
162 | assert_false(tls_peer_supports_ncp(client_peer_info)); | |
163 | ||
164 | peer_list = tls_peer_ncp_list(NULL, &gc); | |
165 | assert_string_equal("", peer_list); | |
166 | assert_false(tls_peer_supports_ncp(client_peer_info)); | |
167 | ||
168 | gc_free(&gc); | |
169 | } | |
170 | ||
171 | static void | |
172 | test_poor_man(void **state) | |
173 | { | |
174 | struct gc_arena gc = gc_new(); | |
175 | char *best_cipher; | |
176 | ||
be453156 | 177 | const char *serverlist = "CHACHA20_POLY1305:AES-128-GCM"; |
c018fc00 | 178 | const char *serverlistbfcbc = "CHACHA20_POLY1305:AES-128-GCM:BF-CBC:none"; |
1828f9c1 | 179 | |
2c1d8c33 AS |
180 | best_cipher = ncp_get_best_cipher(serverlist, |
181 | "IV_YOLO=NO\nIV_BAR=7", | |
182 | "BF-CBC", &gc); | |
183 | ||
184 | assert_ptr_equal(best_cipher, NULL); | |
185 | ||
186 | ||
187 | best_cipher = ncp_get_best_cipher(serverlistbfcbc, | |
1828f9c1 AS |
188 | "IV_YOLO=NO\nIV_BAR=7", |
189 | "BF-CBC", &gc); | |
190 | ||
191 | assert_string_equal(best_cipher, "BF-CBC"); | |
192 | ||
2c1d8c33 AS |
193 | |
194 | best_cipher = ncp_get_best_cipher(serverlist, | |
1828f9c1 AS |
195 | "IV_NCP=1\nIV_BAR=7", |
196 | "AES-128-GCM", &gc); | |
197 | ||
198 | assert_string_equal(best_cipher, "AES-128-GCM"); | |
199 | ||
2c1d8c33 | 200 | best_cipher = ncp_get_best_cipher(serverlist, NULL, |
1828f9c1 AS |
201 | "AES-128-GCM", &gc); |
202 | ||
203 | assert_string_equal(best_cipher, "AES-128-GCM"); | |
204 | ||
c018fc00 AS |
205 | best_cipher = ncp_get_best_cipher(serverlist, NULL, |
206 | "none", &gc); | |
207 | assert_ptr_equal(best_cipher, NULL); | |
208 | ||
209 | best_cipher = ncp_get_best_cipher(serverlistbfcbc, NULL, | |
210 | "none", &gc); | |
211 | assert_string_equal(best_cipher, "none"); | |
212 | ||
2c1d8c33 AS |
213 | best_cipher = ncp_get_best_cipher(serverlist, NULL,NULL, &gc); |
214 | assert_ptr_equal(best_cipher, NULL); | |
215 | ||
1828f9c1 AS |
216 | gc_free(&gc); |
217 | } | |
218 | ||
219 | ||
220 | static void | |
221 | test_ncp_best(void **state) | |
222 | { | |
223 | struct gc_arena gc = gc_new(); | |
224 | char *best_cipher; | |
225 | ||
be453156 | 226 | const char *serverlist = "CHACHA20_POLY1305:AES-128-GCM:AES-256-GCM"; |
1828f9c1 | 227 | |
2c1d8c33 | 228 | best_cipher = ncp_get_best_cipher(serverlist, |
1828f9c1 AS |
229 | "IV_YOLO=NO\nIV_NCP=2\nIV_BAR=7", |
230 | "BF-CBC", &gc); | |
231 | ||
232 | assert_string_equal(best_cipher, "AES-128-GCM"); | |
233 | ||
234 | /* Best cipher is in --cipher of client */ | |
2c1d8c33 | 235 | best_cipher = ncp_get_best_cipher(serverlist, "IV_NCP=2\nIV_BAR=7", |
1828f9c1 AS |
236 | "CHACHA20_POLY1305", &gc); |
237 | ||
238 | assert_string_equal(best_cipher, "CHACHA20_POLY1305"); | |
239 | ||
240 | /* Best cipher is in --cipher of client */ | |
2c1d8c33 | 241 | best_cipher = ncp_get_best_cipher(serverlist, "IV_CIPHERS=AES-128-GCM", |
1828f9c1 AS |
242 | "AES-256-CBC", &gc); |
243 | ||
244 | ||
245 | assert_string_equal(best_cipher, "AES-128-GCM"); | |
246 | ||
247 | /* IV_NCP=2 should be ignored if IV_CIPHERS is sent */ | |
2c1d8c33 | 248 | best_cipher = ncp_get_best_cipher(serverlist, |
1828f9c1 AS |
249 | "IV_FOO=7\nIV_CIPHERS=AES-256-GCM\nIV_NCP=2", |
250 | "AES-256-CBC", &gc); | |
251 | ||
252 | assert_string_equal(best_cipher, "AES-256-GCM"); | |
253 | ||
254 | ||
255 | gc_free(&gc); | |
256 | } | |
257 | ||
258 | ||
259 | ||
1828f9c1 AS |
260 | const struct CMUnitTest ncp_tests[] = { |
261 | cmocka_unit_test(test_check_ncp_ciphers_list), | |
262 | cmocka_unit_test(test_extract_client_ciphers), | |
263 | cmocka_unit_test(test_poor_man), | |
264 | cmocka_unit_test(test_ncp_best) | |
265 | }; | |
266 | ||
267 | ||
be453156 AS |
268 | int |
269 | main(void) | |
1828f9c1 AS |
270 | { |
271 | #if defined(ENABLE_CRYPTO_OPENSSL) | |
272 | OpenSSL_add_all_algorithms(); | |
273 | #endif | |
274 | return cmocka_run_group_tests(ncp_tests, NULL, NULL); | |
275 | } |