Commit 6786e2a5 authored by jan.koester's avatar jan.koester
Browse files

windows fixed

parent 1385af98
Loading
Loading
Loading
Loading
+36 −30
Original line number Diff line number Diff line
@@ -51,8 +51,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define BLOCKSIZE 16384
#endif

// Set to 1 to enable debug logging - REBUILD CHECK 4
#define IOCP_DEBUG 1
// Set to 1 to enable debug logging
#define IOCP_DEBUG 0

#if IOCP_DEBUG
#define IOCP_LOG(x) std::cerr << x << std::endl
@@ -495,9 +495,13 @@ namespace netplus {
            std::cerr << "[IOCP] Found connection, operation=" << (buf->operation == OP_READ ? "READ" : "WRITE") << " bytes=" << bytes << " InternalHigh=" << buf->overlapped.InternalHigh << std::endl;
#endif

            // For READ completions: push data directly into the socket's buffer
            // This avoids race conditions with InternalHigh being overwritten
            if (buf->operation == OP_READ && bytes > 0) {
            // For READ completions: hold event_mutex for entire processing
            // This serializes all READ handling for this connection
            if (buf->operation == OP_READ) {
                std::lock_guard<std::mutex> lock(owner->event_mutex);
                
                // Push data into socket's buffer while holding lock
                if (bytes > 0) {
                    owner->csock->pushReceivedData(
                        reinterpret_cast<const uint8_t*>(buf->data.buf), 
                        bytes
@@ -525,7 +529,6 @@ namespace netplus {
                    continue;
                }

            if (buf->operation == OP_READ) {
                if (bytes == 0) {
                    // Connection closed by peer
                    owner->ReadPending.store(false);
@@ -578,7 +581,7 @@ handshake_continue:
#if IOCP_DEBUG
                    std::cerr << "[IOCP] Starting handshake_after_accept (fd=" << owner->csock->fd() << ")..." << std::endl;
#endif
                    std::lock_guard<std::mutex> hsLock(owner->event_mutex);
                    // event_mutex already held
                    try {
                        // Process handshake from internal buffer
                        owner->csock->handshake_after_accept();
@@ -813,8 +816,10 @@ handshake_continue:
                    continue;
                }

                // NO MUTEX HERE - avoid deadlock with flush_out
                // WritePending atomic protects against concurrent try_post_send calls
                // Hold event_mutex for application data handling to protect SSL state
                // The handshake path above already holds the mutex
                {
                std::lock_guard<std::mutex> lock(owner->event_mutex);
                
                owner->WritePending.store(false);
                
@@ -876,6 +881,7 @@ handshake_continue:
                } catch (...) {
                    try_cleanup_con(ev, st, owner, cs, tid);
                }
                } // end lock_guard scope

                // send buffer is internal - no delete
                // if (buf) delete buf;
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <array>
#include <iostream>
#include <atomic>
#include <mutex>
#include <string>
#include <memory>
#include <deque>
@@ -367,6 +368,7 @@ namespace netplus {
		bool hasBufferedData() const { return !_rx_tcp_buf.empty(); }

		// Push received data directly into the buffer (called by IOCP)
		// Caller must hold con::event_mutex
		void pushReceivedData(const uint8_t* data, size_t len) override {
			_rx_tcp_buf.insert(_rx_tcp_buf.end(), data, data + len);
		}
+70 −40
Original line number Diff line number Diff line
@@ -360,67 +360,47 @@ netplus::ssl::ssl(std::shared_ptr<netplus::x509cert> cert, int sock) :

std::vector<uint8_t> netplus::ssl::readTlsRecordAsync()
{
    // Caller must hold con::event_mutex to protect _rx_tcp_buf
#if SSL_DEBUG
    std::cerr << "[SSL] readTlsRecordAsync: entry _rx_tcp_buf.size()=" << _rx_tcp_buf.size() << std::endl;
    
    // ----------------------------------------------------------------
    // Helper lambda: try to read more data from underlying TCP socket
    // On IOCP (Windows): data is pushed via pushReceivedData(), tcp::recvData throws Note
    // On epoll (Linux): tcp::recvData() calls ::recv() synchronously
    // ----------------------------------------------------------------
    auto tryReadMore = [this]() -> bool {
        try {
            buffer buf(16384);

            size_t got = tcp::recvData(buf, 0);
            if (got > 0) {
                _rx_tcp_buf.insert(_rx_tcp_buf.end(), 
                                   (uint8_t*)buf.data.buf,
                                   (uint8_t*)buf.data.buf + got);
                std::cerr << "[SSL] readTlsRecordAsync: tcp::recvData got " << got 
                          << " bytes, _rx_tcp_buf now " << _rx_tcp_buf.size() << std::endl;
                return true;
            }
        } catch (const NetException& e) {
            // Note = would block or no data (IOCP case)
            // Error = connection closed
            if (e.getErrorType() != NetException::Note) {
                throw;  // re-throw real errors
            }
        }
        return false;
    };
#endif
    
    // ----------------------------------------------------------------
    // 1) ensure we have at least TLS record header (5 bytes)
    // On Windows/IOCP: data arrives via pushReceivedData(), just check buffer
    // On Linux/epoll: would need to call tcp::recvData() - but that's handled
    // by the event loop before calling ssl::recvData()
    // ----------------------------------------------------------------
    while (_rx_tcp_buf.size() < 5) {
    if (_rx_tcp_buf.size() < 5) {
#if SSL_DEBUG
        std::cerr << "[SSL] readTlsRecordAsync: need header, only have " << _rx_tcp_buf.size() << " bytes" << std::endl;
        if (!tryReadMore()) {
#endif
        NetException n;
        n[NetException::Note] << "ssl: record incomplete (need header)";
        throw n;
    }
    }

    // ------------------------------------------------------------
    // 2) parse record length
    // ------------------------------------------------------------
    uint16_t recLen = (uint16_t(_rx_tcp_buf[3]) << 8) | uint16_t(_rx_tcp_buf[4]);
    size_t total = 5 + recLen;
#if SSL_DEBUG
    std::cerr << "[SSL] readTlsRecordAsync: header found, recLen=" << recLen << " total=" << total 
              << " type=0x" << std::hex << (int)_rx_tcp_buf[0] << std::dec << std::endl;
#endif
              
    // ------------------------------------------------------------
    // 3) ensure full record is present
    // ------------------------------------------------------------
    while (_rx_tcp_buf.size() < total) {
    if (_rx_tcp_buf.size() < total) {
#if SSL_DEBUG
        std::cerr << "[SSL] readTlsRecordAsync: need " << total << " bytes, only have " << _rx_tcp_buf.size() << std::endl;
        if (!tryReadMore()) {
#endif
        NetException n;
        n[NetException::Note] << "ssl: record incomplete";
        throw n;
    }
    }

    // ------------------------------------------------------------
    // 4) extract full record
@@ -1239,14 +1219,20 @@ std::vector<uint8_t> netplus::ssl::_tls13_read_record_handshake()
    for (;;) {  // Loop to skip CCS records
        std::vector<uint8_t> rec = readTlsRecordAsync();
        if (rec.empty()) {
#if SSL_DEBUG
            std::cerr << "[SSL] _tls13_read_record_handshake: readTlsRecordAsync returned empty" << std::endl;
#endif
            return {};
        }

#if SSL_DEBUG
        std::cerr << "[SSL] _tls13_read_record_handshake: got record, size=" << rec.size() << std::endl;
#endif

        if (rec.size() < 5) {
#if SSL_DEBUG
            std::cerr << "[SSL] _tls13_read_record_handshake: record too short (" << rec.size() << " < 5)" << std::endl;
#endif
            throwSSL(NetException::Error, "TLS1.3 record too short");
        }

@@ -1254,13 +1240,17 @@ std::vector<uint8_t> netplus::ssl::_tls13_read_record_handshake()
        uint16_t ver        = (uint16_t(rec[1]) << 8) | rec[2];
        uint16_t rlen       = (uint16_t(rec[3]) << 8) | rec[4];

#if SSL_DEBUG
        std::cerr << "[SSL] _tls13_read_record_handshake: outer_type=0x" << std::hex << (int)outer_type << std::dec 
                  << " ver=0x" << std::hex << ver << std::dec << " rlen=" << rlen << std::endl;
#endif

        // ✅ Skip CCS records (middlebox compatibility in TLS 1.3)
        if (outer_type == 0x14) {
            if (rec.size() == 6 && rec[5] == 0x01) {
#if SSL_DEBUG
                std::cerr << "[SSL] _tls13_read_record_handshake: skipping CCS record" << std::endl;
#endif
                continue;  // ignore CCS, read next record
            }
        }
@@ -1326,12 +1316,15 @@ std::vector<uint8_t> netplus::ssl::_tls13_read_record_handshake()

        uint8_t inner_type = inner[end - 1];

#if SSL_DEBUG
        std::cerr << "[TLS] record decrypted: size=" << inner.size() << " stripped=" << end << " type=0x" << std::hex << (int)inner_type << std::dec << std::endl;
        std::cerr.flush();
#endif

        // ✅ If alert, allow it through for debugging (client may be rejecting handshake)
        if (inner_type == 0x15) {
            // Alert: level (byte 0) + description (byte 1, in the plaintext)
#if SSL_DEBUG
            std::cerr << "[TLS] ALERT RECEIVED from client: ";
            if (end >= 2) {
                uint8_t level = inner[0];
@@ -1340,6 +1333,7 @@ std::vector<uint8_t> netplus::ssl::_tls13_read_record_handshake()
            }
            std::cerr << std::endl;
            std::cerr.flush();
#endif
            // Continue anyway for now to see what happens
        }

@@ -1593,8 +1587,10 @@ void netplus::ssl::_tls13_send_finished(bool handshake_keys){
void netplus::ssl::handshake_after_accept(){
    // Note: Caller (IOCP layer) must hold con::event_mutex to prevent concurrent access

#if SSL_DEBUG
    std::cerr << "[SSL] ===== handshake_after_accept ENTER state=" << (int)_hs_state << std::endl;
    std::cerr.flush();
#endif

    auto throwSSL = [&](int type, const std::string& msg) {
        netplus::NetException e;
@@ -1667,23 +1663,31 @@ void netplus::ssl::handshake_after_accept(){
    // Run as far as possible in one call, until IO would block (Note thrown)
    try {
    for (;;) {
#if SSL_DEBUG
        std::cerr << "[SSL] handshake_after_accept loop: state=" << (int)_hs_state << std::endl;
        std::cerr.flush();
#endif

        switch (_hs_state) {
        case HsState::READ_CLIENT_HELLO: {
#if SSL_DEBUG
            std::cerr << "[SSL] Processing READ_CLIENT_HELLO state" << std::endl;
            std::cerr.flush();
#endif

            std::vector<uint8_t> ch = _fetchNextHandshakePlain();
            if (ch.empty()) {
#if SSL_DEBUG
                std::cerr << "[SSL] READ_CLIENT_HELLO: fetchNextHandshakePlain returned empty - need more data" << std::endl;
                std::cerr.flush();
#endif
                return;
            }

#if SSL_DEBUG
            std::cerr << "[SSL] READ_CLIENT_HELLO: got " << ch.size() << " bytes of handshake message" << std::endl;
            std::cerr.flush();
#endif

            if (ch.size() < 4) throwSSL(NetException::Error, "ClientHello too short");
            if (ch[0] != 0x01) throwSSL(NetException::Error, "Expected ClientHello");
@@ -2164,12 +2168,16 @@ void netplus::ssl::handshake_after_accept(){
        // WAIT_CCS
        // ============================================================
        case HsState::WAIT_CCS: {
#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CCS: waiting for ChangeCipherSpec record" << std::endl;
            std::cerr.flush();
#endif

            if (_ccs_received) {
#if SSL_DEBUG
                std::cerr << "[SSL] WAIT_CCS: CCS already received, transitioning to WAIT_FIN" << std::endl;
                std::cerr.flush();
#endif
                _recv_seq = 0;
                _hs_state = HsState::WAIT_FIN;
                continue; // direkt WAIT_FIN probieren
@@ -2180,22 +2188,28 @@ void netplus::ssl::handshake_after_accept(){
                rec = readTlsRecordAsync();
            } catch (netplus::NetException& e) {
                if (e.getErrorType() == netplus::NetException::Note) {
#if SSL_DEBUG
                    std::cerr << "[SSL] WAIT_CCS: No data yet, returning" << std::endl;
                    std::cerr.flush();
#endif
                    return;
                }
                TLSDBG("readTlsRecordAsync ERROR");
                throw;
            }

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CCS: Got record, size=" << rec.size() << " type=" << (int)rec[0] << std::endl;
            std::cerr.flush();
#endif

            if (rec.size() != 6 || rec[0] != 0x14 || rec[5] != 0x01)
                throwSSL(NetException::Error, "Expected CCS");

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CCS: CCS received correctly, transitioning to WAIT_FIN" << std::endl;
            std::cerr.flush();
#endif

            _ccs_received = true;   // bleibt true bis WAIT_FIN erfolgreich war
            _recv_seq = 0;
@@ -2297,17 +2311,23 @@ void netplus::ssl::handshake_after_accept(){
        }

        case HsState::WAIT_CKE: {
#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: calling _fetchNextHandshakePlain()" << std::endl;
            std::cerr.flush();
#endif

            // ✅ Always read full handshake message (handles fragmentation)
            std::vector<uint8_t> msg = _fetchNextHandshakePlain();
#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: _fetchNextHandshakePlain returned " << msg.size() << " bytes" << std::endl;
            std::cerr.flush();
#endif

            if (msg.empty()) {
#if SSL_DEBUG
                std::cerr << "[SSL] WAIT_CKE: No data yet, returning" << std::endl;
                std::cerr.flush();
#endif
                return;  // would block
            }

@@ -2344,36 +2364,46 @@ void netplus::ssl::handshake_after_accept(){
                    " kBytes=" + std::to_string(kBytes));
            }

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: Decrypting RSA ciphertext (" << encLen << " bytes)..." << std::endl;
            std::cerr.flush();
#endif

            rsa::bigInt cipher = rsa::bigIntFromBytesBE(msg.data() + off, encLen);
            rsa::bigInt plainBI = _rsa.decrypt(cipher);

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: RSA decryption successful" << std::endl;
            std::cerr.flush();
#endif

            std::vector<uint8_t> pkcs1 = rsa::bigIntToBytesBE(plainBI, kBytes);
            std::vector<uint8_t> preMaster = extractPreMasterFromPkcs1(pkcs1);

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: Extracted premaster (" << preMaster.size() << " bytes)" << std::endl;
            std::cerr.flush();
#endif

            // master_secret = PRF(PMS, "master secret", client_random || server_random)
            std::vector<uint8_t> msSeed = _clientRandom;
            msSeed.insert(msSeed.end(), _serverRandom.begin(), _serverRandom.end());
            _masterSecret = _prf(preMaster, "master secret", msSeed, 48);

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: Master secret derived" << std::endl;
            std::cerr.flush();
#endif

            // key_block = PRF(master, "key expansion", server_random || client_random)
            std::vector<uint8_t> kbSeed = _serverRandom;
            kbSeed.insert(kbSeed.end(), _clientRandom.begin(), _clientRandom.end());
            std::vector<uint8_t> keyBlock = _prf(_masterSecret, "key expansion", kbSeed, 72);

#if SSL_DEBUG
            std::cerr << "[SSL] WAIT_CKE: Key block derived" << std::endl;
            std::cerr.flush();
#endif

            size_t k = 0;
            _client_mac_key.assign(keyBlock.begin() + k, keyBlock.begin() + k + 20); k += 20;