Integrate Kyber1024 client/server communication into SVR*.

This commit is contained in:
gram-signal 2024-08-15 15:02:14 -07:00 committed by GitHub
parent 30a96d58f0
commit 5908542cf8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 337 additions and 103 deletions

View File

@ -20,7 +20,7 @@ jobs:
- name: Checkout main project
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: true
submodules: recursive
lfs: true
- name: Show releases

View File

@ -19,7 +19,7 @@ jobs:
- name: Checkout main project
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: true
submodules: recursive
- name: Expose Docker environmental variables for gha cache
# This action takes in the ID tokens etc provided by the permissions,

2
.gitmodules vendored
View File

@ -3,7 +3,7 @@
url = https://github.com/protocolbuffers/protobuf.git
[submodule "enclave/noise-c"]
path = enclave/noise-c
url = https://github.com/rweather/noise-c.git
url = https://github.com/signalapp/noise-c.git
[submodule "enclave/SipHash"]
path = enclave/SipHash
url = https://github.com/veorq/SipHash

View File

@ -16,7 +16,8 @@ validate:
git:
git submodule init || true
git submodule update || true
git submodule update --recursive --init || true
git submodule update --recursive || true
ETARGET ?= all

View File

@ -43,33 +43,36 @@ build/noise-c/TEST.a: build/libsodium/TEST.a
$(QUIET) echo -e "BUILD\t$@"
$(QUIET) mkdir -p $(@D)
$(QUIET) (cd noise-c && \
(git clean -fx ; git submodule foreach --recursive git clean -xf ; true) && \
./autogen.sh && \
libsodium_CFLAGS=-I$$PWD/../build/libsodium/TEST.a.dir/include/ libsodium_LIBS=$$PWD/../build/libsodium/TEST.a \
CC=$(CC) CFLAGS="$(TEST_CFLAGS) -I$(shell ./find_header.sh $(CC) immintrin.h)" ./configure --with-libsodium && \
$(MAKE) clean && \
$(MAKE)) $(QUIET_OUT)
$(MAKE) -C src/protocol) $(QUIET_OUT)
$(QUIET) cp noise-c/src/protocol/libnoiseprotocol.a $@
$(QUIET) echo -e "BUILT\t$@"
build/noise-c/SGX.a: build/libsodium/SGX.a | build/noise-c/TEST.a
$(QUIET) echo -e "BUILD\t$@"
$(QUIET) mkdir -p $(@D)
$(QUIET) (cd noise-c && \
(git clean -fx ; git submodule foreach --recursive git clean -xf ; true) && \
./autogen.sh && \
libsodium_CFLAGS=-I$$PWD/../build/libsodium/SGX.a.dir/include/ libsodium_LIBS=$$PWD/../build/libsodium/SGX.a \
CC=$(CC) CFLAGS="$(SGX_CFLAGS) -I$(shell ./find_header.sh $(CC) immintrin.h)" ./configure --with-libsodium && \
$(MAKE) clean && \
$(MAKE)) $(QUIET_OUT)
$(MAKE) -C src/protocol) $(QUIET_OUT)
$(QUIET) cp noise-c/src/protocol/libnoiseprotocol.a $@
$(QUIET) echo -e "BUILT\t$@"
build/noise-c/X86.a: build/libsodium/X86.a | build/noise-c/SGX.a
$(QUIET) echo -e "BUILD\t$@"
$(QUIET) mkdir -p $(@D)
$(QUIET) (cd noise-c && \
(git clean -fx ; git submodule foreach --recursive git clean -xf ; true) && \
./autogen.sh && \
libsodium_CFLAGS=-I$$PWD/../build/libsodium/X86.a.dir/include/ libsodium_LIBS=$$PWD/../build/libsodium/X86.a \
CC=$(CC) CFLAGS="$(X86_CFLAGS) -I$(shell ./find_header.sh $(CC) immintrin.h)" ./configure --with-libsodium && \
$(MAKE) clean && \
$(MAKE)) $(QUIET_OUT)
$(MAKE) -C src/protocol) $(QUIET_OUT)
$(QUIET) cp noise-c/src/protocol/libnoiseprotocol.a $@
$(QUIET) echo -e "BUILT\t$@"
@ -271,10 +274,11 @@ build/attest.azuresnp: build/initmain/X86.a $(patsubst %,build/%/X86.a,$(AZURESN
clean:
$(QUIET) echo CLEAN
$(QUIET) (cd protobuf ; make clean ; git clean -fx ; true) $(QUIET_OUT)
$(QUIET) (cd noise-c ; make clean ; git clean -fx ; true) $(QUIET_OUT)
$(QUIET) (cd SipHash ; make clean ; git clean -fx ; true) $(QUIET_OUT)
$(QUIET) (cd boringssl ; make clean ; git clean -fx ; true) $(QUIET_OUT)
$(QUIET) (cd protobuf ; make clean ; true) $(QUIET_OUT)
$(QUIET) (cd noise-c ; make clean ; true) $(QUIET_OUT)
$(QUIET) (cd SipHash ; make clean ; true) $(QUIET_OUT)
$(QUIET) (cd boringssl ; make clean ; true) $(QUIET_OUT)
$(QUIET) (git submodule foreach --recursive git clean -xf ; true) $(QUIET_OUT)
$(QUIET) rm -vfr build $(QUIET_OUT)
$(QUIET) rm -vf .testdepends $(QUIET_OUT)

View File

@ -23,13 +23,23 @@ const NoiseProtocolId client_protocol = {
.hybrid_id = 0,
};
const NoiseProtocolId client_protocol_pq = {
.prefix_id = NOISE_PREFIX_STANDARD,
.pattern_id = NOISE_PATTERN_NK_HFS,
.dh_id = NOISE_DH_CURVE25519,
.cipher_id = NOISE_CIPHER_CHACHAPOLY,
.hash_id = NOISE_HASH_SHA256,
.hybrid_id = NOISE_DH_KYBER1024,
};
Client::Client(
std::unique_ptr<db::DB::ClientState> cs)
std::unique_ptr<db::DB::ClientState> cs, bool pq)
: hs_(noise::WrapHandshakeState(nullptr)),
tx_(noise::WrapCipherState(nullptr)),
rx_(noise::WrapCipherState(nullptr)),
id_(id_gen.fetch_add(1)),
cs_(std::move(cs)) {
cs_(std::move(cs)),
pq_(pq) {
}
Client::~Client() {
@ -38,7 +48,8 @@ Client::~Client() {
error::Error Client::Init(const noise::DHState& dhstate, const e2e::Attestation& attestation) {
util::unique_lock lock(mu_);
NoiseHandshakeState* hs;
if (NOISE_ERROR_NONE != noise_handshakestate_new_by_id(&hs, &client_protocol, NOISE_ROLE_RESPONDER)) {
const NoiseProtocolId* protocol = pq_ ? &client_protocol_pq : &client_protocol;
if (NOISE_ERROR_NONE != noise_handshakestate_new_by_id(&hs, protocol, NOISE_ROLE_RESPONDER)) {
return COUNTED_ERROR(Client_HandshakeState);
}
auto hs_wrap = noise::WrapHandshakeState(hs);
@ -131,7 +142,7 @@ std::pair<Client*, error::Error> ClientManager::NewClient(
context::Context* ctx,
std::unique_ptr<db::DB::ClientState> cs) {
MEASURE_CPU(ctx, cpu_client_hs_start);
std::unique_ptr<Client> c(new Client(std::move(cs)));
std::unique_ptr<Client> c(new Client(std::move(cs), pq_));
auto [dhstate, attestation] = ClientArgs(ctx);
error::Error err = c->Init(dhstate, attestation);
if (err != error::OK) {

View File

@ -44,7 +44,7 @@ class Client {
private:
~Client();
explicit Client(std::unique_ptr<db::DB::ClientState> cs);
Client(std::unique_ptr<db::DB::ClientState> cs, bool pq);
error::Error Init(const noise::DHState& dhstate, const e2e::Attestation& attestation) EXCLUDES(mu_);
friend class ClientManager;
friend std::unique_ptr<Client>::deleter_type;
@ -56,11 +56,12 @@ class Client {
noise::CipherState rx_ GUARDED_BY(mu_);
const size_t id_;
std::unique_ptr<db::DB::ClientState> cs_;
const bool pq_;
};
class ClientManager {
public:
ClientManager(noise::DHState dhstate) : dhstate_(std::move(dhstate)) {}
ClientManager(noise::DHState dhstate, bool pq) : dhstate_(std::move(dhstate)), pq_(pq) {}
error::Error RefreshAttestation(context::Context* ctx, const enclaveconfig::RaftGroupConfig& config) EXCLUDES(mu_);
error::Error RotateKeyAndRefreshAttestation(context::Context* ctx, const enclaveconfig::RaftGroupConfig& config) EXCLUDES(mu_);
static noise::DHState NewDHState();
@ -82,6 +83,7 @@ class ClientManager {
noise::DHState dhstate_ GUARDED_BY(mu_);
e2e::Attestation attestation_ GUARDED_BY(mu_);
std::unordered_map<ClientID, std::unique_ptr<Client>> clients_ GUARDED_BY(mu_);
const bool pq_;
};
} // namespace svr2::client

View File

@ -149,7 +149,7 @@ error::Error Core::Init(context::Context* ctx, const enclaveconfig::EnclaveConfi
enclave_config_ = config;
}
peer_manager_ = std::move(peer_manager);
client_manager_ = std::make_unique<client::ClientManager>(std::move(client_dh));
client_manager_ = std::make_unique<client::ClientManager>(std::move(client_dh), config.client_pq());
clock_.SetLocalTime(initial_timestamp_unix_secs);
peer_manager_->SetPeerAttestationTimestamp(ctx, initial_timestamp_unix_secs, raft_config_template_.attestation_timeout());

View File

@ -81,7 +81,8 @@ void Gauge::Clear() {
}
namespace internal {
error::Error RecordError(error::Error e) {
error::Error RecordError(error::Error e, const char* file, int line) {
LOG(VERBOSE) << e << " @ " << file << ":" << line;
recorded_errors[e].fetch_add(1);
return e;
}

View File

@ -75,7 +75,7 @@ enum Gauges {
};
namespace internal {
error::Error RecordError(error::Error);
error::Error RecordError(error::Error, const char* file, int line);
extern Counter counters[COUNTERS_ARRAY_SIZE];
extern Gauge gauges[GAUGES_ARRAY_SIZE];
} // namespace internal
@ -93,6 +93,6 @@ extern Gauge gauges[GAUGES_ARRAY_SIZE];
// COUNTED_ERROR counts an error within metrics, returning that same error.
// It's generally used like:
// return COUNTED_ERROR(Foo_Bar);
#define COUNTED_ERROR(x) ::svr2::metrics::internal::RecordError(error::x)
#define COUNTED_ERROR(x) ::svr2::metrics::internal::RecordError(error::x, __FILE__, __LINE__)
#endif // __SVR2_METRICS_METRICS_H__

@ -1 +1 @@
Subproject commit 9ab8de7db4082d08aea7d5f7bb614ea3e777b09d
Subproject commit 68814bedb0dbe893796a585ba9aed7c78360f2da

View File

@ -21,7 +21,7 @@
namespace svr2::noise {
const size_t HANDSHAKE_INIT_SIZE = 64;
const size_t HANDSHAKE_INIT_SIZE = 4096;
const size_t HANDSHAKE_HFS_INIT_SIZE = 4096;
inline uint8_t* StrU8Ptr(std::string* s) {

View File

@ -55,7 +55,7 @@ static NoiseProtocolId peer_to_peer_protocol = {
// have access to hardware-accelerated AES, so we use that.
.cipher_id = NOISE_CIPHER_AESGCM,
.hash_id = NOISE_HASH_SHA256,
.hybrid_id = NOISE_DH_NEWHOPE,
.hybrid_id = NOISE_DH_KYBER1024,
};
Peer::Peer(const peerid::PeerID& id, PeerManager* parent)

View File

@ -6,6 +6,8 @@
//TESTDEP metrics
//TESTDEP proto
//TESTDEP protobuf-lite
//TESTDEP env
//TESTDEP libsodium
#include <gtest/gtest.h>
#include "util/hex.h"
#include <string>

View File

@ -15,11 +15,11 @@ enclave_binaries:
# -count=1 forces this test to run un-cached, since enclave.test may have changed
# even though Go code has not, and tests may depend on it.
test: build enclave_binaries rustclient
test: build enclave_binaries rustclient/target/debug/rustclient
go test $(GO_TEST_FLAGS) -count=1 ./...
rustclient:
cd integration/rustclient && cargo build
rustclient/target/debug/rustclient:
cd rustclient && cargo build
EDGER8R_FILES=enclave/c/svr2_u.c enclave/c/svr2_u.h enclave/c/svr2_args.h
# This $(firstword) trick allows for grouped targets.

View File

@ -49,37 +49,6 @@ const (
enclaveNitro = "nitro"
)
type prefixWriter struct {
written bool
prefix []byte
to io.Writer
}
func (p *prefixWriter) Write(bs []byte) (int, error) {
lastStart := 0
for i, b := range bs {
if !p.written {
if n, err := p.to.Write(bs[lastStart:i]); err != nil {
return lastStart + n, err
}
lastStart = i
if _, err := p.to.Write(p.prefix); err != nil {
return i, err
}
p.written = true
} else if b == '\n' {
p.written = false
}
}
if n, err := p.to.Write(bs[lastStart:]); err != nil {
return lastStart + n, err
}
return len(bs), nil
}
func newPrefixWriter(s string, to io.Writer) io.Writer {
return &prefixWriter{to: to, prefix: []byte(s)}
}
func userName(i int) string {
return fmt.Sprintf("%032x", i)
}
@ -92,18 +61,6 @@ func TestIntegration(t *testing.T) {
restore(t, testClient(t, u, userName(9999)), pin)
}
func TestRustClient(t *testing.T) {
host := fmt.Sprintf("localhost:%v", port(clientType, 1))
u := url.URL{Scheme: "ws", Host: host, Path: "v1/enclave"}
cmd := exec.Command("./rustclient/target/debug/rustclient", u.String())
w := newPrefixWriter("RUSTCLIENT ", os.Stderr)
cmd.Stdout = w
cmd.Stderr = w
if err := cmd.Run(); err != nil {
t.Errorf("rustclient: %v", err)
}
}
func TestConcurrentClients(t *testing.T) {
host := fmt.Sprintf("localhost:%v", port(clientType, 1))
u := url.URL{Scheme: "ws", Host: host, Path: "v1/enclave"}
@ -348,7 +305,7 @@ func start(enclaveType string) group {
args...)
cmd.Env = append(cmd.Env, "AUTH_SECRET="+base64.StdEncoding.EncodeToString([]byte(authSecret)))
w := newPrefixWriter(fmt.Sprintf("[%d] ", i), os.Stderr)
w := servicetest.NewPrefixWriter(fmt.Sprintf("[%d] ", i), os.Stderr)
cmd.Stdout = w
cmd.Stderr = w

View File

@ -1 +0,0 @@
../../../shared/proto/

View File

@ -1 +0,0 @@
../../../.cargotarget/

View File

@ -161,15 +161,19 @@ dependencies = [
[[package]]
name = "bytes"
version = "1.6.1"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
[[package]]
name = "cc"
version = "1.1.5"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549"
dependencies = [
"jobserver",
"libc",
]
[[package]]
name = "cfg-if"
@ -329,6 +333,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "either"
version = "1.13.0"
@ -348,7 +358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -440,7 +450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check 0.9.4",
"version_check 0.9.5",
]
[[package]]
@ -464,6 +474,12 @@ dependencies = [
"polyval",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.14.5"
@ -535,9 +551,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.2.6"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
dependencies = [
"equivalent",
"hashbrown",
@ -570,6 +586,15 @@ dependencies = [
"either",
]
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -750,9 +775,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.64"
version = "0.10.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
dependencies = [
"bitflags 2.6.0",
"cfg-if 1.0.0",
@ -782,9 +807,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.102"
version = "0.9.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2"
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
dependencies = [
"cc",
"libc",
@ -865,9 +890,43 @@ dependencies = [
[[package]]
name = "ppv-lite86"
version = "0.2.17"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "pqcrypto-internals"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9d34bec6abe2283e6de7748b68b292d1ffa2203397e3e71380ff8418a49fb46"
dependencies = [
"cc",
"dunce",
"getrandom",
"libc",
]
[[package]]
name = "pqcrypto-kyber"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c00293cf898859d0c771455388054fd69ab712263c73fdc7f287a39b1ba000"
dependencies = [
"cc",
"glob",
"libc",
"pqcrypto-internals",
"pqcrypto-traits",
]
[[package]]
name = "pqcrypto-traits"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94e851c7654eed9e68d7d27164c454961a616cf8c203d500607ef22c737b51bb"
[[package]]
name = "prettyplease"
@ -894,7 +953,7 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc"
dependencies = [
"bytes 1.6.1",
"bytes 1.7.1",
"prost-derive",
]
@ -904,7 +963,7 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1"
dependencies = [
"bytes 1.6.1",
"bytes 1.7.1",
"heck",
"itertools",
"log 0.4.22",
@ -1103,9 +1162,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex"
version = "1.10.5"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
@ -1173,7 +1232,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -1188,7 +1247,7 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
dependencies = [
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -1298,6 +1357,8 @@ dependencies = [
"blake2",
"chacha20poly1305",
"curve25519-dalek",
"pqcrypto-kyber",
"pqcrypto-traits",
"rand_core 0.6.4",
"rustc_version 0.4.0",
"sha2",
@ -1312,9 +1373,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.71"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
@ -1323,14 +1384,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.10.1"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
dependencies = [
"cfg-if 1.0.0",
"fastrand",
"once_cell",
"rustix",
"windows-sys",
"windows-sys 0.59.0",
]
[[package]]
@ -1528,9 +1590,9 @@ checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "version_check"
version = "0.9.4"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
@ -1628,6 +1690,15 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@ -1702,6 +1773,27 @@ dependencies = [
"winapi-build",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zeroize"
version = "1.8.1"

View File

@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
snow = "0.9.6"
snow = { version = "0.9.6", features = ["hfs", "pqclean_kyber1024"] }
websocket = "0.27.1"
prost = "0.13.1"
simple-error = "0.3.1"

View File

@ -1,3 +1,6 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
fn main() {
let protos = [
"proto/msgs.proto",

1
host/rustclient/proto Symbolic link
View File

@ -0,0 +1 @@
../../shared/proto/

View File

@ -0,0 +1,124 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
package rustclient
import (
"context"
"encoding/base64"
"fmt"
"net/url"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/signalapp/svr2/servicetest"
"google.golang.org/protobuf/encoding/prototext"
pb "github.com/signalapp/svr2/proto"
)
var (
validConfig = pb.InitConfig{
EnclaveConfig: &pb.EnclaveConfig{
Raft: &pb.RaftConfig{
ElectionTicks: 30,
HeartbeatTicks: 15,
ReplicationChunkBytes: 1 << 20,
ReplicaVotingTimeoutTicks: 120,
ReplicaMembershipTimeoutTicks: 240,
LogMaxBytes: 10 << 20,
},
E2ETxnTimeoutTicks: 30,
ClientPq: true,
},
GroupConfig: &pb.RaftGroupConfig{
DbVersion: pb.DatabaseVersion_DATABASE_VERSION_SVR2,
MinVotingReplicas: 1,
MaxVotingReplicas: 1,
AttestationTimeout: 3600,
Simulated: true,
},
}
hostPath = "../main"
sgxPath = "../../enclave/build/enclave.test"
clientPath = "target/debug/rustclient"
authSecret = "123456"
)
func hostConfig(redisAddr string) string {
return fmt.Sprintf(`
peerAddr: localhost:9990
clientListenAddr: localhost:9991
controlListenAddr: localhost:9992
raft:
tickDuration: 250ms
redis:
addrs: [%s]`, redisAddr)
}
func TestRustClient(t *testing.T) {
dir, err := os.MkdirTemp("", "rustclient")
if err != nil {
t.Fatalf("mkdir: %v", err)
}
t.Logf("using dir %v", dir)
defer os.RemoveAll(dir)
redis, err := miniredis.Run()
if err != nil {
t.Fatalf("miniredis: %v", err)
}
hConfig := hostConfig(redis.Addr())
eConfig, err := prototext.Marshal(&validConfig)
if err != nil {
t.Fatalf("proto marshal: %v", err)
}
if err := os.WriteFile(filepath.Join(dir, "hconfig"), []byte(hConfig), 0600); err != nil {
t.Fatalf("write hconfig: %v", err)
}
if err := os.WriteFile(filepath.Join(dir, "econfig"), eConfig, 0600); err != nil {
t.Fatalf("write econfig: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
hostCmd := exec.CommandContext(
ctx,
hostPath,
"-hconfig_path", filepath.Join(dir, "hconfig"),
"-econfig_path", filepath.Join(dir, "econfig"),
"-enclave_type", "sgx",
"-sgx_path", sgxPath)
hostCmd.Env = append(hostCmd.Env, "AUTH_SECRET="+base64.StdEncoding.EncodeToString([]byte(authSecret)))
hostCmd.Stdout = servicetest.NewPrefixWriter("HOST_OUT: ", os.Stderr)
hostCmd.Stderr = servicetest.NewPrefixWriter("HOST_ERR: ", os.Stderr)
defer time.Sleep(time.Second) // allow logs to make it out.
t.Logf("Starting...")
if err := hostCmd.Start(); err != nil {
t.Fatalf("starting: %v", err)
}
t.Logf("Waiting for healthy")
if err := servicetest.WaitFor200(time.Minute, "http://localhost:9992/health/ready"); err != nil {
t.Fatalf("wait for 200: %v", err)
}
t.Logf("Running test")
u := url.URL{Scheme: "ws", Host: "localhost:9991", Path: "v1/enclave"}
clientCmd := exec.CommandContext(
ctx,
clientPath,
u.String())
clientCmd.Stdout = servicetest.NewPrefixWriter("CLIENT_OUT: ", os.Stderr)
clientCmd.Stderr = servicetest.NewPrefixWriter("CLIENT_ERR: ", os.Stderr)
if err := clientCmd.Run(); err != nil {
t.Fatalf("client error: %v", err)
}
}

View File

@ -1,3 +1,6 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
use hmac::Mac;
use websocket::header::{Authorization, Basic, Headers};
use prost::Message;
@ -25,7 +28,7 @@ pub mod svr2 {
type HmacSha256 = hmac::Hmac<sha2::Sha256>;
static PATTERN: &'static str = "Noise_NK_25519_ChaChaPoly_SHA256";
static PATTERN: &'static str = "Noise_NKhfs_25519+Kyber1024_ChaChaPoly_SHA256";
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
@ -77,9 +80,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Send handshake start");
client.send_message(&websocket::Message::binary(&buf[..len]))?;
println!("Recv handshake finish");
println!("Recv handshake start");
let msg2 = client.recv_message()?;
let bin2 = if let websocket::OwnedMessage::Binary(b) = msg2 {
println!("Received!");
b
} else {
bail!("received message not binary");

1
host/rustclient/target Symbolic link
View File

@ -0,0 +1 @@
../../.cargotarget/

View File

@ -79,3 +79,34 @@ func WaitFor200(timeout time.Duration, url string) error {
})
return err
}
type PrefixWriter struct {
written bool
prefix []byte
to io.Writer
}
func (p *PrefixWriter) Write(bs []byte) (int, error) {
lastStart := 0
for i, b := range bs {
if !p.written {
if n, err := p.to.Write(bs[lastStart:i]); err != nil {
return lastStart + n, err
}
lastStart = i
if _, err := p.to.Write(p.prefix); err != nil {
return i, err
}
p.written = true
} else if b == '\n' {
p.written = false
}
}
if n, err := p.to.Write(bs[lastStart:]); err != nil {
return lastStart + n, err
}
return len(bs), nil
}
func NewPrefixWriter(s string, to io.Writer) io.Writer {
return &PrefixWriter{to: to, prefix: []byte(s)}
}

View File

@ -48,6 +48,8 @@ message EnclaveConfig {
uint32 e2e_txn_timeout_ticks = 2;
// Every N ticks, send our local timestamp to our peers.
uint32 send_timestamp_ticks = 5;
// If true, use HFS for client/server PQ protection.
bool client_pq = 6;
}
// RaftGroupConfig is a configuration shared by members of a Raft group.