From a009895eb8124a4a1ab6a3f875b129d178a40dfc Mon Sep 17 00:00:00 2001 From: gram-signal <84339875+gram-signal@users.noreply.github.com> Date: Wed, 19 Mar 2025 12:35:45 -0700 Subject: [PATCH] Use Kyber1024 for HFS in Noise. Co-authored-by: Chris Eager <79161849+eager-signal@users.noreply.github.com> --- .github/workflows/push.yml | 2 +- .github/workflows/test.yml | 8 +++--- .gitmodules | 7 +++-- README.md | 3 ++- c/Makefile | 26 ++++++++++++++++--- c/enclave/enc.c | 8 +++--- c/libsodium | 1 + c/noise-c | 2 +- c/noiseutil/noise.c | 19 +++++++++++++- c/noiseutil/noise.h | 7 +++-- c/noiseutil/tests/noise.c | 13 ++++++---- c/testhost/client_state.c | 6 ++--- c/testhost/crud_test_fns.c | 4 +-- pom.xml | 4 ++- .../java/org/signal/cdsi/enclave/Enclave.java | 3 ++- 15 files changed, 80 insertions(+), 33 deletions(-) create mode 160000 c/libsodium diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 7d59708..acbcd97 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -18,7 +18,7 @@ jobs: - name: Checkout main project uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - submodules: true + submodules: recursive path: cdsi - name: Set up JDK 21 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3dbafc3..2f216d8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout main project uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - submodules: true + submodules: recursive path: cdsi - name: Docker cache @@ -40,7 +40,7 @@ jobs: - name: Checkout main project uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - submodules: true + submodules: recursive path: cdsi - name: Docker cache @@ -65,7 +65,7 @@ jobs: - name: Checkout main project uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - submodules: true + submodules: recursive path: cdsi - name: Set up JDK 21 @@ -106,7 +106,7 @@ jobs: - name: Checkout main project uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - submodules: true + submodules: recursive path: cdsi - name: Set up JDK 21 uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 diff --git a/.gitmodules b/.gitmodules index 1fc1900..55db5f3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,9 @@ [submodule "c/sgx/oram/src/SipHash"] path = c/SipHash url = https://github.com/veorq/SipHash -[submodule "c/sgx/enclave/noise-c"] +[submodule "c/noise-c"] path = c/noise-c - url = https://github.com/rweather/noise-c.git + url = https://github.com/signalapp/noise-c.git +[submodule "c/libsodium"] + path = c/libsodium + url = https://github.com/jedisct1/libsodium diff --git a/README.md b/README.md index 5a1dba0..8d40a62 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ Building ``` git submodule init -git submodule update +git submodule update --recursive --init || true +git submodule update --recursive || true mvn verify ``` diff --git a/c/Makefile b/c/Makefile index 26d6951..926d9f0 100644 --- a/c/Makefile +++ b/c/Makefile @@ -42,15 +42,33 @@ proto: cdsi.h cdsi.c enclave: proto -libnoise.a: +LIBSODIUM_UNDEFS = \ + -UHAVE_MMAP \ + -UHAVE_MLOCK \ + -UHAVE_MADVISE \ + -UHAVE_MPROTECT \ + -UHAVE_RAISE \ +##LIBSODIUM_UNDEFS + +libsodium.a: + rm -rf $$(pwd)/libsodium/.build && mkdir -p $$(pwd)/libsodium/.build + (cd libsodium && (git clean -fxd || true) && ./configure \ + CFLAGS="$(TRUSTED_CFLAGS) $(LIBSODIUM_UNDEFS)" \ + CXXFLAGS="$(TRUSTED_CXXFLAGS) $(LIBSODIUM_UNDEFS)" \ + CC=$(CC) CXX=$(CXX) --prefix=$$(pwd)/.build && $(MAKE) clean && $(MAKE) install) + cp -fv $$(pwd)/libsodium/.build/lib/libsodium.a $@ + +libnoise.a: libsodium.a mkdir -p $$(dirname $@) # Noise depends on the "immintrin" header which is not found in the pared-down # version of libc we use, and which it could otherwise not find with -nostdinc. (cd noise-c && \ + (git clean -fxd ; git submodule foreach --recursive git clean -xfd ; true) && \ ./autogen.sh && \ + libsodium_CFLAGS=-I$$(pwd)/.libsodium/include/ libsodium_LIBS=libsodium.a \ CC=$(TRUSTED_CC) CFLAGS="$(TRUSTED_CFLAGS) -I$(shell ./find_header.sh $(CC) immintrin.h)" ./configure && \ $(MAKE) -j) - cp -v noise-c/src/protocol/libnoiseprotocol.a libnoise.a + cp -vf noise-c/src/protocol/libnoiseprotocol.a libnoise.a libsip.a: SipHash/halfsiphash.c $(TRUSTED_CC) $(TRUSTED_CFLAGS) -o SipHash/halfsiphash.o -c SipHash/halfsiphash.c @@ -226,6 +244,7 @@ TESTS=\ tests: $(patsubst %,%.out,$(TESTS)) enclave.test.out constant_time_check.test + @echo ALL TESTS SUCCEEDED valgrinds: $(patsubst %,%.valgrind,$(TESTS)) public.pem: @@ -261,11 +280,12 @@ clean: enclave.test.out \ proto/cdsi.c \ proto/cdsi.h \ + libsodium/.build \ ## for dir in $(SUBDIRS); do make -C $$dir -f ../Makefile.subdirs clean; done (cd noise-c && \ ($(MAKE) clean || true) && \ - (git clean -fx || true)) >/dev/null + (git clean -fx ; git submodule foreach --recursive git clean -xfd ; true)) >/dev/null @echo CLEAN docker_%: diff --git a/c/enclave/enc.c b/c/enclave/enc.c index aba2ca7..96ec546 100644 --- a/c/enclave/enc.c +++ b/c/enclave/enc.c @@ -387,12 +387,12 @@ int enclave_new_client( RETURN_IF_ERROR(check_init_complete()); client_t *c; RETURN_IF_ERROR(MALLOCZ(c)); - TEST_LOG("noise_handshakestate_new_by_name '%s'", NOISE_PROTOCOL_DEFINITION); + TEST_LOG("noise_handshakestate_new_by_id"); error_t err = err_SUCCESS; GOTO_IF_ERROR(err = noise_errort( err_NOISE__HANDSHAKESTATE__NEW__, - noise_handshakestate_new_by_name( - &c->handshake, NOISE_PROTOCOL_DEFINITION, NOISE_ROLE_RESPONDER)), + noise_handshakestate_new_by_id( + &c->handshake, &cdsi_client_protocol_id, NOISE_ROLE_RESPONDER)), free_client); NoiseDHState *local_keypair = noise_handshakestate_get_local_keypair_dh(c->handshake); @@ -837,7 +837,7 @@ int enclave_handshake( GOTO_IF_ERROR(err = noise_errort(err_NOISE__HANDSHAKESTATE__READ__, noise_handshakestate_read_message(c->handshake, &buf_in, NULL)), client_unlock); // Generate the handshake response. - unsigned char handshake_msg[64]; + unsigned char handshake_msg[NOISE_HANDSHAKEWRITE_SIZE]; NoiseBuffer buf_out; noise_buffer_set_output(buf_out, handshake_msg, sizeof(handshake_msg)); TEST_LOG("noise_handshakestate_write_message"); diff --git a/c/libsodium b/c/libsodium new file mode 160000 index 0000000..fb4533b --- /dev/null +++ b/c/libsodium @@ -0,0 +1 @@ +Subproject commit fb4533b0a941b3a5b1db5687d1b008a5853d1f29 diff --git a/c/noise-c b/c/noise-c index 9379e58..68814be 160000 --- a/c/noise-c +++ b/c/noise-c @@ -1 +1 @@ -Subproject commit 9379e580a14c0374a57d826a49ba53b7440c80bc +Subproject commit 68814bedb0dbe893796a585ba9aed7c78360f2da diff --git a/c/noiseutil/noise.c b/c/noiseutil/noise.c index ff9d040..d358a6e 100644 --- a/c/noiseutil/noise.c +++ b/c/noiseutil/noise.c @@ -4,6 +4,23 @@ #include #include +const NoiseProtocolId cdsi_client_protocol_id = { + .prefix_id = NOISE_PREFIX_STANDARD, +#ifdef NO_NOISE_HFS + .pattern_id = NOISE_PATTERN_NK, +#else + .pattern_id = NOISE_PATTERN_NK_HFS, +#endif + .dh_id = NOISE_DH_CURVE25519, + .cipher_id = NOISE_CIPHER_CHACHAPOLY, + .hash_id = NOISE_HASH_SHA256, +#ifdef NO_NOISE_HFS + .hybrid_id = 0, +#else + .hybrid_id = NOISE_DH_KYBER1024, +#endif +}; + error_t noise_encrypt_message( NoiseCipherState* tx, const unsigned char* plaintext_data, @@ -76,7 +93,7 @@ error_t noise_pubkey_from_privkey( unsigned char pubkey[NOISE_KEY_SIZE]) { NoiseDHState* state; error_t err = err_SUCCESS; - RETURN_IF_ERROR(noise_errort(err_NOISE__DHSTATE__NEW__, noise_dhstate_new_by_name(&state, NOISE_DH_TYPE))); + RETURN_IF_ERROR(noise_errort(err_NOISE__DHSTATE__NEW__, noise_dhstate_new_by_id(&state, cdsi_client_protocol_id.dh_id))); GOTO_IF_ERROR(err = noise_errort(err_NOISE__DHSTATE__SET_KEYPAIR_PRIVATE__, noise_dhstate_set_keypair_private(state, privkey, NOISE_KEY_SIZE)), free_state); GOTO_IF_ERROR(err = noise_errort(err_NOISE__DHSTATE__GET_PUBLIC_KEY__, noise_dhstate_get_public_key(state, pubkey, NOISE_KEY_SIZE)), free_state); diff --git a/c/noiseutil/noise.h b/c/noiseutil/noise.h index a5d6ec5..f4612f2 100644 --- a/c/noiseutil/noise.h +++ b/c/noiseutil/noise.h @@ -4,18 +4,17 @@ #define _CDSI_NOISE_H #include -#define NOISE_PROTOCOL_TYPE "NK" -#define NOISE_DH_TYPE "25519" -#define NOISE_TYPE_SUFFIX NOISE_DH_TYPE "_ChaChaPoly_SHA256" -#define NOISE_PROTOCOL_DEFINITION "Noise_" NOISE_PROTOCOL_TYPE "_" NOISE_TYPE_SUFFIX #define NOISE_MAX_OVERHEAD 64 #define NOISE_KEY_SIZE 32 #define NOISE_MAX_PACKET_SIZE NOISE_MAX_PAYLOAD_LEN #define NOISE_MAC_SIZE 16 #define NOISE_MAX_DATA_SIZE (NOISE_MAX_PACKET_SIZE - NOISE_MAC_SIZE) +#define NOISE_HANDSHAKEWRITE_SIZE 1632 #include "util/util.h" +extern const NoiseProtocolId cdsi_client_protocol_id; + #define NOISE_ERROR_BASE NOISE_ID('E', 0) error_t noise_errort(error_t space, int noise_error); diff --git a/c/noiseutil/tests/noise.c b/c/noiseutil/tests/noise.c index 8b01d10..7eab262 100644 --- a/c/noiseutil/tests/noise.c +++ b/c/noiseutil/tests/noise.c @@ -24,10 +24,13 @@ static void test_noise_message_encrypt_decrypt() { NoiseHandshakeState* ah; NoiseHandshakeState* bh; - NOISE_ASSERT(noise_handshakestate_new_by_name( - &ah, "Noise_NN_25519_ChaChaPoly_SHA256", NOISE_ROLE_INITIATOR)); - NOISE_ASSERT(noise_handshakestate_new_by_name( - &bh, "Noise_NN_25519_ChaChaPoly_SHA256", NOISE_ROLE_RESPONDER)); + NoiseProtocolId id; + memcpy(&id, &cdsi_client_protocol_id, sizeof(id)); + id.pattern_id = NOISE_PATTERN_NN_HFS; + NOISE_ASSERT(noise_handshakestate_new_by_id( + &ah, &id, NOISE_ROLE_INITIATOR)); + NOISE_ASSERT(noise_handshakestate_new_by_id( + &bh, &id, NOISE_ROLE_RESPONDER)); NOISE_ASSERT(noise_handshakestate_start(ah)); NOISE_ASSERT(noise_handshakestate_start(bh)); @@ -36,7 +39,6 @@ static void test_noise_message_encrypt_decrypt() { NoiseCipherState* brx; NoiseCipherState* btx; uint8_t* bufbuf = calloc(1, BUFSIZE); - NoiseBuffer buf; noise_buffer_set_output(buf, bufbuf, BUFSIZE); NOISE_ASSERT(noise_handshakestate_write_message(ah, &buf, NULL)); @@ -70,5 +72,6 @@ static void test_noise_message_encrypt_decrypt() { } int main(int argc, char** argv) { + printf("Running\n"); test_noise_message_encrypt_decrypt(); } diff --git a/c/testhost/client_state.c b/c/testhost/client_state.c index 343e41a..997c4d8 100644 --- a/c/testhost/client_state.c +++ b/c/testhost/client_state.c @@ -110,7 +110,7 @@ exit: int perform_handshake(enclave_client_state *ecs, bool simulate, uint8_t pubkey[NOISE_KEY_SIZE]) { int err, retval, result; - RETURN_IF_ERROR(noise_errort(err_NOISE__HANDSHAKESTATE__NEW__, noise_handshakestate_new_by_name(&ecs->handshake, NOISE_PROTOCOL_DEFINITION, NOISE_ROLE_INITIATOR))); + RETURN_IF_ERROR(noise_errort(err_NOISE__HANDSHAKESTATE__NEW__, noise_handshakestate_new_by_id(&ecs->handshake, &cdsi_client_protocol_id, NOISE_ROLE_INITIATOR))); NoiseDHState *dhstate = noise_handshakestate_get_remote_public_key_dh(ecs->handshake); RETURN_IF_ERROR(noise_errort(err_NOISE__DHSTATE__SET_PUBLIC_KEY__, noise_dhstate_set_public_key(dhstate, pubkey, NOISE_KEY_SIZE))); RETURN_IF_ERROR(noise_errort(err_NOISE__HANDSHAKESTATE__START__, noise_handshakestate_start(ecs->handshake))); @@ -120,12 +120,12 @@ int perform_handshake(enclave_client_state *ecs, bool simulate, uint8_t pubkey[N return err_HOST__HANDSHAKE__INVALID_STATE; } NoiseBuffer mbuf; - uint8_t message[64]; + uint8_t message[4096]; noise_buffer_set_output(mbuf, message, sizeof(message)); RETURN_IF_ERROR(noise_errort(err_NOISE__HANDSHAKESTATE__WRITE__, noise_handshakestate_write_message(ecs->handshake, &mbuf, NULL))); size_t in_size = mbuf.size; - CHECK(in_size == 48); + CHECK(in_size == NOISE_HANDSHAKEWRITE_SIZE); uint8_t *in = message; uint8_t out[8192]; size_t actual_out_size = 0; diff --git a/c/testhost/crud_test_fns.c b/c/testhost/crud_test_fns.c index 133c005..dc127ae 100644 --- a/c/testhost/crud_test_fns.c +++ b/c/testhost/crud_test_fns.c @@ -169,7 +169,7 @@ int call_ratelimit(enclave_client_state *ecs, client_request req) int noise_err = noise_cipherstate_decrypt(ecs->recv, &buf_out); if (NOISE_ERROR_NONE != noise_err) { - noise_perror(NOISE_PROTOCOL_DEFINITION, noise_err); + noise_perror("noise_cipherstate_decrypt", noise_err); err = err_HOST__RATELIMIT__DECRYPT; } @@ -264,7 +264,7 @@ int run(enclave_client_state *ecs, size_t num_triples, e164_pni_aci_triple *trip int noise_err = noise_cipherstate_decrypt(ecs->recv, &buf_out); if (NOISE_ERROR_NONE != noise_err) { - noise_perror(NOISE_PROTOCOL_DEFINITION, noise_err); + noise_perror("noise_cipherstate_decrypt", noise_err); return err_HOST__RUN__DECRYPT; } diff --git a/pom.xml b/pom.xml index 473e841..1b82286 100644 --- a/pom.xml +++ b/pom.xml @@ -418,7 +418,9 @@ make - ENCLAVE_ID=test CONFIG=cds-test.conf RESOURCES_DIR=${project.build.testOutputDirectory}/org/signal/cdsi/enclave ADDITIONAL_CFLAGS="-DINSECURE" -C c ${make.docker.prefix}install + + ENCLAVE_ID=test CONFIG=cds-test.conf RESOURCES_DIR=${project.build.testOutputDirectory}/org/signal/cdsi/enclave ADDITIONAL_CFLAGS="-DINSECURE -DNO_NOISE_HFS" -C c ${make.docker.prefix}install diff --git a/src/main/java/org/signal/cdsi/enclave/Enclave.java b/src/main/java/org/signal/cdsi/enclave/Enclave.java index d1f43ac..e8ebc42 100644 --- a/src/main/java/org/signal/cdsi/enclave/Enclave.java +++ b/src/main/java/org/signal/cdsi/enclave/Enclave.java @@ -335,7 +335,8 @@ public class Enclave implements AutoCloseable { } CompletableFuture clientHandshake(final EnclaveClient client, final ByteBuffer in) { - final ByteBuffer out = ByteBuffer.allocateDirect(1024); + // see noise.h: NOISE_HANDSHAKEWRITE_SIZE + final ByteBuffer out = ByteBuffer.allocateDirect(1632); return supplyAsync(HANDSHAKE_TIMER_NAME, () -> { try {