Commit 08f5724b authored by jan.koester's avatar jan.koester
Browse files

test

parent 794ffc67
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -514,9 +514,26 @@ namespace netplus {
                    }
                    
                    // If there's pending data to send (handshake response)
                    // CRITICAL: flush_out() posts WSASend ASYNCHRONOUSLY in IOCP mode
                    if (owner->csock->hasPendingWrite()) {
                        std::cerr << "[IOCP] Flushing handshake response via IOCP..." << std::endl;
                        std::cerr << "[IOCP] Flushing handshake response, posting async WSASend..." << std::endl;
                        owner->csock->flush_out();
                        std::cerr << "[IOCP] flush_out posted - now continuing in READ handler" << std::endl;
                        // After posting async write, DON'T try to recv more data yet.
                        // The write completion handler will decide what's next.
                        // Just post recv and let IOCP sequence things properly.
                        if (!owner->csock->getHandshakeDone()) {
                            std::cerr << "[IOCP] Still in handshake, posting recv for next message" << std::endl;
                            try {
                                post_recv(st, *owner);
                            } catch (...) {}
                        } else {
                            std::cerr << "[IOCP] Handshake complete, posting recv for application data" << std::endl;
                            try {
                                post_recv(st, *owner);
                            } catch (...) {}
                        }
                        continue;
                    }
                    
                    // If handshake still not done, wait for more data
@@ -575,6 +592,10 @@ namespace netplus {
                // So we clear SendData entirely on completion
                bool isSSL = (owner->csock->getSocketType() == sockettype::SSL);
                
                // CRITICAL: Clear the pending IOCP write flag
                owner->csock->setPendingWrite(false);
                std::cerr << "[IOCP] Write completed, cleared _pendingIocpWrite" << std::endl;
                
                if (isSSL) {
                    // SSL: all data was encrypted and sent
                    owner->SendData.clear();
+10 −1
Original line number Diff line number Diff line
@@ -179,6 +179,7 @@ namespace netplus {
		virtual size_t recvData(buffer& data, int flags = 0) = 0;

		virtual bool hasPendingWrite() const { return false; }
		virtual void setPendingWrite(bool pending) {}  // Only used for SSL/IOCP
		virtual bool getHandshakeDone() { return true; }
		virtual int  getSocketType() const { return _Type; }

@@ -334,9 +335,15 @@ namespace netplus {
		bool loadServerPrivateKey(const std::vector<uint8_t>& keyData);

		bool hasPendingWrite() const override {
			return (!_send_queue.empty()) || (_send_off < _send_record.size());
			// Return true if there's queued data not yet sent
			// Check _send_queue (queued but not flushed)
			// Check _send_off (current record being transmitted via WSASend)
			// Check _pendingIocpWrite (async WSASend posted but not completed)
			return (!_send_queue.empty()) || (_send_off > 0) || _pendingIocpWrite;
		}

		void setPendingWrite(bool pending) override { _pendingIocpWrite = pending; }

		bool getHandshakeDone() override { return _handshakeDone; }

		virtual void queueRaw(const std::vector<uint8_t>& v);
@@ -485,6 +492,7 @@ namespace netplus {
			return sha256_hash(_handshake_transcript);
		}

		std::vector<uint8_t> _rsa_sha256_pkcs15_sign(const std::vector<uint8_t>& in);
		std::vector<uint8_t> _rsa_pss_sha256_sign(const std::vector<uint8_t>& in);
		std::vector<uint8_t> _ecdsa_sha256_sign(const std::vector<uint8_t>& in);

@@ -526,6 +534,7 @@ namespace netplus {
		std::deque<std::vector<uint8_t>> _send_queue;
		std::vector<uint8_t> _send_record;
		size_t _send_off = 0;
		bool _pendingIocpWrite = false;  // IOCP WSASend posted but not yet completed

		std::vector<uint8_t> _rx_record_buf;
		std::vector<uint8_t> _rx_handshake_buf;
+219 −74
Original line number Diff line number Diff line
@@ -1266,6 +1266,7 @@ std::vector<uint8_t> netplus::ssl::_fetchNextHandshakeTLS13()

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()) return {};

@@ -1276,6 +1277,13 @@ 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];

        // ✅ Skip CCS records (middlebox compatibility in TLS 1.3)
        if (outer_type == 0x14) {
            if (rec.size() == 6 && rec[5] == 0x01) {
                continue;  // ignore CCS, read next record
            }
        }

        if (outer_type == 0x15)
            throwSSL(NetException::Error, "TLS1.3 alert received");

@@ -1336,10 +1344,29 @@ std::vector<uint8_t> netplus::ssl::_tls13_read_record_handshake()
            throwSSL(NetException::Error, "TLS1.3 inner all padding");

        uint8_t inner_type = inner[end - 1];
    if (inner_type != 0x16)
        
        std::cerr << "[TLS] record decrypted: size=" << inner.size() << " stripped=" << end << " type=0x" << std::hex << (int)inner_type << std::dec << std::endl;
        std::cerr.flush();
        
        // ✅ 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)
            std::cerr << "[TLS] ALERT RECEIVED from client: ";
            if (end >= 2) {
                uint8_t level = inner[0];
                uint8_t desc = inner[1];
                std::cerr << "level=" << (int)level << " desc=" << (int)desc;
            }
            std::cerr << std::endl;
            std::cerr.flush();
            // Continue anyway for now to see what happens
        }
        
        if (inner_type != 0x16 && inner_type != 0x15)
            throwSSL(NetException::Error, "TLS1.3 inner type not handshake");

        return std::vector<uint8_t>(inner.begin(), inner.begin() + (end - 1));
    }  // end loop
}

std::vector<uint8_t> netplus::ssl::_tls13_build_certificate()
@@ -1390,21 +1417,44 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_certificate_verify()
    toSign.push_back(0x00);
    toSign.insert(toSign.end(), th.begin(), th.end());

    // DEBUG: Log what we're signing
    fprintf(stderr, "[TLS] CertificateVerify: toSign buffer size=%zu\n", toSign.size());
    fprintf(stderr, "[TLS] CertificateVerify: transcript hash (first 16 bytes): ");
    for (int i = 0; i < 16 && i < (int)th.size(); i++)
        fprintf(stderr, "%02x ", th[i]);
    fprintf(stderr, "\n");

    std::vector<uint8_t> sig;
    std::vector<uint8_t> cv;
    
    if (_has_ec_key) {
        // Use ECDSA-SHA256 with P-256 curve
    // Use RSA-PKCS1-SHA256 (0x0401) for maximum compatibility
    // This is the classic RSA signature algorithm, widely supported
    if (_rsa) {
        // For TLS 1.3, we need to use RSA-PKCS1-SHA256 (0x0401)
        // which is RSA signature with PKCS#1 v1.5 padding
        sig = _rsa_sha256_pkcs15_sign(toSign);
        if (sig.empty())
            throwSSL(NetException::Error, "TLS1.3 CertificateVerify: RSA signature empty");
        
        // DEBUG: Log RSA signature details
        fprintf(stderr, "[TLS] RSA-PKCS1-SHA256 signature generated: size=%zu\n", sig.size());
        fprintf(stderr, "[TLS] RSA signature (first 16 bytes): ");
        for (int i = 0; i < 16 && i < (int)sig.size(); i++)
            fprintf(stderr, "%02x ", sig[i]);
        fprintf(stderr, "\n");
        fprintf(stderr, "[TLS] RSA signature (last 16 bytes): ");
        for (int i = (int)sig.size() - 16; i < (int)sig.size(); i++)
            if (i >= 0) fprintf(stderr, "%02x ", sig[i]);
        fprintf(stderr, "\n");
        
        cv.push_back(0x04); cv.push_back(0x01);  // rsa_pkcs1_sha256
    } else if (_has_ec_key) {
        // Use ECDSA-SHA256 with P-256 curve (0x0403)
        sig = _ecdsa_sha256_sign(toSign);
        if (sig.empty())
            throwSSL(NetException::Error, "TLS1.3 CertificateVerify: ECDSA signature empty");
        fprintf(stderr, "[TLS] ECDSA-SHA256 signature generated: size=%zu\n", sig.size());
        cv.push_back(0x04); cv.push_back(0x03);  // ecdsa_secp256r1_sha256
    } else if (_rsa) {
        // Use RSA-PSS-SHA256
        sig = _rsa_pss_sha256_sign(toSign);
        if (sig.empty())
            throwSSL(NetException::Error, "TLS1.3 CertificateVerify: RSA signature empty");
        cv.push_back(0x08); cv.push_back(0x04);  // rsa_pss_rsae_sha256
    } else {
        throwSSL(NetException::Error, "TLS1.3 CertificateVerify: no private key available");
    }
@@ -1412,6 +1462,14 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_certificate_verify()
    cv.push_back(uint8_t(sig.size() >> 8));
    cv.push_back(uint8_t(sig.size() & 0xFF));
    cv.insert(cv.end(), sig.begin(), sig.end());
    
    fprintf(stderr, "[TLS] CertificateVerify message complete: total size=%zu (alg_id=2 + len=2 + sig=%zu)\n", 
            cv.size(), sig.size());
    fprintf(stderr, "[TLS] CertificateVerify (first 20 bytes): ");
    for (int i = 0; i < 20 && i < (int)cv.size(); i++)
        fprintf(stderr, "%02x ", cv[i]);
    fprintf(stderr, "\n");
    
    return cv;
}

@@ -2308,8 +2366,9 @@ void netplus::ssl::handshake_after_accept(){
            // The client computes its Finished over CH..server_Finished (not including client Finished)
            std::vector<uint8_t> th_before_client_finished = sha256_hash(_handshake_transcript);
            
            // wir erwarten encrypted records (outer 0x17) mit handshake keys
            std::vector<uint8_t> msg = _fetchNextHandshakePlain();
            // ✅ FIXED: Read ENCRYPTED handshake record (not plaintext!)
            // After ServerHello, all handshake messages are encrypted with handshake keys
            std::vector<uint8_t> msg = _tls13_read_record_handshake();
            if (msg.empty()) {
                // Must throw Note so event loop waits for more data
                NetException n;
@@ -2349,7 +2408,16 @@ void netplus::ssl::handshake_after_accept(){
            if (expected != client_verify)
                throwSSL(NetException::Error, "TLS1.3 Finished verify_data mismatch");

            // Note: transcript already includes client Finished (added by _fetchNextHandshakePlain)
            // ✅ Add client Finished to transcript (includes handshake header + body)
            std::vector<uint8_t> client_finished_msg;
            client_finished_msg.push_back(0x14);  // Finished type
            client_finished_msg.push_back(0x00);
            client_finished_msg.push_back(0x00);
            client_finished_msg.push_back(0x20);  // length = 32
            client_finished_msg.insert(client_finished_msg.end(), client_verify.begin(), client_verify.end());
            
            _handshake_transcript.insert(_handshake_transcript.end(), 
                                         client_finished_msg.begin(), client_finished_msg.end());

            TLSDBG("✅ TLS1.3 Client Finished verified");

@@ -2611,6 +2679,8 @@ void netplus::ssl::flush_out(){
        _SendBuffer->data.len = (ULONG)combined.size();
        
        tcp::flush_out();
        _pendingIocpWrite = true;  // Mark async write as pending
        std::cerr << "[SSL] flush_out: Set _pendingIocpWrite=true, hasPendingWrite=" << hasPendingWrite() << std::endl;
    } catch (...) {
        throw;
    }
@@ -4329,6 +4399,81 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_server_finished() {
    return verify_data;
}

// RSA-PKCS1-v1.5-SHA256 signature for maximum compatibility with TLS 1.3
std::vector<uint8_t> netplus::ssl::_rsa_sha256_pkcs15_sign(const std::vector<uint8_t>& in){
    if (!_rsa) throwSSL(NetException::Error, "TLS1.3: no RSA private key");
    
    // Compute SHA256 hash
    std::vector<uint8_t> mHash = sha256_hash(in);
    if (mHash.size() != 32)
        throwSSL(NetException::Error, "SHA256 hash failed");
    
    fprintf(stderr, "[TLS] _rsa_sha256_pkcs15_sign: input size=%zu, hash size=%zu\n", in.size(), mHash.size());
    fprintf(stderr, "[TLS] SHA256 hash: ");
    for (int i = 0; i < 16; i++) fprintf(stderr, "%02x ", mHash[i]);
    fprintf(stderr, "...\n");
    
    // PKCS#1 v1.5 signature digest info for SHA256:
    // DigestInfo ::= SEQUENCE {
    //   digestAlgorithm DigestAlgorithmIdentifier,
    //   digest Digest
    // }
    // For SHA256: OID = 2.16.840.1.101.3.4.2.1 = 60 86 48 01 65 03 04 02 01
    const uint8_t sha256_prefix[] = {
        0x30, 0x31,                       // SEQUENCE length=49
        0x30, 0x0d,                       // SEQUENCE length=13 (algId)
        0x06, 0x09, 0x60, 0x86, 0x48,   // OID for SHA256
        0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
        0x05, 0x00,                       // NULL
        0x04, 0x20                        // OCTET STRING length=32
    };
    const size_t sha256_prefix_len = sizeof(sha256_prefix) / sizeof(sha256_prefix[0]);
    
    fprintf(stderr, "[TLS] SHA256 DigestInfo prefix (%zu bytes): ", sha256_prefix_len);
    for (size_t i = 0; i < sha256_prefix_len; i++) fprintf(stderr, "%02x ", sha256_prefix[i]);
    fprintf(stderr, "\n");
    
    // Build DigestInfo: prefix || hash
    std::vector<uint8_t> tBuf;
    tBuf.insert(tBuf.end(), sha256_prefix, sha256_prefix + sha256_prefix_len);
    tBuf.insert(tBuf.end(), mHash.begin(), mHash.end());
    
    fprintf(stderr, "[TLS] DigestInfo total size=%zu\n", tBuf.size());
    
    // Build PKCS#1 v1.5 encoded message
    size_t modBytes = (_rsa.n.bitLength() + 7) / 8;
    fprintf(stderr, "[TLS] RSA modulus bits=%u, bytes=%zu\n", _rsa.n.bitLength(), modBytes);
    
    if (tBuf.size() > modBytes - 11)
        throwSSL(NetException::Error, "Message too long for RSA key");
    
    std::vector<uint8_t> EM(modBytes, 0x00);
    EM[0] = 0x00;
    EM[1] = 0x01;  // Block type (signature)
    // Padding bytes (0xFF)
    for (size_t i = 2; i < modBytes - tBuf.size() - 1; i++)
        EM[i] = 0xFF;
    EM[modBytes - tBuf.size() - 1] = 0x00;  // Separator
    // Copy digest info
    std::memcpy(&EM[modBytes - tBuf.size()], tBuf.data(), tBuf.size());
    
    fprintf(stderr, "[TLS] PKCS#1 EM encoding: [00 01 FF...FF 00 DigestInfo]\n");
    fprintf(stderr, "[TLS] EM (first 20 bytes): ");
    for (int i = 0; i < 20 && i < (int)EM.size(); i++) fprintf(stderr, "%02x ", EM[i]);
    fprintf(stderr, "\n");
    fprintf(stderr, "[TLS] EM (last 20 bytes): ");
    for (int i = (int)EM.size() - 20; i < (int)EM.size(); i++) 
        if (i >= 0) fprintf(stderr, "%02x ", EM[i]);
    fprintf(stderr, "\n");
    
    // Perform raw RSA operation: signature = EM^d mod n
    rsa::bigInt m = rsa::bytesToBigIntBE(EM);
    rsa::bigInt s = rsa::modPow(m, _rsa.d, _rsa.n);
    
    std::vector<uint8_t> sig = rsa::bigIntToBytesBE(s, modBytes);
    fprintf(stderr, "[TLS] Final RSA signature size=%zu (should be %zu)\n", sig.size(), modBytes);
    return sig;
}

std::vector<uint8_t> netplus::ssl::_rsa_pss_sha256_sign(const std::vector<uint8_t>& in){
    if (!_rsa) throwSSL(NetException::Error, "TLS1.3: no RSA private key");