aboutsummaryrefslogtreecommitdiff
path: root/projects/openvpn/fuzz_crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'projects/openvpn/fuzz_crypto.c')
-rw-r--r--projects/openvpn/fuzz_crypto.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/projects/openvpn/fuzz_crypto.c b/projects/openvpn/fuzz_crypto.c
new file mode 100644
index 000000000..e9a851be0
--- /dev/null
+++ b/projects/openvpn/fuzz_crypto.c
@@ -0,0 +1,257 @@
+/* Copyright 2021 Google LLC
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+
+#include "config.h"
+#include "syshead.h"
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "fuzz_verify_cert.h"
+#include "misc.h"
+#include "manage.h"
+#include "otime.h"
+#include "base64.h"
+#include "ssl_verify.h"
+#include "ssl_verify_backend.h"
+
+#include "fuzz_randomizer.h"
+
+static void key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key,
+ size_t key_len) {
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher);
+
+ /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */
+ if (cipher_kt_mode_aead(cipher_kt)) {
+ size_t impl_iv_len = 0;
+ ASSERT(cipher_kt_iv_size(cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN);
+ impl_iv_len = cipher_kt_iv_size(cipher_kt) - sizeof(packet_id_type);
+ ASSERT(impl_iv_len <= OPENVPN_MAX_IV_LENGTH);
+ ASSERT(impl_iv_len <= key_len);
+ memcpy(ctx->implicit_iv, key, impl_iv_len);
+ ctx->implicit_iv_len = impl_iv_len;
+ }
+}
+
+static int init_frame(struct frame *frame) {
+ frame->link_mtu = fuzz_randomizer_get_int(100, 1000);
+ frame->extra_buffer = fuzz_randomizer_get_int(100, 1000);
+ frame->link_mtu_dynamic = fuzz_randomizer_get_int(100, 1000);
+ frame->extra_frame = fuzz_randomizer_get_int(100, 1000);
+ frame->extra_tun = fuzz_randomizer_get_int(100, 1000);
+ frame->extra_link = fuzz_randomizer_get_int(100, 1000);
+ frame->align_flags = 0;
+ frame->align_adjust = 0;
+ if (TUN_MTU_SIZE(frame) <= 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ OPENSSL_malloc_init();
+ SSL_library_init();
+ ERR_load_crypto_strings();
+
+ OpenSSL_add_all_algorithms();
+ OpenSSL_add_ssl_algorithms();
+
+ SSL_load_error_strings();
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ fuzz_random_init(data, size);
+ fuzz_success = 1;
+ bool key_ctx_dec_initialized = false;
+ bool key_ctx_enc_initialized = false;
+ struct key_ctx key_ctx_dec;
+ memset(&key_ctx_dec, 0, sizeof(struct key_ctx));
+ struct key_ctx key_ctx_enc;
+ memset(&key_ctx_enc, 0, sizeof(struct key_ctx));
+
+ struct gc_arena gc;
+ struct tls_session *session = NULL;
+ X509 *x509 = NULL;
+ gc = gc_new();
+
+ gb_init();
+
+ // Read key file
+ struct key2 key2;
+ char *keydata = gb_get_random_string();
+ read_key_file(&key2, keydata, RKF_INLINE);
+
+ // init key type
+ struct key_type kt;
+ memset(&kt, 0, sizeof(struct key_type));
+
+ char *ciphername = gb_get_random_string();
+ char *authname = gb_get_random_string();
+ bool key_type_initialized = false;
+
+ if (strcmp(ciphername, "AES-256-GCM") == 0 ||
+ strcmp(ciphername, "AES-128-GCM") == 0 ||
+ strcmp(ciphername, "AES-192-GCM") == 0 ||
+ strcmp(ciphername, "CAMELLIA-128-CFB128") == 0) {
+
+ int v = fuzz_randomizer_get_int(0, 1);
+ if (v == 0) {
+ init_key_type(&kt, ciphername, authname, true, 0);
+ } else {
+ init_key_type(&kt, ciphername, authname, false, 0);
+ }
+ key_type_initialized = true;
+ }
+
+ if (fuzz_success == 0) {
+ goto cleanup;
+ }
+
+ // Generate key.
+ // Identify which one we should do, read or generate a random key.
+ int c = fuzz_randomizer_get_int(0, 1);
+ const uint8_t d[1024];
+ int key_read = 0;
+ struct key key;
+ if (c == 0) {
+ if (fuzz_get_random_data(d, 1024) != 1024) {
+ struct buffer buf = alloc_buf(1024);
+ buf_write(&buf, d, 1024);
+ if (read_key(&key, &kt, &buf) == 1) {
+ key_read = 1;
+ }
+ free_buf(&buf);
+ }
+ }
+ else {
+ if (key_type_initialized == true) {
+ generate_key_random(&key, &kt);
+ }
+ }
+
+ if (fuzz_success == 0) {
+ goto cleanup;
+ }
+ key_read = 1;
+
+ // init decryption context
+ if (key_type_initialized && key_read) {
+ init_key_ctx(&key_ctx_dec, &key, &kt, OPENVPN_OP_DECRYPT, "x");
+ key_ctx_update_implicit_iv(&key_ctx_dec, &(key.hmac), MAX_HMAC_KEY_LENGTH);
+ key_ctx_dec_initialized = true;
+ }
+
+ // init encryption context
+ if (key_type_initialized && key_read) {
+ init_key_ctx(&key_ctx_enc, &key, &kt, OPENVPN_OP_DECRYPT, "x");
+ key_ctx_update_implicit_iv(&key_ctx_enc, &(key.hmac), MAX_HMAC_KEY_LENGTH);
+ key_ctx_enc_initialized = true;
+ }
+
+ // perform encryption
+ struct frame frame;
+ memset(&frame, 0, sizeof(struct frame));
+ if (key_ctx_enc_initialized == true && key_ctx_dec_initialized == true &&
+ init_frame(&frame) == 0) {
+ struct crypto_options opt;
+ memset(&opt, 0, sizeof(opt));
+ opt.pid_persist = NULL;
+ opt.key_ctx_bi.encrypt = key_ctx_enc;
+ opt.key_ctx_bi.decrypt = key_ctx_dec;
+ opt.key_ctx_bi.initialized = true;
+ opt.packet_id.rec.initialized = true;
+ opt.packet_id.rec.seq_list = NULL;
+ opt.packet_id.rec.name = NULL;
+
+ void *buf_p;
+
+ struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
+ struct buffer work = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
+ struct buffer src = alloc_buf_gc(TUN_MTU_SIZE(&(frame)), &gc);
+ struct buffer buf = clear_buf();
+
+ int x = fuzz_randomizer_get_int(1, TUN_MTU_SIZE(&frame));
+
+ ASSERT(buf_init(&work, FRAME_HEADROOM(&(frame))));
+ ASSERT(buf_init(&src, 0));
+ src.len = x;
+ ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
+
+ buf = work;
+ buf_p = buf_write_alloc(&buf, BLEN(&src));
+ ASSERT(buf_p);
+ memcpy(buf_p, BPTR(&src), BLEN(&src));
+
+ ASSERT(buf_init(&encrypt_workspace, FRAME_HEADROOM(&(frame))));
+
+ openvpn_encrypt(&buf, encrypt_workspace, &opt);
+ }
+
+ // perform decryption
+ memset(&frame, 0, sizeof(struct frame));
+ if (key_ctx_dec_initialized == true && key_ctx_enc_initialized == true &&
+ init_frame(&frame) == 0) {
+ struct crypto_options opt;
+ memset(&opt, 0, sizeof(opt));
+ opt.pid_persist = NULL;
+ opt.key_ctx_bi.encrypt = key_ctx_enc;
+ opt.key_ctx_bi.decrypt = key_ctx_dec;
+ opt.key_ctx_bi.initialized = true;
+ opt.packet_id.rec.initialized = true;
+ opt.packet_id.rec.seq_list = NULL;
+ opt.packet_id.rec.name = NULL;
+
+ void *buf_p;
+
+ struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
+ struct buffer work = alloc_buf_gc(BUF_SIZE(&(frame)), &gc);
+ struct buffer src = alloc_buf_gc(TUN_MTU_SIZE(&(frame)), &gc);
+ struct buffer buf = clear_buf();
+
+ int x = fuzz_randomizer_get_int(1, TUN_MTU_SIZE(&frame));
+
+ ASSERT(buf_init(&work, FRAME_HEADROOM(&(frame))));
+ ASSERT(buf_init(&src, 0));
+ src.len = x;
+ ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
+
+ buf = work;
+ buf_p = buf_write_alloc(&buf, BLEN(&src));
+ ASSERT(buf_p);
+ memcpy(buf_p, BPTR(&src), BLEN(&src));
+
+ ASSERT(buf_init(&decrypt_workspace, FRAME_HEADROOM(&(frame))));
+
+ openvpn_decrypt(&buf, decrypt_workspace, &opt, &frame, BPTR(&buf));
+ }
+
+cleanup:
+ // cleanup
+ gc_free(&gc);
+
+ if (key_ctx_dec_initialized == true) {
+ free_key_ctx(&key_ctx_dec);
+ }
+
+ if (key_ctx_enc_initialized == true) {
+ free_key_ctx(&key_ctx_enc);
+ }
+ fuzz_random_destroy();
+
+ gb_cleanup();
+
+ return 0;
+}