refactor(crypto): pass static public key to `noise_xxpsk3_*_init()`
What changed, and why it matters
This commit changes how a cryptographic library sets up secure connections. Previously, the code automatically calculated the public key from the private key. Now, the caller must provide the public key directly. This is a code-quality refactor that reduces the risk of using mismatched keys, but the commit itself does not claim to fix a specific security bug and no exploit is described.
Review all call sites of `noise_xxpsk3_initiator_init()` and `noise_xxpsk3_responder_init()` to ensure the supplied static public key is correctly derived from and matches the static private key. Treat this as a defensive hardening change rather than an active vulnerability patch unless further evidence emerges.
Security signals we found
Cryptographic key handling changed: public key is now supplied rather than derived
Potential reduction of key-mismatch risk if caller provides correct public key
New null-pointer check added for static_public_key
No changelog entry; commit framed as refactor
Evidence from the diff
The patch refactors noise_xxpsk3_initiator_init() and noise_xxpsk3_responder_init() to accept a caller-supplied static public key instead of deriving it via curve25519_scalarmult_basepoint() from the static private key. The internal noise_xxpsk3_init_state() now copies the provided public key into the handshake state. This prevents a class of key-mismatch bugs where the public key used in the handshake could differ from the one the caller expects, but it also shifts responsibility for key correctness to callers. The commit is tagged [no changelog] and contains no security disclosure or incident attribution.
Changed components
crypto/noise_xxpsk3.ccrypto/noise_xxpsk3.hInspect captured patch +20 / −9
diff --git a/crypto/noise_xxpsk3.c b/crypto/noise_xxpsk3.c
index b68bba69..8e313ded 100644
--- a/crypto/noise_xxpsk3.c
+++ b/crypto/noise_xxpsk3.c
@@ -356,6 +356,7 @@ static bool noise_xxpsk3_init_state(
noise_xxpsk3_handshake_state_t *state,
const uint8_t psk[NOISE_XXPSK3_DHLEN],
const uint8_t static_private_key[NOISE_XXPSK3_DHLEN],
+ const uint8_t static_public_key[NOISE_XXPSK3_DHLEN],
const uint8_t *prologue, size_t prologue_len) {
static const uint8_t XX_PROTOCOL_NAME[] = "Noise_XXpsk3_25519_AESGCM_SHA256";
@@ -367,7 +368,7 @@ static bool noise_xxpsk3_init_state(
sizeof(XX_PROTOCOL_NAME) - 1); // -1 substract the string terminator
memcpy(state->static_private, static_private_key, NOISE_XXPSK3_DHLEN);
- curve25519_scalarmult_basepoint(state->static_public, state->static_private);
+ memcpy(state->static_public, static_public_key, NOISE_XXPSK3_DHLEN);
ss_mix_hash(&state->symmetric_state, prologue, prologue_len);
@@ -383,12 +384,14 @@ static bool noise_xxpsk3_init_state(
bool noise_xxpsk3_responder_init(
noise_xxpsk3_responder_t *rspn, const uint8_t psk[NOISE_XXPSK3_DHLEN],
- const uint8_t static_private_key[NOISE_XXPSK3_DHLEN]) {
+ const uint8_t static_private_key[NOISE_XXPSK3_DHLEN],
+ const uint8_t static_public_key[NOISE_XXPSK3_DHLEN]) {
if (rspn == NULL) {
return false;
}
- if (rspn->initialized || psk == NULL || static_private_key == NULL) {
+ if (rspn->initialized || psk == NULL || static_private_key == NULL ||
+ static_public_key == NULL) {
goto cleanup;
}
@@ -396,7 +399,7 @@ bool noise_xxpsk3_responder_init(
memset(rspn, 0, sizeof(noise_xxpsk3_responder_t));
if (!noise_xxpsk3_init_state(&rspn->handshake_state, psk, static_private_key,
- NULL, 0)) {
+ static_public_key, NULL, 0)) {
goto cleanup;
}
@@ -610,12 +613,14 @@ cleanup:
bool noise_xxpsk3_initiator_init(
noise_xxpsk3_initiator_t *intr, const uint8_t psk[NOISE_XXPSK3_DHLEN],
- const uint8_t static_private_key[NOISE_XXPSK3_DHLEN]) {
+ const uint8_t static_private_key[NOISE_XXPSK3_DHLEN],
+ const uint8_t static_public_key[NOISE_XXPSK3_DHLEN]) {
if (intr == NULL) {
return false;
}
- if (intr->initialized || psk == NULL || static_private_key == NULL) {
+ if (intr->initialized || psk == NULL || static_private_key == NULL ||
+ static_public_key == NULL) {
goto cleanup;
}
@@ -623,7 +628,7 @@ bool noise_xxpsk3_initiator_init(
memset(intr, 0, sizeof(noise_xxpsk3_initiator_t));
if (!noise_xxpsk3_init_state(&intr->handshake_state, psk, static_private_key,
- NULL, 0)) {
+ static_public_key, NULL, 0)) {
goto cleanup;
}
diff --git a/crypto/noise_xxpsk3.h b/crypto/noise_xxpsk3.h
index 4d89d5a3..ad1098d3 100644
--- a/crypto/noise_xxpsk3.h
+++ b/crypto/noise_xxpsk3.h
@@ -133,11 +133,14 @@ typedef struct {
* @param intr Pointer to the initiator structure to initialize
* @param psk Pre-shared key for the Noise protocol (32 bytes)
* @param static_private_key Static private key for the initiator (32 bytes)
+ * @param static_public_key Static public key corresponding to
+ * `static_private_key` (32 bytes)
* @return true if the initiator was initialized correctly, false otherwise
*/
bool noise_xxpsk3_initiator_init(
noise_xxpsk3_initiator_t *intr, const uint8_t psk[NOISE_XXPSK3_DHLEN],
- const uint8_t static_private_key[NOISE_XXPSK3_DHLEN]);
+ const uint8_t static_private_key[NOISE_XXPSK3_DHLEN],
+ const uint8_t static_public_key[NOISE_XXPSK3_DHLEN]);
/**
* @brief Deinitialize the initiator structure and clear any sensitive data.
@@ -252,11 +255,14 @@ bool noise_xxpsk3_initiator_create_request2(
* @param rspn Pointer to the responder structure to initialize
* @param psk Pre-shared key for the Noise protocol (32 bytes)
* @param static_private_key Static private key for the responder (32 bytes)
+ * @param static_public_key Static public key corresponding to
+ * `static_private_key` (32 bytes)
* @return true if the responder was initialized correctly, false otherwise
*/
bool noise_xxpsk3_responder_init(
noise_xxpsk3_responder_t *rspn, const uint8_t psk[NOISE_XXPSK3_DHLEN],
- const uint8_t static_private_key[NOISE_XXPSK3_DHLEN]);
+ const uint8_t static_private_key[NOISE_XXPSK3_DHLEN],
+ const uint8_t static_public_key[NOISE_XXPSK3_DHLEN]);
/**
* @brief Deinitialize the responder structure and clear any sensitive data.
Why this scored 27/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.