Skip to content

Commit

Permalink
Add libfuzzer integration for libsignal-protocol-c
Browse files Browse the repository at this point in the history
Now building and running the tests will create a new `fuzzer` target that
fuzzes deserialization and decryption with libfuzzer. As part of ctest
this will automatically run for 2048 iterations (takes 3 seconds on my
computer) in order to ensure that the fuzzer stays up to date. The fuzzer
can be run manually in order to fuzz for more iterations.

I've run this fuzzer for ~10 million iterations on my own computer and have
not found anything yet. But, my ultimate goal with this PR is to integrate
this repository with OSSFuzz per signalapp#136.

Note that tests/fuzzing_corpus/ includes an initial corpus for fuzzing so
that the fuzzer has somewhere to start. This was seeded with a couple of
valid serialized ciphertexts but the majority of it was synthesized by the
fuzzer over time.
  • Loading branch information
ddworken committed May 18, 2020
1 parent 3a83a4f commit fb11253
Show file tree
Hide file tree
Showing 52 changed files with 171 additions and 1 deletion.
20 changes: 20 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,23 @@ add_test(test_fingerprint ${TEST_PATH}/test_fingerprint)
add_executable(test_device_consistency test_device_consistency.c ${common_SRCS})
target_link_libraries(test_device_consistency ${LIBS})
add_test(test_device_consistency ${TEST_PATH}/test_device_consistency)

# Build the fuzzer executable
find_package(Check 0.9.10 REQUIRED)
find_package(OpenSSL 1.0 REQUIRED)
set(LIBS
${CHECK_LDFLAGS}
${OPENSSL_LIBRARIES}
signal-protocol-c
)
add_executable(fuzzer "fuzz_target.c" "test_common_openssl.c")
target_link_libraries(fuzzer ${LIBS})
set_target_properties(fuzzer
PROPERTIES COMPILE_FLAGS "-fsanitize=fuzzer-no-link,address"
)
set_target_properties(fuzzer
PROPERTIES LINK_FLAGS "-fsanitize=fuzzer,address -z muldefs"
)

# And run it for 2048 iterations as part of the test suite (should take at most a few seconds) to ensure it works
add_test(test_fuzzer ${TEST_PATH}/fuzzer -use_value_profile=1 -use_memmem=1 -use_cmp=1 -runs=2048)
138 changes: 138 additions & 0 deletions tests/fuzz_target.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#include "../src/protocol.c"
#include "../src/protocol.h"
#include "../src/session_builder.h"
#include "../src/session_cipher.h"
#include "../src/signal_protocol.h"
#include "test_common.c"
#include "test_common.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

signal_context *global_context;

static signal_protocol_address alice_address = {"+14159998888", 12, 1};

static signal_protocol_address bob_address = {"+14151231234", 12, 1};

ec_key_pair *bob_signed_pre_key;
int32_t bob_signed_pre_key_id;

// Fuzz the decrypt routine with Data and Size
extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int result = 0;

// Create a new context
result = signal_context_create(&global_context, 0);
assert(result == 0);

// Set up a test crypto provider using OpenSSL
setup_test_crypto_provider(global_context);

// Create Bob's data store
signal_protocol_store_context *bob_store = 0;
setup_test_store_context(&bob_store, global_context);

// Register Bob
uint32_t bob_local_registration_id = 0;
result = signal_protocol_identity_get_local_registration_id(
bob_store, &bob_local_registration_id);
assert(result == 0);

// Create his keys
ec_key_pair *bob_pre_key_pair = 0;
result = curve_generate_key_pair(global_context, &bob_pre_key_pair);
assert(result == 0);

ec_key_pair *bob_signed_pre_key_pair = 0;
result = curve_generate_key_pair(global_context, &bob_signed_pre_key_pair);
assert(result == 0);

ratchet_identity_key_pair *bob_identity_key_pair = 0;
result = signal_protocol_identity_get_key_pair(bob_store, &bob_identity_key_pair);
assert(result == 0);

signal_buffer *bob_signed_pre_key_public_serialized = 0;
result = ec_public_key_serialize(&bob_signed_pre_key_public_serialized,
ec_key_pair_get_public(bob_signed_pre_key_pair));
assert(result == 0);

signal_buffer *bob_signed_pre_key_signature = 0;
result = curve_calculate_signature(
global_context, &bob_signed_pre_key_signature,
ratchet_identity_key_pair_get_private(bob_identity_key_pair),
signal_buffer_data(bob_signed_pre_key_public_serialized),
signal_buffer_len(bob_signed_pre_key_public_serialized));
assert(result == 0);

session_pre_key_bundle *bob_pre_key = 0;
result = session_pre_key_bundle_create(
&bob_pre_key, bob_local_registration_id,
1, /* device ID */
31337, /* pre key ID */
ec_key_pair_get_public(bob_pre_key_pair),
22, /* signed pre key ID */
ec_key_pair_get_public(bob_signed_pre_key_pair),
signal_buffer_data(bob_signed_pre_key_signature),
signal_buffer_len(bob_signed_pre_key_signature),
ratchet_identity_key_pair_get_public(bob_identity_key_pair));
assert(result == 0);

// And add Bob's pre keys to his data store
session_pre_key *bob_pre_key_record = 0;
result = session_pre_key_create(
&bob_pre_key_record, session_pre_key_bundle_get_pre_key_id(bob_pre_key),
bob_pre_key_pair);
assert(result == 0);

result = signal_protocol_pre_key_store_key(bob_store, bob_pre_key_record);
assert(result == 0);

session_signed_pre_key *bob_signed_pre_key_record = 0;
result = session_signed_pre_key_create(
&bob_signed_pre_key_record, 22, time(0), bob_signed_pre_key_pair,
signal_buffer_data(bob_signed_pre_key_signature),
signal_buffer_len(bob_signed_pre_key_signature));
assert(result == 0);

result = signal_protocol_signed_pre_key_store_key(bob_store,
bob_signed_pre_key_record);
assert(result == 0);

session_cipher *bob_session_cipher = 0;
result = session_cipher_create(&bob_session_cipher, bob_store, &alice_address,
global_context);
assert(result == 0);

// Start of the actual fuzzing, attempt to deserialize the input data
pre_key_signal_message *incoming_message_bad = 0;
result = pre_key_signal_message_deserialize(
&incoming_message_bad, Data, Size, global_context);
if (result != 0) {
goto done;
}

// And if it deserialized okay, then decrypt it
signal_buffer *plaintext = 0;
result = session_cipher_decrypt_pre_key_signal_message(
bob_session_cipher, incoming_message_bad, 0, &plaintext);

// Then free everything
signal_buffer_free(plaintext);
done:
session_cipher_free(bob_session_cipher);
SIGNAL_UNREF(incoming_message_bad);
SIGNAL_UNREF(bob_pre_key);
SIGNAL_UNREF(bob_pre_key_pair);
SIGNAL_UNREF(bob_signed_pre_key_pair);
SIGNAL_UNREF(bob_identity_key_pair);
SIGNAL_UNREF(bob_signed_pre_key_record);
SIGNAL_UNREF(bob_pre_key_record);
signal_buffer_free(bob_signed_pre_key_public_serialized);
signal_buffer_free(bob_signed_pre_key_signature);
signal_protocol_store_context_destroy(bob_store);
signal_context_destroy(global_context);

return 0;
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�b��
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3!�u��$7�#�J��Lq�UpEς׫�.��N!Tl�'�����R��{���D��6|�F��f�"#1�|������& 5ē���<��@@���R��{��}0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
p33
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
p
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:x
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
>07
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
��
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/�
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�������������������������������������������������������������������������������������������������������������������������*
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1c
3 changes: 2 additions & 1 deletion tests/test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include <check.h>
#include <assert.h>

#include "../src/signal_protocol.h"
#include "curve.h"
Expand Down Expand Up @@ -169,7 +170,7 @@ void setup_test_store_context(signal_protocol_store_context **context, signal_co

signal_protocol_store_context *store_context = 0;
result = signal_protocol_store_context_create(&store_context, global_context);
ck_assert_int_eq(result, 0);
assert(result == 0);

setup_test_session_store(store_context);
setup_test_pre_key_store(store_context);
Expand Down

0 comments on commit fb11253

Please sign in to comment.