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 0.693 second using v1.01-cache-2.11-cpan-4ab04211f4c )