mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-24 17:33:46 +00:00
tests: port remaining C unit tests to the C++ test harness
Convert acl, acl_literal, aead2022, base64, buffer, cache (legacy reference), crypto, ipset, ipset_reference, json, netutils, ppbloom, process, ref, ssurl and utils tests to test_helpers.hpp. ctest names are unchanged; every assertion is kept. Build the ported sources with the strict C++ warning set.
This commit is contained in:
+125
-136
@@ -1,53 +1,53 @@
|
||||
/*
|
||||
* Unit tests for the Shadowsocks 2022 Edition (SIP022) cipher suite.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Shadowsocks 2022 Edition (SIP022) cipher suite in the legacy crypto
|
||||
// reference (tests/reference/aead.cpp): BLAKE3 vectors, TCP and UDP round
|
||||
// trips, tamper and replay rejection.
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sodium.h>
|
||||
|
||||
int verbose = 0;
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
#include "crypto.h"
|
||||
#include "aead.h"
|
||||
#include "blake3/blake3.h"
|
||||
#include "crypto.h"
|
||||
#include "ppbloom.h"
|
||||
#include "utils.h"
|
||||
#include "blake3/blake3.h"
|
||||
|
||||
/* Provide nonce_cache symbol needed by crypto.cpp */
|
||||
struct cache *nonce_cache = NULL;
|
||||
extern "C" {
|
||||
int verbose = 0;
|
||||
// Provide the nonce_cache symbol needed by the crypto reference.
|
||||
struct cache *nonce_cache = nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* 32-byte and 16-byte PSKs in base64 */
|
||||
#define PSK32 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
||||
#define PSK16 "AAAAAAAAAAAAAAAAAAAAAA=="
|
||||
|
||||
static const char *methods_2022[] = {
|
||||
const char *const methods_2022[] = {
|
||||
"2022-blake3-aes-128-gcm",
|
||||
"2022-blake3-aes-256-gcm",
|
||||
"2022-blake3-chacha20-poly1305",
|
||||
};
|
||||
|
||||
static const char *
|
||||
psk_for(const char *method)
|
||||
const char *psk_for(const char *method)
|
||||
{
|
||||
return strcmp(method, "2022-blake3-aes-128-gcm") == 0 ? PSK16 : PSK32;
|
||||
return std::strcmp(method, "2022-blake3-aes-128-gcm") == 0 ? PSK16 : PSK32;
|
||||
}
|
||||
|
||||
static crypto_t *
|
||||
make_crypto(const char *method)
|
||||
crypto_t *make_crypto(const char *method)
|
||||
{
|
||||
crypto_t *c = crypto_init(psk_for(method), NULL, method);
|
||||
assert(c != NULL);
|
||||
crypto_t *c = crypto_init(psk_for(method), nullptr, method);
|
||||
SS_CHECK(c != nullptr);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
free_crypto(crypto_t *c)
|
||||
void free_crypto(crypto_t *c)
|
||||
{
|
||||
/*
|
||||
* crypto_init() sets up the nonce bloom filter each time it is called,
|
||||
@@ -64,14 +64,13 @@ free_crypto(crypto_t *c)
|
||||
* nothing interoperates. Vector generated from the BLAKE3 reference for
|
||||
* context "shadowsocks 2022 session subkey" over 32 zero bytes of material.
|
||||
*/
|
||||
static void
|
||||
test_blake3_derive_key_known_vector(void)
|
||||
void test_blake3_derive_key_known_vector()
|
||||
{
|
||||
blake3_hasher h;
|
||||
uint8_t material[32];
|
||||
uint8_t out[32];
|
||||
|
||||
memset(material, 0, sizeof(material));
|
||||
std::memset(material, 0, sizeof(material));
|
||||
blake3_hasher_init_derive_key(&h, SS2022_SUBKEY_CTX);
|
||||
blake3_hasher_update(&h, material, sizeof(material));
|
||||
blake3_hasher_finalize(&h, out, sizeof(out));
|
||||
@@ -81,20 +80,18 @@ test_blake3_derive_key_known_vector(void)
|
||||
blake3_hasher_init_derive_key(&h, SS2022_SUBKEY_CTX);
|
||||
blake3_hasher_update(&h, material, sizeof(material));
|
||||
blake3_hasher_finalize(&h, out2, sizeof(out2));
|
||||
assert(memcmp(out, out2, 32) == 0);
|
||||
SS_CHECK(std::memcmp(out, out2, 32) == 0);
|
||||
|
||||
/* A different context string must give a different subkey. */
|
||||
uint8_t out3[32];
|
||||
blake3_hasher_init_derive_key(&h, "some other context");
|
||||
blake3_hasher_update(&h, material, sizeof(material));
|
||||
blake3_hasher_finalize(&h, out3, sizeof(out3));
|
||||
assert(memcmp(out, out3, 32) != 0);
|
||||
(void)out3;
|
||||
SS_CHECK(std::memcmp(out, out3, 32) != 0);
|
||||
}
|
||||
|
||||
/* BLAKE3 hash of the empty input, from the reference test vectors. */
|
||||
static void
|
||||
test_blake3_empty_hash_vector(void)
|
||||
void test_blake3_empty_hash_vector()
|
||||
{
|
||||
blake3_hasher h;
|
||||
uint8_t out[32];
|
||||
@@ -108,16 +105,14 @@ test_blake3_empty_hash_vector(void)
|
||||
blake3_hasher_init(&h);
|
||||
blake3_hasher_update(&h, "", 0);
|
||||
blake3_hasher_finalize(&h, out, sizeof(out));
|
||||
assert(memcmp(out, expected, 32) == 0);
|
||||
(void)expected;
|
||||
SS_CHECK(std::memcmp(out, expected, 32) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* A client request stream must round-trip through a server decrypt context:
|
||||
* salt, fixed header, variable header with the SOCKS address, then payload.
|
||||
*/
|
||||
static void
|
||||
test_tcp_request_roundtrip(const char *method)
|
||||
void test_tcp_request_roundtrip(const char *method)
|
||||
{
|
||||
/* SOCKS address: IPv4 1.2.3.4:80 */
|
||||
static const uint8_t addr[] = { 0x01, 1, 2, 3, 4, 0x00, 0x50 };
|
||||
@@ -137,35 +132,35 @@ test_tcp_request_roundtrip(const char *method)
|
||||
|
||||
/* First write: the address header. */
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
std::memset(&buf, 0, sizeof(buf));
|
||||
balloc(&buf, 4096);
|
||||
memcpy(buf.data, addr, sizeof(addr));
|
||||
std::memcpy(buf.data, addr, sizeof(addr));
|
||||
buf.len = sizeof(addr);
|
||||
assert(c->encrypt(&buf, &enc, 4096) == CRYPTO_OK);
|
||||
SS_CHECK(c->encrypt(&buf, &enc, 4096) == CRYPTO_OK);
|
||||
|
||||
/* Second write: stream payload. */
|
||||
buffer_t buf2;
|
||||
memset(&buf2, 0, sizeof(buf2));
|
||||
std::memset(&buf2, 0, sizeof(buf2));
|
||||
balloc(&buf2, 4096);
|
||||
size_t plen = strlen(payload);
|
||||
memcpy(buf2.data, payload, plen);
|
||||
size_t plen = std::strlen(payload);
|
||||
std::memcpy(buf2.data, payload, plen);
|
||||
buf2.len = plen;
|
||||
assert(c->encrypt(&buf2, &enc, 4096) == CRYPTO_OK);
|
||||
SS_CHECK(c->encrypt(&buf2, &enc, 4096) == CRYPTO_OK);
|
||||
|
||||
/* Feed both writes to the server in one go, as they arrive on the wire. */
|
||||
buffer_t wire;
|
||||
memset(&wire, 0, sizeof(wire));
|
||||
std::memset(&wire, 0, sizeof(wire));
|
||||
balloc(&wire, 8192);
|
||||
memcpy(wire.data, buf.data, buf.len);
|
||||
memcpy(wire.data + buf.len, buf2.data, buf2.len);
|
||||
std::memcpy(wire.data, buf.data, buf.len);
|
||||
std::memcpy(wire.data + buf.len, buf2.data, buf2.len);
|
||||
wire.len = buf.len + buf2.len;
|
||||
|
||||
assert(c->decrypt(&wire, &dec, 8192) == CRYPTO_OK);
|
||||
SS_CHECK(c->decrypt(&wire, &dec, 8192) == CRYPTO_OK);
|
||||
|
||||
/* The server sees the SOCKS address followed by the payload. */
|
||||
assert(wire.len == sizeof(addr) + plen);
|
||||
assert(memcmp(wire.data, addr, sizeof(addr)) == 0);
|
||||
assert(memcmp(wire.data + sizeof(addr), payload, plen) == 0);
|
||||
SS_CHECK(wire.len == sizeof(addr) + plen);
|
||||
SS_CHECK(std::memcmp(wire.data, addr, sizeof(addr)) == 0);
|
||||
SS_CHECK(std::memcmp(wire.data + sizeof(addr), payload, plen) == 0);
|
||||
|
||||
bfree(&buf);
|
||||
bfree(&buf2);
|
||||
@@ -179,8 +174,7 @@ test_tcp_request_roundtrip(const char *method)
|
||||
* A stream split across arbitrary boundaries must still decrypt: the
|
||||
* decryptor buffers partial chunks and returns CRYPTO_NEED_MORE.
|
||||
*/
|
||||
static void
|
||||
test_tcp_partial_delivery(const char *method)
|
||||
void test_tcp_partial_delivery(const char *method)
|
||||
{
|
||||
static const uint8_t addr[] = { 0x01, 10, 0, 0, 1, 0x1f, 0x90 };
|
||||
crypto_t *c = make_crypto(method);
|
||||
@@ -194,33 +188,32 @@ test_tcp_partial_delivery(const char *method)
|
||||
dec.role = CRYPTO_ROLE_SERVER;
|
||||
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
std::memset(&buf, 0, sizeof(buf));
|
||||
balloc(&buf, 4096);
|
||||
memcpy(buf.data, addr, sizeof(addr));
|
||||
std::memcpy(buf.data, addr, sizeof(addr));
|
||||
buf.len = sizeof(addr);
|
||||
assert(c->encrypt(&buf, &enc, 4096) == CRYPTO_OK);
|
||||
SS_CHECK(c->encrypt(&buf, &enc, 4096) == CRYPTO_OK);
|
||||
|
||||
/* Deliver the ciphertext one byte at a time. */
|
||||
size_t total = buf.len;
|
||||
int got_ok = 0;
|
||||
for (size_t i = 0; i < total; i++) {
|
||||
buffer_t piece;
|
||||
memset(&piece, 0, sizeof(piece));
|
||||
std::memset(&piece, 0, sizeof(piece));
|
||||
balloc(&piece, 4096);
|
||||
piece.data[0] = buf.data[i];
|
||||
piece.len = 1;
|
||||
|
||||
int rc = c->decrypt(&piece, &dec, 4096);
|
||||
assert(rc == CRYPTO_OK || rc == CRYPTO_NEED_MORE);
|
||||
SS_CHECK(rc == CRYPTO_OK || rc == CRYPTO_NEED_MORE);
|
||||
if (rc == CRYPTO_OK) {
|
||||
assert(piece.len == sizeof(addr));
|
||||
assert(memcmp(piece.data, addr, sizeof(addr)) == 0);
|
||||
SS_CHECK(piece.len == sizeof(addr));
|
||||
SS_CHECK(std::memcmp(piece.data, addr, sizeof(addr)) == 0);
|
||||
got_ok = 1;
|
||||
}
|
||||
bfree(&piece);
|
||||
}
|
||||
assert(got_ok);
|
||||
(void)got_ok;
|
||||
SS_CHECK(got_ok);
|
||||
|
||||
bfree(&buf);
|
||||
c->ctx_release(&enc);
|
||||
@@ -229,8 +222,7 @@ test_tcp_partial_delivery(const char *method)
|
||||
}
|
||||
|
||||
/* A tampered ciphertext must fail authentication rather than pass through. */
|
||||
static void
|
||||
test_tcp_tamper_detection(const char *method)
|
||||
void test_tcp_tamper_detection(const char *method)
|
||||
{
|
||||
static const uint8_t addr[] = { 0x01, 127, 0, 0, 1, 0x00, 0x50 };
|
||||
crypto_t *c = make_crypto(method);
|
||||
@@ -244,16 +236,16 @@ test_tcp_tamper_detection(const char *method)
|
||||
dec.role = CRYPTO_ROLE_SERVER;
|
||||
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
std::memset(&buf, 0, sizeof(buf));
|
||||
balloc(&buf, 4096);
|
||||
memcpy(buf.data, addr, sizeof(addr));
|
||||
std::memcpy(buf.data, addr, sizeof(addr));
|
||||
buf.len = sizeof(addr);
|
||||
assert(c->encrypt(&buf, &enc, 4096) == CRYPTO_OK);
|
||||
SS_CHECK(c->encrypt(&buf, &enc, 4096) == CRYPTO_OK);
|
||||
|
||||
/* Flip a bit inside the first header chunk (past the salt). */
|
||||
buf.data[c->cipher->key_len + 2] ^= 0x01;
|
||||
|
||||
assert(c->decrypt(&buf, &dec, 4096) == CRYPTO_ERROR);
|
||||
SS_CHECK(c->decrypt(&buf, &dec, 4096) == CRYPTO_ERROR);
|
||||
|
||||
bfree(&buf);
|
||||
c->ctx_release(&enc);
|
||||
@@ -262,8 +254,7 @@ test_tcp_tamper_detection(const char *method)
|
||||
}
|
||||
|
||||
/* UDP packets must round-trip through the session interface. */
|
||||
static void
|
||||
test_udp_roundtrip(const char *method)
|
||||
void test_udp_roundtrip(const char *method)
|
||||
{
|
||||
static const uint8_t pkt[] = {
|
||||
0x01, 8, 8, 8, 8, 0x00, 0x35, /* 8.8.8.8:53 */
|
||||
@@ -271,26 +262,26 @@ test_udp_roundtrip(const char *method)
|
||||
};
|
||||
|
||||
crypto_t *c = make_crypto(method);
|
||||
assert(c->encrypt_udp != NULL);
|
||||
assert(c->decrypt_udp != NULL);
|
||||
SS_CHECK(c->encrypt_udp != nullptr);
|
||||
SS_CHECK(c->decrypt_udp != nullptr);
|
||||
|
||||
void *client_session = NULL;
|
||||
void *server_session = NULL;
|
||||
void *client_session = nullptr;
|
||||
void *server_session = nullptr;
|
||||
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
std::memset(&buf, 0, sizeof(buf));
|
||||
balloc(&buf, 2048);
|
||||
memcpy(buf.data, pkt, sizeof(pkt));
|
||||
std::memcpy(buf.data, pkt, sizeof(pkt));
|
||||
buf.len = sizeof(pkt);
|
||||
|
||||
aead_set_role(CRYPTO_ROLE_CLIENT);
|
||||
assert(c->encrypt_udp(&buf, c->cipher, 2048, &client_session) == CRYPTO_OK);
|
||||
assert(buf.len > sizeof(pkt));
|
||||
SS_CHECK(c->encrypt_udp(&buf, c->cipher, 2048, &client_session) == CRYPTO_OK);
|
||||
SS_CHECK(buf.len > sizeof(pkt));
|
||||
|
||||
aead_set_role(CRYPTO_ROLE_SERVER);
|
||||
assert(c->decrypt_udp(&buf, c->cipher, 2048, &server_session) == CRYPTO_OK);
|
||||
assert(buf.len == sizeof(pkt));
|
||||
assert(memcmp(buf.data, pkt, sizeof(pkt)) == 0);
|
||||
SS_CHECK(c->decrypt_udp(&buf, c->cipher, 2048, &server_session) == CRYPTO_OK);
|
||||
SS_CHECK(buf.len == sizeof(pkt));
|
||||
SS_CHECK(std::memcmp(buf.data, pkt, sizeof(pkt)) == 0);
|
||||
|
||||
bfree(&buf);
|
||||
c->udp_session_release(client_session);
|
||||
@@ -300,39 +291,38 @@ test_udp_roundtrip(const char *method)
|
||||
}
|
||||
|
||||
/* A replayed UDP packet must be rejected by the sliding window filter. */
|
||||
static void
|
||||
test_udp_replay_rejected(const char *method)
|
||||
void test_udp_replay_rejected(const char *method)
|
||||
{
|
||||
static const uint8_t pkt[] = { 0x01, 8, 8, 8, 8, 0x00, 0x35, 0x42 };
|
||||
|
||||
crypto_t *c = make_crypto(method);
|
||||
void *client_session = NULL;
|
||||
void *server_session = NULL;
|
||||
void *client_session = nullptr;
|
||||
void *server_session = nullptr;
|
||||
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
std::memset(&buf, 0, sizeof(buf));
|
||||
balloc(&buf, 2048);
|
||||
memcpy(buf.data, pkt, sizeof(pkt));
|
||||
std::memcpy(buf.data, pkt, sizeof(pkt));
|
||||
buf.len = sizeof(pkt);
|
||||
|
||||
aead_set_role(CRYPTO_ROLE_CLIENT);
|
||||
assert(c->encrypt_udp(&buf, c->cipher, 2048, &client_session) == CRYPTO_OK);
|
||||
SS_CHECK(c->encrypt_udp(&buf, c->cipher, 2048, &client_session) == CRYPTO_OK);
|
||||
|
||||
/* Keep a copy of the wire packet so we can replay it verbatim. */
|
||||
buffer_t copy;
|
||||
memset(©, 0, sizeof(copy));
|
||||
std::memset(©, 0, sizeof(copy));
|
||||
balloc(©, 2048);
|
||||
memcpy(copy.data, buf.data, buf.len);
|
||||
std::memcpy(copy.data, buf.data, buf.len);
|
||||
copy.len = buf.len;
|
||||
|
||||
aead_set_role(CRYPTO_ROLE_SERVER);
|
||||
assert(c->decrypt_udp(&buf, c->cipher, 2048, &server_session) == CRYPTO_OK);
|
||||
SS_CHECK(c->decrypt_udp(&buf, c->cipher, 2048, &server_session) == CRYPTO_OK);
|
||||
/* A rejected packet must not publish a session into a fresh relay slot. */
|
||||
void *rejected_session = NULL;
|
||||
assert(c->decrypt_udp(©, c->cipher, 2048, &rejected_session) == CRYPTO_ERROR);
|
||||
assert(rejected_session == NULL);
|
||||
void *rejected_session = nullptr;
|
||||
SS_CHECK(c->decrypt_udp(©, c->cipher, 2048, &rejected_session) == CRYPTO_ERROR);
|
||||
SS_CHECK(rejected_session == nullptr);
|
||||
/* the very same packet again must be refused */
|
||||
assert(c->decrypt_udp(©, c->cipher, 2048, &server_session) == CRYPTO_ERROR);
|
||||
SS_CHECK(c->decrypt_udp(©, c->cipher, 2048, &server_session) == CRYPTO_ERROR);
|
||||
|
||||
bfree(&buf);
|
||||
bfree(©);
|
||||
@@ -343,17 +333,16 @@ test_udp_replay_rejected(const char *method)
|
||||
}
|
||||
|
||||
/* Encrypt one client packet into buf and hand it to the server's slot. */
|
||||
static void
|
||||
client_to_server(crypto_t *c, buffer_t *buf, const uint8_t *pkt, size_t len,
|
||||
void client_to_server(crypto_t *c, buffer_t *buf, const uint8_t *pkt, size_t len,
|
||||
void **client_session, void **server_session)
|
||||
{
|
||||
memcpy(buf->data, pkt, len);
|
||||
std::memcpy(buf->data, pkt, len);
|
||||
buf->len = len;
|
||||
aead_set_role(CRYPTO_ROLE_CLIENT);
|
||||
assert(c->encrypt_udp(buf, c->cipher, 2048, client_session) == CRYPTO_OK);
|
||||
SS_CHECK(c->encrypt_udp(buf, c->cipher, 2048, client_session) == CRYPTO_OK);
|
||||
aead_set_role(CRYPTO_ROLE_SERVER);
|
||||
assert(c->decrypt_udp(buf, c->cipher, 2048, server_session) == CRYPTO_OK);
|
||||
assert(buf->len == len && memcmp(buf->data, pkt, len) == 0);
|
||||
SS_CHECK(c->decrypt_udp(buf, c->cipher, 2048, server_session) == CRYPTO_OK);
|
||||
SS_CHECK(buf->len == len && std::memcmp(buf->data, pkt, len) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -361,34 +350,33 @@ client_to_server(crypto_t *c, buffer_t *buf, const uint8_t *pkt, size_t len,
|
||||
* the table with fresh client session IDs used to free the session behind
|
||||
* the relay's back, so the reply path encrypted with freed memory.
|
||||
*/
|
||||
static void
|
||||
test_udp_session_survives_table_eviction(const char *method)
|
||||
void test_udp_session_survives_table_eviction(const char *method)
|
||||
{
|
||||
static const uint8_t pkt[] = { 0x01, 8, 8, 8, 8, 0x00, 0x35, 0x42 };
|
||||
|
||||
crypto_t *c = make_crypto(method);
|
||||
void *client_session = NULL;
|
||||
void *server_session = NULL;
|
||||
void *client_session = nullptr;
|
||||
void *server_session = nullptr;
|
||||
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
std::memset(&buf, 0, sizeof(buf));
|
||||
balloc(&buf, 2048);
|
||||
|
||||
client_to_server(c, &buf, pkt, sizeof(pkt), &client_session, &server_session);
|
||||
assert(server_session != NULL);
|
||||
SS_CHECK(server_session != nullptr);
|
||||
void *first = server_session;
|
||||
void *shared_session = NULL;
|
||||
void *shared_session = nullptr;
|
||||
client_to_server(c, &buf, pkt, sizeof(pkt), &client_session, &shared_session);
|
||||
assert(shared_session == first);
|
||||
SS_CHECK(shared_session == first);
|
||||
/* Reattaching the same slot must not acquire an extra reference. */
|
||||
client_to_server(c, &buf, pkt, sizeof(pkt), &client_session, &server_session);
|
||||
assert(server_session == first);
|
||||
SS_CHECK(server_session == first);
|
||||
|
||||
/* Each new client session ID inserts a table entry; overflow evicts ours. */
|
||||
for (int i = 0; i < AEAD_2022_UDP_SESSION_TABLE_CAP + 1; i++) {
|
||||
void *other_client = NULL, *other_server = NULL;
|
||||
void *other_client = nullptr, *other_server = nullptr;
|
||||
client_to_server(c, &buf, pkt, sizeof(pkt), &other_client, &other_server);
|
||||
assert(other_server != NULL && other_server != first);
|
||||
SS_CHECK(other_server != nullptr && other_server != first);
|
||||
c->udp_session_release(other_client);
|
||||
c->udp_session_release(other_server);
|
||||
}
|
||||
@@ -397,18 +385,18 @@ test_udp_session_survives_table_eviction(const char *method)
|
||||
c->udp_session_release(shared_session);
|
||||
|
||||
/* The reply must still encrypt with the evicted session and verify. */
|
||||
memcpy(buf.data, pkt, sizeof(pkt));
|
||||
std::memcpy(buf.data, pkt, sizeof(pkt));
|
||||
buf.len = sizeof(pkt);
|
||||
aead_set_role(CRYPTO_ROLE_SERVER);
|
||||
assert(c->encrypt_udp(&buf, c->cipher, 2048, &server_session) == CRYPTO_OK);
|
||||
assert(server_session == first);
|
||||
SS_CHECK(c->encrypt_udp(&buf, c->cipher, 2048, &server_session) == CRYPTO_OK);
|
||||
SS_CHECK(server_session == first);
|
||||
aead_set_role(CRYPTO_ROLE_CLIENT);
|
||||
assert(c->decrypt_udp(&buf, c->cipher, 2048, &client_session) == CRYPTO_OK);
|
||||
assert(buf.len == sizeof(pkt) && memcmp(buf.data, pkt, sizeof(pkt)) == 0);
|
||||
SS_CHECK(c->decrypt_udp(&buf, c->cipher, 2048, &client_session) == CRYPTO_OK);
|
||||
SS_CHECK(buf.len == sizeof(pkt) && std::memcmp(buf.data, pkt, sizeof(pkt)) == 0);
|
||||
|
||||
/* The client's next packet re-creates a table entry and swaps the slot. */
|
||||
client_to_server(c, &buf, pkt, sizeof(pkt), &client_session, &server_session);
|
||||
assert(server_session != NULL && server_session != first);
|
||||
SS_CHECK(server_session != nullptr && server_session != first);
|
||||
|
||||
/* Releasing the slot after eviction must neither leak nor double free. */
|
||||
c->udp_session_release(server_session);
|
||||
@@ -420,15 +408,14 @@ test_udp_session_survives_table_eviction(const char *method)
|
||||
}
|
||||
|
||||
/* The 2022 ciphers must reject a PSK of the wrong size rather than pad it. */
|
||||
static void
|
||||
test_psk_parsing(void)
|
||||
void test_psk_parsing()
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
/* Correct size decodes. */
|
||||
assert(crypto_parse_psk(PSK32, key, 32) == 32);
|
||||
SS_CHECK(crypto_parse_psk(PSK32, key, 32) == 32);
|
||||
for (int i = 0; i < 32; i++)
|
||||
assert(key[i] == 0);
|
||||
SS_CHECK(key[i] == 0);
|
||||
|
||||
/*
|
||||
* The standard alphabet ('+' and '/') and the URL-safe one ('-' and '_')
|
||||
@@ -436,38 +423,40 @@ test_psk_parsing(void)
|
||||
* tools using either convention.
|
||||
*/
|
||||
uint8_t k1[32], k2[32];
|
||||
assert(crypto_parse_psk("//////////////////////////////////////////8=", k1, 32) == 32);
|
||||
assert(crypto_parse_psk("__________________________________________8=", k2, 32) == 32);
|
||||
assert(memcmp(k1, k2, 32) == 0);
|
||||
SS_CHECK(crypto_parse_psk("//////////////////////////////////////////8=", k1, 32) == 32);
|
||||
SS_CHECK(crypto_parse_psk("__________________________________________8=", k2, 32) == 32);
|
||||
SS_CHECK(std::memcmp(k1, k2, 32) == 0);
|
||||
for (int i = 0; i < 32; i++)
|
||||
assert(k1[i] == 0xff);
|
||||
SS_CHECK(k1[i] == 0xff);
|
||||
|
||||
/* A key with distinct bytes must decode to exactly those bytes. */
|
||||
uint8_t k3[32];
|
||||
assert(crypto_parse_psk("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
|
||||
SS_CHECK(crypto_parse_psk("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
|
||||
k3, 32) == 32);
|
||||
for (int i = 0; i < 32; i++)
|
||||
assert(k3[i] == i);
|
||||
SS_CHECK(k3[i] == i);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
if (sodium_init() < 0)
|
||||
if (sodium_init() < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
test_blake3_empty_hash_vector();
|
||||
test_blake3_derive_key_known_vector();
|
||||
test_psk_parsing();
|
||||
SS_RUN(test_blake3_empty_hash_vector);
|
||||
SS_RUN(test_blake3_derive_key_known_vector);
|
||||
SS_RUN(test_psk_parsing);
|
||||
|
||||
for (size_t i = 0; i < sizeof(methods_2022) / sizeof(methods_2022[0]); i++) {
|
||||
const char *m = methods_2022[i];
|
||||
for (const char *m : methods_2022) {
|
||||
test_tcp_request_roundtrip(m);
|
||||
test_tcp_partial_delivery(m);
|
||||
test_tcp_tamper_detection(m);
|
||||
test_udp_roundtrip(m);
|
||||
test_udp_replay_rejected(m);
|
||||
test_udp_session_survives_table_eviction(m);
|
||||
std::printf("ok %s\n", m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user