This test is reusing code from --test-crypto but is modified to not rely
on the static key functionality and also only tests the most common
algorithm. So it does not yet completely replace --test-crypto
Change-Id: Ifa5ae96165d17b3cae4afc53e844bb34d1610e58
Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Message-Id: <20240208085749.869-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg28195.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -44,6 +44,9 @@ |
| 44 | 44 |
#include "ssl_verify_backend.h" |
| 45 | 45 |
#include "win32.h" |
| 46 | 46 |
#include "test_common.h" |
| 47 |
+#include "ssl.h" |
|
| 48 |
+#include "buffer.h" |
|
| 49 |
+#include "packet_id.h" |
|
| 47 | 50 |
|
| 48 | 51 |
/* Mock function to be allowed to include win32.c which is required for |
| 49 | 52 |
* getting the temp directory */ |
| ... | ... |
@@ -120,20 +123,238 @@ crypto_pem_encode_certificate(void **state) |
| 120 | 120 |
gc_free(&gc); |
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 |
+static void |
|
| 124 |
+init_implicit_iv(struct crypto_options *co) |
|
| 125 |
+{
|
|
| 126 |
+ cipher_ctx_t *cipher = co->key_ctx_bi.encrypt.cipher; |
|
| 127 |
+ |
|
| 128 |
+ if (cipher_ctx_mode_aead(cipher)) |
|
| 129 |
+ {
|
|
| 130 |
+ size_t impl_iv_len = cipher_ctx_iv_length(cipher) - sizeof(packet_id_type); |
|
| 131 |
+ ASSERT(cipher_ctx_iv_length(cipher) <= OPENVPN_MAX_IV_LENGTH); |
|
| 132 |
+ ASSERT(cipher_ctx_iv_length(cipher) >= OPENVPN_AEAD_MIN_IV_LEN); |
|
| 133 |
+ |
|
| 134 |
+ /* Generate dummy implicit IV */ |
|
| 135 |
+ ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv, |
|
| 136 |
+ OPENVPN_MAX_IV_LENGTH)); |
|
| 137 |
+ co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len; |
|
| 138 |
+ |
|
| 139 |
+ memcpy(co->key_ctx_bi.decrypt.implicit_iv, |
|
| 140 |
+ co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH); |
|
| 141 |
+ co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len; |
|
| 142 |
+ } |
|
| 143 |
+} |
|
| 144 |
+ |
|
| 145 |
+static void |
|
| 146 |
+init_frame_parameters(struct frame *frame) |
|
| 147 |
+{
|
|
| 148 |
+ int overhead = 0; |
|
| 149 |
+ |
|
| 150 |
+ /* tls-auth and tls-crypt */ |
|
| 151 |
+ overhead += 128; |
|
| 152 |
+ |
|
| 153 |
+ /* TCP length field and opcode */ |
|
| 154 |
+ overhead += 3; |
|
| 155 |
+ |
|
| 156 |
+ /* ACK array and remote SESSION ID (part of the ACK array) */ |
|
| 157 |
+ overhead += ACK_SIZE(RELIABLE_ACK_SIZE); |
|
| 158 |
+ |
|
| 159 |
+ /* Previous OpenVPN version calculated the maximum size and buffer of a |
|
| 160 |
+ * control frame depending on the overhead of the data channel frame |
|
| 161 |
+ * overhead and limited its maximum size to 1250. Since control frames |
|
| 162 |
+ * also need to fit into data channel buffer we have the same |
|
| 163 |
+ * default of 1500 + 100 as data channel buffers have. Increasing |
|
| 164 |
+ * control channel mtu beyond this limit also increases the data channel |
|
| 165 |
+ * buffers */ |
|
| 166 |
+ int tls_mtu = 1500; |
|
| 167 |
+ frame->buf.payload_size = tls_mtu + 100; |
|
| 168 |
+ |
|
| 169 |
+ frame->buf.headroom = overhead; |
|
| 170 |
+ frame->buf.tailroom = overhead; |
|
| 171 |
+ |
|
| 172 |
+ frame->tun_mtu = tls_mtu; |
|
| 173 |
+ |
|
| 174 |
+} |
|
| 175 |
+ |
|
| 176 |
+static void |
|
| 177 |
+do_data_channel_round_trip(struct crypto_options *co) |
|
| 178 |
+{
|
|
| 179 |
+ struct gc_arena gc = gc_new(); |
|
| 180 |
+ |
|
| 181 |
+ /* initialise frame for the test */ |
|
| 182 |
+ struct frame frame; |
|
| 183 |
+ init_frame_parameters(&frame); |
|
| 184 |
+ |
|
| 185 |
+ struct buffer src = alloc_buf_gc(frame.buf.payload_size, &gc); |
|
| 186 |
+ struct buffer work = alloc_buf_gc(BUF_SIZE(&frame), &gc); |
|
| 187 |
+ struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc); |
|
| 188 |
+ struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc); |
|
| 189 |
+ struct buffer buf = clear_buf(); |
|
| 190 |
+ void *buf_p; |
|
| 191 |
+ |
|
| 192 |
+ /* init work */ |
|
| 193 |
+ ASSERT(buf_init(&work, frame.buf.headroom)); |
|
| 194 |
+ |
|
| 195 |
+ init_implicit_iv(co); |
|
| 196 |
+ update_time(); |
|
| 197 |
+ |
|
| 198 |
+ /* Test encryption, decryption for all packet sizes */ |
|
| 199 |
+ for (int i = 1; i <= frame.buf.payload_size; ++i) |
|
| 200 |
+ {
|
|
| 201 |
+ |
|
| 202 |
+ /* msg(M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); */ |
|
| 203 |
+ |
|
| 204 |
+ /* |
|
| 205 |
+ * Load src with random data. |
|
| 206 |
+ */ |
|
| 207 |
+ ASSERT(buf_init(&src, 0)); |
|
| 208 |
+ ASSERT(i <= src.capacity); |
|
| 209 |
+ src.len = i; |
|
| 210 |
+ ASSERT(rand_bytes(BPTR(&src), BLEN(&src))); |
|
| 211 |
+ |
|
| 212 |
+ /* copy source to input buf */ |
|
| 213 |
+ buf = work; |
|
| 214 |
+ buf_p = buf_write_alloc(&buf, BLEN(&src)); |
|
| 215 |
+ ASSERT(buf_p); |
|
| 216 |
+ memcpy(buf_p, BPTR(&src), BLEN(&src)); |
|
| 217 |
+ |
|
| 218 |
+ /* initialize work buffer with buf.headroom bytes of prepend capacity */ |
|
| 219 |
+ ASSERT(buf_init(&encrypt_workspace, frame.buf.headroom)); |
|
| 220 |
+ |
|
| 221 |
+ /* encrypt */ |
|
| 222 |
+ openvpn_encrypt(&buf, encrypt_workspace, co); |
|
| 223 |
+ |
|
| 224 |
+ /* decrypt */ |
|
| 225 |
+ openvpn_decrypt(&buf, decrypt_workspace, co, &frame, BPTR(&buf)); |
|
| 226 |
+ |
|
| 227 |
+ /* compare */ |
|
| 228 |
+ assert_int_equal(buf.len, src.len); |
|
| 229 |
+ assert_memory_equal(BPTR(&src), BPTR(&buf), i); |
|
| 230 |
+ |
|
| 231 |
+ } |
|
| 232 |
+ gc_free(&gc); |
|
| 233 |
+} |
|
| 234 |
+ |
|
| 235 |
+ |
|
| 236 |
+ |
|
| 237 |
+struct crypto_options |
|
| 238 |
+init_crypto_options(const char *cipher, const char *auth) |
|
| 239 |
+{
|
|
| 240 |
+ struct key2 key2 = { .n = 2};
|
|
| 241 |
+ |
|
| 242 |
+ ASSERT(rand_bytes(key2.keys[0].cipher, sizeof(key2.keys[0].cipher))); |
|
| 243 |
+ ASSERT(rand_bytes(key2.keys[0].hmac, sizeof(key2.keys[0].hmac))); |
|
| 244 |
+ ASSERT(rand_bytes(key2.keys[1].cipher, sizeof(key2.keys[1].cipher))); |
|
| 245 |
+ ASSERT(rand_bytes(key2.keys[1].hmac, sizeof(key2.keys)[1].hmac)); |
|
| 246 |
+ |
|
| 247 |
+ struct crypto_options co = { 0 };
|
|
| 248 |
+ |
|
| 249 |
+ struct key_type kt = create_kt(cipher, auth, "ssl-test"); |
|
| 250 |
+ |
|
| 251 |
+ init_key_ctx_bi(&co.key_ctx_bi, &key2, 0, &kt, "unit-test-ssl"); |
|
| 252 |
+ packet_id_init(&co.packet_id, 5, 5, "UNITTEST", 0); |
|
| 253 |
+ |
|
| 254 |
+ return co; |
|
| 255 |
+} |
|
| 256 |
+ |
|
| 257 |
+static void |
|
| 258 |
+uninit_crypto_options(struct crypto_options *co) |
|
| 259 |
+{
|
|
| 260 |
+ packet_id_free(&co->packet_id); |
|
| 261 |
+ free_key_ctx_bi(&co->key_ctx_bi); |
|
| 262 |
+ |
|
| 263 |
+} |
|
| 264 |
+ |
|
| 265 |
+ |
|
| 266 |
+static void |
|
| 267 |
+run_data_channel_with_cipher(const char *cipher, const char *auth) |
|
| 268 |
+{
|
|
| 269 |
+ struct crypto_options co = init_crypto_options(cipher, auth); |
|
| 270 |
+ do_data_channel_round_trip(&co); |
|
| 271 |
+ uninit_crypto_options(&co); |
|
| 272 |
+} |
|
| 273 |
+ |
|
| 274 |
+static void |
|
| 275 |
+test_data_channel_roundtrip_aes_128_gcm(void **state) |
|
| 276 |
+{
|
|
| 277 |
+ run_data_channel_with_cipher("AES-128-GCM", "none");
|
|
| 278 |
+} |
|
| 279 |
+ |
|
| 280 |
+static void |
|
| 281 |
+test_data_channel_roundtrip_aes_192_gcm(void **state) |
|
| 282 |
+{
|
|
| 283 |
+ run_data_channel_with_cipher("AES-192-GCM", "none");
|
|
| 284 |
+} |
|
| 285 |
+ |
|
| 286 |
+static void |
|
| 287 |
+test_data_channel_roundtrip_aes_256_gcm(void **state) |
|
| 288 |
+{
|
|
| 289 |
+ run_data_channel_with_cipher("AES-256-GCM", "none");
|
|
| 290 |
+} |
|
| 291 |
+ |
|
| 292 |
+static void |
|
| 293 |
+test_data_channel_roundtrip_aes_128_cbc(void **state) |
|
| 294 |
+{
|
|
| 295 |
+ run_data_channel_with_cipher("AES-128-CBC", "SHA256");
|
|
| 296 |
+} |
|
| 297 |
+ |
|
| 298 |
+static void |
|
| 299 |
+test_data_channel_roundtrip_aes_192_cbc(void **state) |
|
| 300 |
+{
|
|
| 301 |
+ run_data_channel_with_cipher("AES-192-CBC", "SHA256");
|
|
| 302 |
+} |
|
| 303 |
+ |
|
| 304 |
+static void |
|
| 305 |
+test_data_channel_roundtrip_aes_256_cbc(void **state) |
|
| 306 |
+{
|
|
| 307 |
+ run_data_channel_with_cipher("AES-256-CBC", "SHA256");
|
|
| 308 |
+} |
|
| 309 |
+ |
|
| 310 |
+static void |
|
| 311 |
+test_data_channel_roundtrip_chacha20_poly1305(void **state) |
|
| 312 |
+{
|
|
| 313 |
+ if (!cipher_valid("ChaCha20-Poly1305"))
|
|
| 314 |
+ {
|
|
| 315 |
+ skip(); |
|
| 316 |
+ return; |
|
| 317 |
+ } |
|
| 318 |
+ run_data_channel_with_cipher("ChaCha20-Poly1305", "none");
|
|
| 319 |
+} |
|
| 320 |
+ |
|
| 321 |
+static void |
|
| 322 |
+test_data_channel_roundtrip_bf_cbc(void **state) |
|
| 323 |
+{
|
|
| 324 |
+ if (!cipher_valid("BF-CBC"))
|
|
| 325 |
+ {
|
|
| 326 |
+ skip(); |
|
| 327 |
+ return; |
|
| 328 |
+ } |
|
| 329 |
+ run_data_channel_with_cipher("BF-CBC", "SHA1");
|
|
| 330 |
+} |
|
| 331 |
+ |
|
| 332 |
+ |
|
| 123 | 333 |
int |
| 124 | 334 |
main(void) |
| 125 | 335 |
{
|
| 126 | 336 |
openvpn_unit_test_setup(); |
| 127 | 337 |
|
| 128 | 338 |
const struct CMUnitTest tests[] = {
|
| 129 |
- cmocka_unit_test(crypto_pem_encode_certificate) |
|
| 339 |
+ cmocka_unit_test(crypto_pem_encode_certificate), |
|
| 340 |
+ cmocka_unit_test(test_data_channel_roundtrip_aes_128_gcm), |
|
| 341 |
+ cmocka_unit_test(test_data_channel_roundtrip_aes_192_gcm), |
|
| 342 |
+ cmocka_unit_test(test_data_channel_roundtrip_aes_256_gcm), |
|
| 343 |
+ cmocka_unit_test(test_data_channel_roundtrip_chacha20_poly1305), |
|
| 344 |
+ cmocka_unit_test(test_data_channel_roundtrip_aes_128_cbc), |
|
| 345 |
+ cmocka_unit_test(test_data_channel_roundtrip_aes_192_cbc), |
|
| 346 |
+ cmocka_unit_test(test_data_channel_roundtrip_aes_256_cbc), |
|
| 347 |
+ cmocka_unit_test(test_data_channel_roundtrip_bf_cbc), |
|
| 130 | 348 |
}; |
| 131 | 349 |
|
| 132 | 350 |
#if defined(ENABLE_CRYPTO_OPENSSL) |
| 133 | 351 |
tls_init_lib(); |
| 134 | 352 |
#endif |
| 135 | 353 |
|
| 136 |
- int ret = cmocka_run_group_tests_name("crypto tests", tests, NULL, NULL);
|
|
| 354 |
+ int ret = cmocka_run_group_tests_name("ssl tests", tests, NULL, NULL);
|
|
| 137 | 355 |
|
| 138 | 356 |
#if defined(ENABLE_CRYPTO_OPENSSL) |
| 139 | 357 |
tls_free_lib(); |