258 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
| /* 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;
 | |
| }
 |