EV-Kafka
view release on metacpan or search on metacpan
src/EV__Kafka.xs view on Meta::CPAN
snprintf(errbuf, sizeof(errbuf), "SASL auth failed: error %d", error_code);
conn_emit_error(aTHX_ self, errbuf);
if (conn_check_destroyed(self)) return;
conn_handle_disconnect(aTHX_ self, "SASL auth failed");
return;
}
#ifdef HAVE_OPENSSL
/* SCRAM multi-step handling */
if (self->sasl_mechanism && self->scram_step == SCRAM_STEP_CLIENT_FIRST && auth_data) {
/* Server-first-message: r=<nonce>,s=<salt>,i=<iterations> */
/* Parse server response, compute proof, send client-final */
const char *server_nonce = NULL;
size_t server_nonce_len = 0;
const char *salt_b64 = NULL;
size_t salt_b64_len = 0;
int iterations = 0;
{
const char *sp = auth_data;
const char *se = auth_data + auth_data_len;
while (sp < se) {
if (sp + 2 <= se && sp[0] == 'r' && sp[1] == '=') {
sp += 2; server_nonce = sp;
while (sp < se && *sp != ',') sp++;
server_nonce_len = sp - server_nonce;
} else if (sp + 2 <= se && sp[0] == 's' && sp[1] == '=') {
sp += 2; salt_b64 = sp;
while (sp < se && *sp != ',') sp++;
salt_b64_len = sp - salt_b64;
} else if (sp + 2 <= se && sp[0] == 'i' && sp[1] == '=') {
sp += 2;
iterations = atoi(sp);
while (sp < se && *sp != ',') sp++;
}
if (sp < se && *sp == ',') sp++;
else sp++;
}
}
if (!server_nonce || !salt_b64 || iterations <= 0 || iterations > 1048576) {
conn_emit_error(aTHX_ self, "SCRAM: malformed server-first-message");
if (conn_check_destroyed(self)) return;
conn_handle_disconnect(aTHX_ self, "SCRAM auth failed");
return;
}
/* RFC 5802: server nonce must start with client nonce */
if (server_nonce_len < 32 ||
memcmp(server_nonce, self->scram_nonce, 32) != 0) {
conn_emit_error(aTHX_ self, "SCRAM: server nonce mismatch");
src/EV__Kafka.xs view on Meta::CPAN
salt_len = BIO_read(bmem, salt, sizeof(salt));
BIO_free_all(bmem);
if (salt_len <= 0) {
conn_emit_error(aTHX_ self, "SCRAM: bad salt");
if (conn_check_destroyed(self)) return;
conn_handle_disconnect(aTHX_ self, "SCRAM auth failed");
return;
}
}
/* SaltedPassword = Hi(password, salt, iterations) using PBKDF2 */
unsigned char salted_password[64];
PKCS5_PBKDF2_HMAC(self->sasl_password, strlen(self->sasl_password),
salt, salt_len, iterations, md, digest_len, salted_password);
/* ClientKey = HMAC(SaltedPassword, "Client Key") */
unsigned char client_key[64];
unsigned int ck_len = digest_len;
HMAC(md, salted_password, digest_len,
(unsigned char *)"Client Key", 10, client_key, &ck_len);
/* ServerKey = HMAC(SaltedPassword, "Server Key") â saved for
* server-final-message verification. */
unsigned int sk_hmac_len = digest_len;
xt/fuzz_structured.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use EV::Kafka;
# Structured/mutation parser fuzzing. xt/fuzz_decode.t feeds UNIFORM
# RANDOM bytes to the parsers â that can never build a valid response
# envelope around a poisoned length field, which is exactly why the
# fetch-response int32 overflow (batch_length 0x7FFFFFF9, a one-packet
# remote segfault) survived it at 20k iterations.
#
# Here we build VALID response envelopes (same byte-builder style as the
# t/18/t/21 goldens), record the offset of every length/count/varint
# field while building, then splice hostile values into those fields:
# negative, 0, INT32_MAX, INT32_MIN, off-by-one vs the remaining byte
# count, and huge/overlong uvarints. The parser must return undef or a
# hashref (arrayref for the batch decoder) and never crash, panic, or
# die.
plan skip_all => 'set RELEASE_TESTING' unless $ENV{RELEASE_TESTING};
( run in 1.263 second using v1.01-cache-2.11-cpan-4ab04211f4c )