#include <iostream>
#include <iomanip>
#include <cstring>
#include <cctype>
#include <stdexcept>
#include <sstream>
#include <vector>
#include <fstream>

#include "tls.h"
#include "sha.h"
#include "rsa_pss_sha256.h"
#include "ecc_p256.h"
#include "ecc_u256.h"
#include "curve25519.h"

#include "../random.h"
#include "../socket.h"
#include "../exception.h"

#define SSL_LOG(x) ((void)0)
#define TLSDBG(x) ((void)0)

namespace netplus {

    // Helper to convert sequence number to bytes (big-endian)
    static inline void seqToBytes(uint64_t seq, uint8_t out[8]) {
        out[0] = uint8_t(seq >> 56);
        out[1] = uint8_t(seq >> 48);
        out[2] = uint8_t(seq >> 40);
        out[3] = uint8_t(seq >> 32);
        out[4] = uint8_t(seq >> 24);
        out[5] = uint8_t(seq >> 16);
        out[6] = uint8_t(seq >>  8);
        out[7] = uint8_t(seq);
    }

    // Helper function to extract SNI from ClientHello
    static bool extractSNIFromClientHello(const std::vector<uint8_t>& ch, std::string& hostname) {
        // ClientHello format: type(1) + length(3) + version(2) + random(32) + session_id_len(1) + ...
        if (ch.size() < 43) return false;
        
        size_t pos = 1 + 3; // skip type and length
        pos += 2 + 32; // skip version and random
        
        if (pos >= ch.size()) return false;
        uint8_t session_id_len = ch[pos++];
        pos += session_id_len;
        
        if (pos + 2 > ch.size()) return false;
        uint16_t cipher_suites_len = (uint16_t(ch[pos]) << 8) | ch[pos + 1];
        pos += 2 + cipher_suites_len;
        
        if (pos >= ch.size()) return false;
        uint8_t compression_len = ch[pos++];
        pos += compression_len;
        
        if (pos + 2 > ch.size()) return false;
        uint16_t extensions_len = (uint16_t(ch[pos]) << 8) | ch[pos + 1];
        pos += 2;
        
        size_t ext_end = pos + extensions_len;
        while (pos + 4 <= ext_end && pos + 4 <= ch.size()) {
            uint16_t ext_type = (uint16_t(ch[pos]) << 8) | ch[pos + 1];
            uint16_t ext_len = (uint16_t(ch[pos + 2]) << 8) | ch[pos + 3];
            pos += 4;
            
            if (ext_type == 0x0000 && ext_len >= 5) { // SNI extension
                // SNI list length (2) + name type (1) + name length (2) + name
                if (pos + ext_len <= ch.size()) {
                    size_t sni_pos = pos + 2; // skip list length
                    if (sni_pos < pos + ext_len && ch[sni_pos] == 0x00) { // host_name type
                        sni_pos++;
                        if (sni_pos + 2 <= pos + ext_len) {
                            uint16_t name_len = (uint16_t(ch[sni_pos]) << 8) | ch[sni_pos + 1];
                            sni_pos += 2;
                            if (sni_pos + name_len <= pos + ext_len) {
                                hostname.assign(reinterpret_cast<const char*>(&ch[sni_pos]), name_len);
                                return true;
                            }
                        }
                    }
                }
            }
            pos += ext_len;
        }
        return false;
    }

    // Helper function to extract premaster secret from PKCS#1 v1.5 padded block
    static std::vector<uint8_t> extractPreMasterFromPkcs1(const std::vector<uint8_t>& block) {
        // PKCS#1 v1.5: 0x00 0x02 <non-zero padding> 0x00 <data>
        if (block.size() < 11 + 48) {
            throw std::runtime_error("RSA plaintext too short");
        }
        if (block[0] != 0x00 || block[1] != 0x02) {
            throw std::runtime_error("Invalid PKCS#1 header");
        }
        
        size_t i = 2;
        while (i < block.size() && block[i] != 0x00) ++i;
        if (i >= block.size()) {
            throw std::runtime_error("Invalid PKCS#1 padding (no separator)");
        }
        
        ++i; // skip separator, now at first byte of premaster
        if (block.size() - i != 48) {
            throw std::runtime_error("Premaster not 48 bytes");
        }
        return std::vector<uint8_t>(block.begin() + i, block.end());
    }

    void tls::handshake_after_accept(){
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        // Note: Caller (IOCP layer) must hold con::event_mutex to prevent concurrent access

    #if SSL_DEBUG
    #endif

        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "ssl::accept: " << msg;
            throw e;
        };

        auto gen_tls13_p256_scalar = [&](uint8_t out_priv[32]) {
            for (;;) {
                netplus::fillRandomBytes(out_priv, 32);

                // priv == 0 ?
                bool allZero = true;
                for (int i=0;i<32;i++) if (out_priv[i]) { allZero=false; break; }
                if (allZero) continue;

                u256 k = bytes_be_to_u256(out_priv);

                // if k >= n -> retry
                if (u256_cmp(k, P256_N) >= 0)
                    continue;

                // ✅ ok: 0 < k < n
                return;
            }
        };

        TLSDBG("enter handshake_after_accept "
        << "pendingWrite=" << (hasPendingWrite()?"yes":"no")
        << " transcript=" << handshake_transcript.size()
        << " sendQ=" << send_queue.size());


        if (hs_state == HsState::IDLE) {
            send_seq = 0;
            recv_seq = 0;
            handshakeDone = false;
            handshake_transcript.clear();
            rx_handshake_buf.clear(); // Falls noch Reste drin waren
            hs_state = HsState::READ_CLIENT_HELLO;
        }

        // If already done -> nothing
        if (hs_state == HsState::DONE) {
            // sicherstellen: alles raus
            if (hasPendingWrite()) {
                flush_out();   // darf Note werfen -> caller rearm EPOLLOUT
                if (hasPendingWrite()) return;
            }
            handshakeDone = true;
            return;
        }

        // ------------------------------------------------------------
        // Reset ONLY at fresh start (never mid-handshake!)
        // ------------------------------------------------------------
        if (hs_state == HsState::READ_CLIENT_HELLO && !handshakeStarted) {
            hs_state = HsState::READ_CLIENT_HELLO;
        }

        // ------------------------------------------------------------
        // Local state that must persist across calls:
        // store these as members if you need them later.
        // In your original code chosenSuite is local, so make it member:
        //   uint16_t chosenSuite;
        // and for masterSecret:
        //   std::vector<uint8_t> masterSecret;
        // ------------------------------------------------------------

        // Run as far as possible in one call, until IO would block (Note thrown)
        try {
        for (;;) {
    #if SSL_DEBUG
    #endif

            switch (hs_state) {
            case HsState::READ_CLIENT_HELLO: {
    #if SSL_DEBUG
    #endif

                std::vector<uint8_t> ch = fetchNextHandshakePlain();
                if (ch.empty()) {
    #if SSL_DEBUG
    #endif
                    return;
                }

    #if SSL_DEBUG
    #endif

                if (ch.size() < 4) throwSSL(NetException::Error, "ClientHello too short");
                if (ch[0] != 0x01) throwSSL(NetException::Error, "Expected ClientHello");

                // ✅ CRITICAL: Save raw ClientHello bytes for transcript hash
                clientHelloRawBytes = ch;

                // ✅ NEW: Versuche SNI zu extrahieren und das richtige Zertifikat auszuwählen
                std::string snihostname;
                if (extractSNIFromClientHello(ch, snihostname)) {
                    requested_hostname = snihostname;
                    if (cert_map) {
                        auto it = cert_map->find(snihostname);
                        if (it != cert_map->end()) {
                            selected_cert_bundle = const_cast<CertificateBundle*>(&it->second);
                            SSL_LOG("[SNI] Selected cert for domain: " << snihostname);
                        } else {
                            SSL_LOG("[SNI] No cert found for domain: " << snihostname << ", using default");
                            if (!cert_map->empty()) {
                                selected_cert_bundle = const_cast<CertificateBundle*>(&cert_map->begin()->second);
                                SSL_LOG("[SNI] Switched to default cert");
                            }
                        }
                    }
                } else {
                    SSL_LOG("[SNI] SNI extension not found in ClientHello, using default cert");
                }

                auto readU16 = [&](size_t& p) -> uint16_t {
                    if (p + 2 > ch.size()) throwSSL(NetException::Error, "parse underrun u16");
                    uint16_t x = (uint16_t(ch[p]) << 8) | ch[p+1];
                    p += 2;
                    return x;
                };
                auto readU8 = [&](size_t& p) -> uint8_t {
                    if (p + 1 > ch.size()) throwSSL(NetException::Error, "parse underrun u8");
                    return ch[p++];
                };

                size_t p = 4;

                // legacy_version
                (void)readU16(p);

                // random
                if (p + 32 > ch.size()) throwSSL(NetException::Error, "ClientHello random truncated");
                clientRandom.assign(ch.begin()+p, ch.begin()+p+32);
                p += 32;

                // session id
                uint8_t sidLen = readU8(p);
                if (p + sidLen > ch.size()) throwSSL(NetException::Error, "ClientHello sid truncated");

                client_session_id.assign(ch.begin()+p, ch.begin()+p+sidLen); // <-- WICHTIG
                p += sidLen;

                // cipher suites
                uint16_t csLen = readU16(p);
                if (csLen < 2 || (csLen % 2) != 0) throwSSL(NetException::Error, "bad cipher_suites length");
                if (p + csLen > ch.size()) throwSSL(NetException::Error, "cipher_suites truncated");

                std::vector<uint16_t> clientSuites;
                for (size_t i=0;i<csLen;i+=2) {
                    clientSuites.push_back((uint16_t(ch[p+i])<<8) | ch[p+i+1]);
                }
                p += csLen;

                // compression
                uint8_t compLen = readU8(p);
                if (compLen < 1)
                    throwSSL(NetException::Error, "compression_methods empty");
                if (p + compLen > ch.size())
                    throwSSL(NetException::Error, "compression_methods truncated");

                // must contain 0x00 at least once
                bool hasNull = false;
                for (uint8_t i=0;i<compLen;i++)
                    if (ch[p+i] == 0x00) hasNull = true;
                if (!hasNull)
                    throwSSL(NetException::Error, "no null compression offered");

                p += compLen;


                // defaults
                bool offeredTLS13 = false;
                bool secureReneg  = false;
                client_keyshare_ecdhe.clear();

                // secure reneg SCSV in suites?
                for (auto cs : clientSuites)
                    if (cs == 0x00FF) secureReneg = true;

                // extensions
                if (p == ch.size()) {
                    throwSSL(NetException::Error, "ClientHello has no extensions");
                }
                if (p + 2 > ch.size()) throwSSL(NetException::Error, "extensions length truncated");

                uint16_t extLen = readU16(p);
                if (p + extLen > ch.size()) throwSSL(NetException::Error, "extensions truncated");

                size_t ep = p;
                size_t eend = p + extLen;

                while (ep + 4 <= eend) {
                    uint16_t et = (uint16_t(ch[ep]) << 8) | ch[ep+1];
                    uint16_t el = (uint16_t(ch[ep+2]) << 8) | ch[ep+3];
                    ep += 4;

                    if (ep + el > eend) throwSSL(NetException::Error, "extension truncated");

                    // renegotiation_info
                    if (et == 0xFF01) secureReneg = true;

                    // supported_versions
                    if (et == 0x002b) {
                        if (el < 3) throwSSL(NetException::Error, "supported_versions too short");
                        uint8_t vlen = ch[ep];
                        if (1 + vlen > el) throwSSL(NetException::Error, "supported_versions bad len");
                        if ((vlen % 2) != 0) throwSSL(NetException::Error, "supported_versions odd");

                        size_t vp = ep + 1;
                        size_t vend = vp + vlen;
                        while (vp + 1 < vend) {
                            uint16_t v = (uint16_t(ch[vp]) << 8) | ch[vp+1];
                            if (v == 0x0304) {
                                offeredTLS13 = true; // TLS 1.3
                                break;
                            }
                            vp += 2;
                        }
                    }

                    // key_share (ClientHello list)
                    if (et == 0x0033) {
                        if (el < 2) throwSSL(NetException::Error, "key_share too short");

                        size_t kp = ep;
                        uint16_t listLen = (uint16_t(ch[kp]) << 8) | ch[kp+1];
                        kp += 2;

                        if (2 + listLen != el)
                            throwSSL(NetException::Error, "key_share listLen mismatch");

                        size_t kend = kp + listLen;

                        // reset stored shares
                        client_keyshare_x25519.clear();
                        client_keyshare_ecdhe.clear();

                        while (kp + 4 <= kend) {
                            uint16_t group = (uint16_t(ch[kp]) << 8) | ch[kp+1]; kp += 2;
                            uint16_t klen  = (uint16_t(ch[kp]) << 8) | ch[kp+1]; kp += 2;

                            if (kp + klen > kend)
                                throwSSL(NetException::Error, "key_share entry truncated");

                            if (group == 0x001d && klen == 32) {
                                client_keyshare_x25519.assign(ch.begin()+kp, ch.begin()+kp+klen);
                                TLSDBG("✅ Found client X25519 key_share");
                            }
                            else if (group == 0x0017 && klen == 65 && ch[kp] == 0x04) {
                                client_keyshare_ecdhe.assign(ch.begin()+kp, ch.begin()+kp+klen);
                                TLSDBG("✅ Found client P-256 key_share");
                            }

                            kp += klen;
                        }
                    }

                    // ALPN (Application-Layer Protocol Negotiation)
                    if (et == 0x0010 && el >= 2) {
                        // ALPN extension format:
                        // - 2 bytes: list length
                        // - For each protocol: 1 byte length + protocol string
                        size_t ap = ep;
                        uint16_t alpn_list_len = (uint16_t(ch[ap]) << 8) | ch[ap+1];
                        ap += 2;

                        if (2 + alpn_list_len != el)
                            throwSSL(NetException::Error, "ALPN listLen mismatch");

                        size_t aend = ap + alpn_list_len;
                        selected_alpn.clear();

                        // Collect all client-offered protocols
                        std::vector<std::string> client_protocols;
                        while (ap < aend && ap + 1 <= aend) {
                            uint8_t plen = ch[ap];
                            ap += 1;

                            if (ap + plen > aend)
                                throwSSL(NetException::Error, "ALPN protocol truncated");

                            client_protocols.emplace_back(ch.begin() + ap, ch.begin() + ap + plen);
                            ap += plen;
                        }

                        // Use callback if set, otherwise accept first client protocol
                        if (alpn_select_cb && !client_protocols.empty()) {
                            selected_alpn = alpn_select_cb(client_protocols);
                        } else if (!client_protocols.empty()) {
                            selected_alpn = client_protocols[0];
                        }
                    }


                    ep += el;
                }

                // store flags
                client_offered_tls13 = offeredTLS13;
                secure_reneg = secureReneg;

                auto hasSuite = [&](uint16_t s) {
                    for (auto cs : clientSuites) if (cs == s) return true;
                    return false;
                };

                // ✅ TLS 1.3 cipher suite preference: AES-256 > AES-128
                auto pickTls13Suite = [&]() -> uint16_t {
                    // Server prefers stronger cipher suite first
                    if (hasSuite(0x1302)) {
                        return 0x1302; // ⭐ AES_256_GCM_SHA384 (PREFERRED)
                    }
                    if (hasSuite(0x1301)) {
                        return 0x1301; // Fallback: AES_128_GCM_SHA256
                    }
                    return 0;
                };

                uint16_t tls13Suite = pickTls13Suite();


                // Prefer X25519 if present, else P-256 if present
                if (!client_keyshare_x25519.empty()) {
                    selected_group = 0x001d; // X25519
                } else if (!client_keyshare_ecdhe.empty()) {
                    selected_group = 0x0017; // P-256
                } else {
                    selected_group = 0;
                }

                bool haveKeyShare =
                    (selected_group == 0x001d && !client_keyshare_x25519.empty()) ||
                    (selected_group == 0x0017 && !client_keyshare_ecdhe.empty());

                if (offeredTLS13 && tls13Suite != 0 && haveKeyShare ) {
                    TLSDBG("[DEBUG] Parsed ClientHello: offeredTLS13=" << offeredTLS13 << ", tls13Suite=0x" << std::hex << tls13Suite << ", haveKeyShare=" << haveKeyShare << ", selected_group=0x" << std::hex << selected_group);
                    handshakeStarted = true;
                    is_tls13 = true;
                    chosenSuite = tls13Suite;
                    tls13_cipher = tls13Suite;  // Also set tls13_cipher for key derivation
                    secure_reneg = false;

                    // ✅ Add ClientHello to transcript for TLS 1.3 key derivation
                    handshake_transcript.insert(handshake_transcript.end(), ch.begin(), ch.end());

                    hs_state = HsState::TLS13_SEND_SERVER_HELLO;
                    TLSDBG("TLS1.3 selected suite=" << std::hex << chosenSuite
        << " group=" << selected_group);
                    continue;
                }


                // fallback TLS 1.2
                handshakeStarted = true;
                is_tls13 = false;
                chosenSuite = 0;
                if (hasSuite(0x002F))      chosenSuite = 0x002F;
                else if (hasSuite(0x0035)) chosenSuite = 0x0035;

                if (chosenSuite == 0)
                    throwSSL(NetException::Error, "No supported cipher suite");

                // --- TLS 1.2 Session Resumption Check ---
                // If client sent a non-empty session_id and we have a cache,
                // look it up.  On hit the expensive RSA decrypt is skipped.
                if (session_cache && !client_session_id.empty()) {
                    TlsSessionCacheEntry cached;
                    if (session_cache->lookup(client_session_id, cached)) {
                        // Verify cipher suite matches what client still offers
                        if (hasSuite(cached.cipher_suite)) {
                            chosenSuite = cached.cipher_suite;
                            masterSecret = cached.master_secret;
                            is_resumption = true;
                            hs_state = HsState::SEND_ABBREVIATED_FLIGHT;
                            continue;
                        }
                    }
                }

                hs_state = HsState::SEND_SERVER_FLIGHT;

                if (rx_handshake_buf.size() < 4) {
                    TLSDBG("rx_handshake_buf < 4 (" << rx_handshake_buf.size() << "), need record");
                }

                continue;
            }
            case HsState::CLI_WAIT_SERVER_HELLO:
            {
                std::vector<uint8_t> sh = fetchNextHandshakePlain();
                if (sh.empty()) {
                    NetException e;
                    e[NetException::Note] << "ssl::handshake_after_connect: wait ServerHello";
                    throw e;
                }

                if (sh[0] != 0x02) {
                    NetException e;
                    e[NetException::Error] << "expected ServerHello got type=" << int(sh[0]);
                    throw e;
                }

                const uint8_t* p = sh.data();
                size_t n = sh.size();

                if (n < 4 + 2 + 32 + 1 + 2 + 1 + 2) {
                    NetException e;
                    e[NetException::Error] << "ServerHello too short";
                    throw e;
                }

                size_t off = 4; // skip handshake hdr

                // legacy_version (still 0x0303 in TLS1.3)
                uint16_t legacy_ver = (uint16_t(p[off]) << 8) | p[off+1];
                off += 2;
                (void)legacy_ver;

                // server_random
                serverRandom.assign(p + off, p + off + 32);
                off += 32;

                // session id
                uint8_t sid_len = p[off++];
                if (off + sid_len > n) {
                    NetException e;
                    e[NetException::Error] << "ServerHello SID overflow";
                    throw e;
                }
                off += sid_len;

                // cipher_suite
                chosenSuite = (uint16_t(p[off]) << 8) | p[off+1];
                off += 2;

                // compression
                uint8_t comp = p[off++];
                if (comp != 0x00) {
                    NetException e;
                    e[NetException::Error] << "ServerHello compression != 0";
                    throw e;
                }

                // extensions length
                uint16_t ext_len = (uint16_t(p[off]) << 8) | p[off+1];
                off += 2;

                if (off + ext_len > n) {
                    NetException e;
                    e[NetException::Error] << "ServerHello extensions overflow";
                    throw e;
                }

                bool tls13 = false;
                bool got_key_share = false;

                // parse extensions
                size_t eoff = off;
                size_t eend = off + ext_len;

                while (eoff + 4 <= eend) {
                    uint16_t et = (uint16_t(p[eoff]) << 8) | p[eoff+1];
                    uint16_t el = (uint16_t(p[eoff+2]) << 8) | p[eoff+3];
                    eoff += 4;

                    if (eoff + el > eend) {
                        NetException e;
                        e[NetException::Error] << "ServerHello bad extension length";
                        throw e;
                    }

                    const uint8_t* ep = p + eoff;

                    // supported_versions (ServerHello: selected_version(2))
                    if (et == 0x002b && el == 2) {
                        uint16_t sel = (uint16_t(ep[0]) << 8) | ep[1];
                        if (sel == 0x0304) tls13 = true;
                    }

                    // key_share (ServerHello: group(2)+klen(2)+key)
                    if (et == 0x0033) {
                        if (el < 4) {
                            NetException e;
                            e[NetException::Error] << "ServerHello key_share too short";
                            throw e;
                        }

                        uint16_t group = (uint16_t(ep[0]) << 8) | ep[1];
                        uint16_t klen  = (uint16_t(ep[2]) << 8) | ep[3];

                        if (4 + klen != el) {
                            NetException e;
                            e[NetException::Error] << "ServerHello key_share length mismatch";
                            throw e;
                        }

                        const uint8_t* key = ep + 4;

                        // ---------------------------------------------------------
                        // ✅ X25519 (0x001d)
                        // ---------------------------------------------------------
                        if (group == 0x001d) { // X25519
                            if (klen != 32) {
                                NetException e;
                                e[NetException::Error] << "ServerHello X25519 key_share invalid length=" << klen;
                                throw e;
                            }

                            // store server pub
                            server_keyshare_x25519.assign(key, key + 32);

                            // compute shared secret
                            std::vector<uint8_t> shared32;
                            shared32.resize(32);

                            if (!netplus::scalarmult_curve25519(shared32, client_priv_x25519, server_keyshare_x25519)) {
                                NetException e;
                                e[NetException::Error] << "TLS1.3 X25519 scalarmult failed";
                                throw e;
                            }

                            if (shared32.size() != 32) {
                                NetException e;
                                e[NetException::Error] << "TLS1.3 X25519 shared secret wrong size=" << shared32.size();
                                throw e;
                            }

                            x25519_shared = shared32;
                            got_key_share = true;
                        }

                        // ---------------------------------------------------------
                        // ✅ P-256 (0x0017)
                        // ---------------------------------------------------------
                        else if (group == 0x0017) { // P-256
                            if (klen != 65 || key[0] != 0x04) {
                                NetException e;
                                e[NetException::Error] << "ServerHello P-256 key_share invalid";
                                throw e;
                            }

                            server_keyshare_ecdhe.assign(key, key + klen);

                            netplus::P256Point srv_pub;
                            if (!netplus::decode_tls_point(srv_pub, key, klen)) {
                                NetException e;
                                e[NetException::Error] << "TLS1.3 server key_share invalid point";
                                throw e;
                            }

                            uint8_t shared32_raw[32];
                            if (!netplus::ecdh_shared_secret(shared32_raw, client_priv_ecdhe, srv_pub)) {
                                NetException e;
                                e[NetException::Error] << "TLS1.3 ECDH failed";
                                throw e;
                            }

                            ecdhe_shared.assign(shared32_raw, shared32_raw + 32);
                            got_key_share = true;
                        }

                        else {
                            NetException e;
                            e[NetException::Error] << "TLS1.3 unsupported key_share group=0x" << std::hex << group;
                            throw e;
                        }
                    }

                    eoff += el;
                }

                if (tls13) {
                    if (chosenSuite != 0x1301 && chosenSuite != 0x1302) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 unsupported cipher suite: " << std::hex << chosenSuite;
                        throw e;
                    }

                    if (!got_key_share) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 ServerHello without key_share";
                        throw e;
                    }

                    is_tls13 = true;
                    neg_version = 0x0304;

                    hs_state = HsState::CLI_TLS13_WAIT_ENC_EXT;
                    break;
                }

                // TLS1.2 flow
                is_tls13 = false;
                hs_state = HsState::CLI_WAIT_CERT;
                break;
            }
            // ============================================================
            // SEND_ABBREVIATED_FLIGHT (TLS 1.2 session resumption)
            // Server sends: ServerHello(echoed session_id) + CCS + Finished
            // Skips Certificate / ServerHelloDone / waiting for CKE.
            // ============================================================
            case HsState::SEND_ABBREVIATED_FLIGHT: {
                if (!serverFlightQueued) {
                    // --- Build ServerHello with echoed session_id ---
                    {
                        std::vector<uint8_t> body;
                        body.reserve(128);
                        body.push_back(0x03); body.push_back(0x03); // TLS 1.2
                        serverRandom.resize(32);
                        fillRandomBytes(serverRandom.data(), 32);
                        body.insert(body.end(), serverRandom.begin(), serverRandom.end());
                        // Echo client session_id so client knows resumption succeeded
                        body.push_back(static_cast<uint8_t>(client_session_id.size()));
                        body.insert(body.end(), client_session_id.begin(), client_session_id.end());
                        body.push_back((chosenSuite >> 8) & 0xFF);
                        body.push_back((chosenSuite >> 0) & 0xFF);
                        body.push_back(0x00); // null compression
                        // renegotiation_info
                        if (secure_reneg) {
                            std::vector<uint8_t> exts;
                            exts.push_back(0xFF); exts.push_back(0x01);
                            exts.push_back(0x00); exts.push_back(0x01);
                            exts.push_back(0x00);
                            body.push_back((exts.size() >> 8) & 0xFF);
                            body.push_back((exts.size() >> 0) & 0xFF);
                            body.insert(body.end(), exts.begin(), exts.end());
                        } else {
                            body.push_back(0x00); body.push_back(0x00);
                        }
                        sendHandshake(0x02, body);
                    }

                    // --- Derive keys from cached masterSecret + new randoms ---
                    {
                        std::vector<uint8_t> kbSeed = serverRandom;
                        kbSeed.insert(kbSeed.end(), clientRandom.begin(), clientRandom.end());

                        size_t keyLen = (chosenSuite == 0x0035) ? 32 : 16;
                        size_t kbLen = 20 + 20 + keyLen + keyLen; // 2 MAC keys + 2 write keys
                        std::vector<uint8_t> keyBlock = prf(masterSecret, "key expansion", kbSeed, kbLen);

                        size_t k = 0;
                        client_mac_key.assign(keyBlock.begin() + k, keyBlock.begin() + k + 20); k += 20;
                        mac_key.assign(keyBlock.begin() + k, keyBlock.begin() + k + 20); k += 20;
                        std::vector<uint8_t> clientKey(keyBlock.begin() + k, keyBlock.begin() + k + keyLen); k += keyLen;
                        std::vector<uint8_t> serverKey(keyBlock.begin() + k, keyBlock.begin() + k + keyLen);

                        if (keyLen == 32) {
                            aes_recv = std::make_unique<aes256>(clientKey);
                            aes      = std::make_unique<aes256>(serverKey);
                        } else {
                            aes_recv = std::make_unique<aes128>(clientKey);
                            aes      = std::make_unique<aes128>(serverKey);
                        }
                    }

                    // --- Queue CCS + server Finished ---
                    {
                        static const uint8_t sccs[] = { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01 };
                        queueRaw(sccs, sizeof(sccs));
                        send_seq = 0;

                        std::vector<uint8_t> th = sha256_hash(handshake_transcript);
                        std::vector<uint8_t> verifyServer = prf(masterSecret, "server finished", th, 12);

                        std::vector<uint8_t> sFin;
                        sFin.reserve(16);
                        sFin.push_back(0x14);
                        sFin.push_back(0x00); sFin.push_back(0x00); sFin.push_back(0x0c);
                        sFin.insert(sFin.end(), verifyServer.begin(), verifyServer.end());
                        handshake_transcript.insert(handshake_transcript.end(), sFin.begin(), sFin.end());
                        sendTLS12Record(0x16, sFin);
                    }

                    serverFlightQueued = true;
                }

                // Flush
                try {
                    flush_out();
                } catch (NetException& e) {
                    if (e.getErrorType() == NetException::Note) return;
                    throw;
                }

                if (!hasPendingWrite()) {
                    recv_seq = 0; // reset recv seq for encrypted records from client
                    hs_state = HsState::WAIT_CCS;
                }
                return;
            }

            // ============================================================
            // SEND_SERVER_FLIGHT
            // ============================================================
            case HsState::SEND_SERVER_FLIGHT: {

                if (!serverFlightQueued) {

                    sendServerHello_TLS12(secure_reneg, chosenSuite);

                    // ✅ Always use selected bundle's cert for TLS 1.2 certificate
                    if (!selected_cert_bundle)
                        throwSSL(NetException::Error, "No certificate bundle selected");
                    
                    const auto& rawCert = selected_cert_bundle->cert.derData();
                    uint32_t cLen    = (uint32_t)rawCert.size();
                    // Total certificate_list length: leaf + chain entries
                    // Each entry = cert_len(3) + cert_data
                    uint32_t listLen = cLen + 3;
                    for (const auto& chainCert : selected_cert_bundle->chain) {
                        listLen += 3 + (uint32_t)chainCert.size();
                    }

                    std::vector<uint8_t> certMsg;
                    certMsg.reserve(3 + listLen);

                    certMsg.push_back((listLen >> 16) & 0xFF);
                    certMsg.push_back((listLen >>  8) & 0xFF);
                    certMsg.push_back((listLen >>  0) & 0xFF);

                    // Leaf certificate
                    certMsg.push_back((cLen >> 16) & 0xFF);
                    certMsg.push_back((cLen >>  8) & 0xFF);
                    certMsg.push_back((cLen >>  0) & 0xFF);
                    certMsg.insert(certMsg.end(), rawCert.begin(), rawCert.end());

                    // Chain certificates (intermediate/root CA)
                    for (const auto& chainCert : selected_cert_bundle->chain) {
                        uint32_t ccLen = (uint32_t)chainCert.size();
                        certMsg.push_back((ccLen >> 16) & 0xFF);
                        certMsg.push_back((ccLen >>  8) & 0xFF);
                        certMsg.push_back((ccLen >>  0) & 0xFF);
                        certMsg.insert(certMsg.end(), chainCert.begin(), chainCert.end());
                    }

                    sendHandshake(0x0b, certMsg);
                    sendHandshake(0x0e, {});

                    serverFlightQueued = true;
                }

                try {
                    flush_out();
                } catch(NetException& e) {
                    if (e.getErrorType() == NetException::Note)
                        return;
                    throw;
                }

                if (!hasPendingWrite()) {
                    hs_state = HsState::WAIT_CKE;
                }
                return;
            }

            // ============================================================
            // WAIT_CCS
            // ============================================================
            case HsState::WAIT_CCS: {
    #if SSL_DEBUG
    #endif

                if (ccs_received) {
    #if SSL_DEBUG
    #endif
                    recv_seq = 0;
                    hs_state = HsState::WAIT_FIN;
                    continue; // direkt WAIT_FIN probieren
                }

                std::vector<uint8_t> rec;
                try {
                    rec = readTlsRecordAsync();
                } catch (netplus::NetException& e) {
                    if (e.getErrorType() == netplus::NetException::Note) {
    #if SSL_DEBUG
    #endif
                        return;
                    }
                    TLSDBG("readTlsRecordAsync ERROR");
                    throw;
                }

    #if SSL_DEBUG
    #endif

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

    #if SSL_DEBUG
    #endif

                ccs_received = true;   // bleibt true bis WAIT_FIN erfolgreich war
                recv_seq = 0;
                hs_state = HsState::WAIT_FIN;
                continue;
            }
            // ============================================================
            // WAIT_FIN
            // ============================================================
            case HsState::WAIT_FIN: {
                if (!aes_recv) throwSSL(NetException::Error, "WAIT_FIN but AES not initialized");

                std::vector<uint8_t> finRec;
                try {
                    finRec = readTlsRecordAsync();
                } catch (NetException& e) {
                    if (e.getErrorType() == NetException::Note) return;
                    throw;
                }

                if (finRec.size() < 5 + 16 || finRec[0] != 0x16)
                    throwSSL(NetException::Error, "Expected Finished handshake record");

                uint16_t finVer = ((uint16_t)finRec[1] << 8) | (uint16_t)finRec[2];
                std::vector<uint8_t> finFrag(finRec.begin() + 5, finRec.end());

                std::vector<uint8_t> finPT = decryptRecordCBC(0x16, finVer, finFrag);

                if (finPT.size() < 4 + 12 ||
                    finPT[0] != 0x14 || finPT[1] != 0x00 || finPT[2] != 0x00 || finPT[3] != 0x0c) {
                    throwSSL(NetException::Error, "Bad Finished structure (client)");
                }

                std::vector<uint8_t> th = sha256_hash(handshake_transcript);
                std::vector<uint8_t> expectedClient = prf(masterSecret, "client finished", th, 12);

                if (!std::equal(expectedClient.begin(), expectedClient.end(), finPT.begin() + 4)) {
                    throwSSL(NetException::Error, "client Finished verify_data mismatch");
                }

                // ✅ Add client's Finished handshake message to transcript
                handshake_transcript.insert(handshake_transcript.end(),
                                            finPT.begin(), finPT.begin() + 4 + 12);

                // ✅ Save transcript AFTER adding client Finished (for server Finished PRF)
                tls12_transcript_before_client_finished = handshake_transcript;

                hs_state = HsState::SEND_CCS_FIN;
                continue;  // process SEND_CCS_FIN immediately
            }
            // ============================================================
            // SEND_CCS_FIN
            // ============================================================
            case HsState::SEND_CCS_FIN: {

                // 1) nur einmal queue’n
                if (!serverFinishedQueued) {

                    static const uint8_t sccs[] = { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01 };
                    queueRaw(sccs, sizeof(sccs));

                    send_seq = 0; // ok - begin new crypto epoch after CCS

                    // ✅ Use transcript after receiving all handshake messages (including client Finished) for server Finished PRF
                    std::vector<uint8_t> th = sha256_hash(tls12_transcript_before_client_finished);
                    std::vector<uint8_t> verifyServer = prf(masterSecret, "server finished", th, 12);

                    std::vector<uint8_t> sFin;
                    sFin.reserve(4 + 12);
                    sFin.push_back(0x14);
                    sFin.push_back(0x00); sFin.push_back(0x00); sFin.push_back(0x0c);
                    sFin.insert(sFin.end(), verifyServer.begin(), verifyServer.end());

                    handshake_transcript.insert(handshake_transcript.end(), sFin.begin(), sFin.end());

                    sendTLS12Record( 0x16, sFin);

                    serverFinishedQueued = true;
                }

                // 2) flush so far as possible
                try {
                    flush_out();
                } catch(NetException& e) {
                    if (e.getErrorType() == NetException::Note) {
                        // socket voll -> warten auf EPOLLOUT
                        return;
                    }
                    throw;
                }

                // 3) erst wenn wirklich alles raus ist -> DONE
                if (!hasPendingWrite()) {
                    handshakeDone = true;
                    hs_state = HsState::DONE;

                    // --- Cache the session for future resumption ---
                    if (session_cache && !is_tls13 && !client_session_id.empty()
                        && !masterSecret.empty()) {
                        session_cache->store(client_session_id, masterSecret, chosenSuite);
                    }
                    return;
                }
                return;
            }

            case HsState::WAIT_CKE: {
    #if SSL_DEBUG
    #endif

                // ✅ Always read full handshake message (handles fragmentation)
                std::vector<uint8_t> msg = fetchNextHandshakePlain();
    #if SSL_DEBUG
    #endif

                if (msg.empty()) {
    #if SSL_DEBUG
    #endif
                    return;  // would block
                }

                // msg = [type][len24][body...]
                if (msg.size() < 4)
                    throwSSL(NetException::Error, "ClientKeyExchange too short");

                uint8_t ht = msg[0];
                uint32_t hlen = (uint32_t(msg[1]) << 16) | (uint32_t(msg[2]) << 8) | uint32_t(msg[3]);

                if (ht != 0x10)
                    throwSSL(NetException::Error,
                            "Expected ClientKeyExchange (0x10), got " + std::to_string(ht));

                if (msg.size() != 4 + hlen)
                    throwSSL(NetException::Error, "ClientKeyExchange length mismatch");

                // RSA CKE body: uint16 encLen + ciphertext
                if (hlen < 2)
                    throwSSL(NetException::Error, "ClientKeyExchange body too short");

                size_t off = 4;

                uint16_t encLen = (uint16_t(msg[off]) << 8) | msg[off + 1];
                off += 2;

                if (off + encLen > msg.size())
                    throwSSL(NetException::Error, "ClientKeyExchange truncated ciphertext");

                const size_t kBytes = (selected_cert_bundle->rsa_key.n.bitLength() + 7) / 8;
                if (encLen != kBytes) {
                    throwSSL(NetException::Error,
                        "RSA ciphertext length mismatch encLen=" + std::to_string(encLen) +
                        " kBytes=" + std::to_string(kBytes));
                }

    #if SSL_DEBUG
    #endif

                rsa::bigInt cipher = rsa::bigIntFromBytesBE(msg.data() + off, encLen);
                rsa::bigInt plainBI = selected_cert_bundle->rsa_key.decrypt(cipher);

    #if SSL_DEBUG
    #endif

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

    #if SSL_DEBUG
    #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
    #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
    #endif

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

                std::vector<uint8_t> clientKey(keyBlock.begin() + k, keyBlock.begin() + k + 16); k += 16;
                std::vector<uint8_t> serverKey(keyBlock.begin() + k, keyBlock.begin() + k + 16);

                aes_recv = std::make_unique<aes128>(clientKey);
                aes      = std::make_unique<aes128>(serverKey);


                hs_state = HsState::WAIT_CCS;
                return;
            }

            case HsState::TLS13_WAIT_CLIENT_FINISHED: {

                // ⚠️ Save transcript hash BEFORE fetching client Finished
                // The client computes its Finished over CH..server_Finished (not including client Finished)
                // RFC 8446: Use cipher suite's hash function
                std::vector<uint8_t> th_before_client_finished;
                size_t hash_len;
                if (chosenSuite == 0x1302) {
                    th_before_client_finished = sha384_hash(handshake_transcript);
                    hash_len = 48;
                } else {
                    th_before_client_finished = sha256_hash(handshake_transcript);
                    hash_len = 32;
                }

                // ✅ 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;
                    n[NetException::Note] << "TLS1.3: waiting for client Finished";
                    throw n;
                }

                // msg enthält Handshake Msg (type+len24+body)
                if (msg.size() < 4)
                    throwSSL(NetException::Error, "TLS1.3 client Finished too short");

                uint8_t ht = msg[0];
                uint32_t len = (uint32_t(msg[1]) << 16) | (uint32_t(msg[2]) << 8) | uint32_t(msg[3]);

                if (ht != 0x14)
                    throwSSL(NetException::Error, "TLS1.3 expected Finished from client");

                if (len != hash_len || msg.size() != 4 + hash_len)
                    throwSSL(NetException::Error, "TLS1.3 Finished verify_data wrong size");

                std::vector<uint8_t> client_verify(msg.begin() + 4, msg.end());

                // finished_key = HKDF-Expand-Label(c_hs_secret, "finished", "", hash_len)
                std::vector<uint8_t> finished_key = hkdf_expand_label(
                    tls13_c_hs_secret,
                    "finished",
                    std::vector<uint8_t>{},
                    hash_len,
                    chosenSuite
                );
                if (finished_key.size() != hash_len)
                    throwSSL(NetException::Error, "TLS1.3 Finished: finished_key wrong size");

                std::vector<uint8_t> expected;
                if (chosenSuite == 0x1302) {
                    expected = hmac_sha384(finished_key, th_before_client_finished);
                } else {
                    expected = hmac_sha256(finished_key, th_before_client_finished);
                }
                if (expected.size() != hash_len)
                    throwSSL(NetException::Error, "TLS1.3 Finished: expected verify_data wrong size");

                if (expected != client_verify)
                    throwSSL(NetException::Error, "TLS1.3 Finished verify_data mismatch");

                // ✅ 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(uint8_t(hash_len));  // length = hash_len (32 or 48)
                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");

                // ⚠️ Do NOT call tls13_derive_application_keys() here!
                // App keys were already derived correctly in TLS13_SEND_ENCRYPTED_FLIGHT
                // after server Finished was added to transcript (but before client Finished).
                // Calling it again here would use wrong transcript (includes client Finished).

                handshakeDone = true;
                hs_state = HsState::ESTABLISHED;
                return;
            }

            case HsState::TLS13_SEND_ENCRYPTED_FLIGHT: {
                
                if (!tls13_encflight_queued) {

                    if (!aes13_hs_send || !aes13_hs_recv)
                        throwSSL(NetException::Error, "TLS1.3 missing handshake keys");

                    // 1) EncryptedExtensions - build with ALPN if negotiated
                    std::vector<uint8_t> ee;
                    
                    if (!selected_alpn.empty()) {
                        // Build ALPN extension (type 0x0010) per RFC 7301
                        std::vector<uint8_t> alpn_ext;
                        
                        // Protocol name list entry: 1-byte length + protocol string
                        uint16_t protocol_name_entry_len = 1 + selected_alpn.size();
                        
                        // Protocol name list: 2-byte length field + entries
                        uint16_t protocol_name_list_len = protocol_name_entry_len;
                        
                        // Extension data = protocol_name_list (2-byte len + entries)
                        uint16_t alpn_ext_data_len = 2 + protocol_name_list_len;
                        
                        // Extension type: 0x0010 (ALPN)
                        alpn_ext.push_back(0x00);
                        alpn_ext.push_back(0x10);
                        
                        // Extension data length
                        alpn_ext.push_back((uint8_t)(alpn_ext_data_len >> 8));
                        alpn_ext.push_back((uint8_t)(alpn_ext_data_len & 0xFF));
                        
                        // Protocol name list length (2 bytes)
                        alpn_ext.push_back((uint8_t)(protocol_name_list_len >> 8));
                        alpn_ext.push_back((uint8_t)(protocol_name_list_len & 0xFF));
                        
                        // Protocol name: length (1 byte) + string
                        alpn_ext.push_back((uint8_t)selected_alpn.size());
                        alpn_ext.insert(alpn_ext.end(), selected_alpn.begin(), selected_alpn.end());
                        
                        // EncryptedExtensions body: extensions_length (2 bytes) + extensions
                        uint16_t extensions_len = alpn_ext.size();
                        ee.push_back((uint8_t)(extensions_len >> 8));
                        ee.push_back((uint8_t)(extensions_len & 0xFF));
                        ee.insert(ee.end(), alpn_ext.begin(), alpn_ext.end());
                        
                    } else {
                        // Empty extensions if no ALPN negotiated
                        ee = {0x00, 0x00};
                    }
                    
                    tls13_send_handshake(0x08, ee, true);

                    // 2) Certificate
                    std::vector<uint8_t> cert = tls13_build_certificate();
                    tls13_send_handshake(0x0b, cert, true);

                    // 3) CertificateVerify
                    std::vector<uint8_t> cv = tls13_build_certificate_verify();
                    tls13_send_handshake(0x0f, cv, true);

                    // 4) Finished
                    // verify_data is the BODY (32 bytes), handshake header is added by send_handshake
                    std::vector<uint8_t> verify_data = tls13_build_server_finished();
                    tls13_send_handshake(0x14, verify_data, true);

                    // 5) Derive application keys AFTER transcript contains server Finished
                    tls13_derive_application_keys();

                    tls13_encflight_queued = true;
                }

                try {
                    flush_out();
                } catch(NetException& e) {
                    if (e.getErrorType() == NetException::Note)
                        return;
                    throw;
                }

                
                if (!hasPendingWrite()) {
                    hs_state = HsState::TLS13_WAIT_CLIENT_FINISHED;
                }

                return;
            }

            case HsState::FAIL:{
                NetException e;
                e[NetException::Error] << "Handshake Failed";
                throw e;
            }

            case HsState::DONE:

            case HsState::ESTABLISHED:
                handshakeDone = true;
            return;

             case HsState::TLS13_SEND_SERVER_HELLO: {

                // Reset per-handshake shared secrets
                x25519_shared.clear();
                ecdhe_shared.clear();


                bool use_x25519 = (client_keyshare_x25519.size() == 32);
                bool use_p256   = (client_keyshare_ecdhe.size() == 65);


                if (!use_x25519 && !use_p256)
                    throwSSL(NetException::Error, "TLS1.3 missing supported client key_share");

                selected_group = use_x25519 ? 0x001d : 0x0017;

                std::vector<uint8_t> server_pub;

                if (selected_group == 0x001d) {
                    // ------------------- X25519 -------------------
                    std::vector<uint8_t> shared32;

                    server_priv_x25519.resize(32);
                    fillRandom(server_priv_x25519);

                    if (!netplus::scalarmult_curve25519_base(server_pub_x25519, server_priv_x25519))
                        throwSSL(NetException::Error, "TLS1.3 X25519 base scalar mult failed");

                    if (!netplus::scalarmult_curve25519(shared32, server_priv_x25519, client_keyshare_x25519))
                        throwSSL(NetException::Error, "TLS1.3 X25519 shared secret failed");

                    server_pub = server_pub_x25519;
                    x25519_shared = shared32;
                } else {
                    // ------------------- P-256 -------------------
                    std::vector<uint8_t> shared32(32);   // ✅ IMPORTANT FIX

                    netplus::P256Point cli_pub;
                    if (!netplus::decode_tls_point(cli_pub, client_keyshare_ecdhe.data(), 65))
                        throwSSL(NetException::Error, "TLS1.3 client key_share invalid point");

                    if (!is_on_curve(cli_pub))
                        throwSSL(NetException::Error, "TLS1.3 key_share point not on curve");

                    gen_tls13_p256_scalar(server_priv_ecdhe);

                    netplus::P256Point srv_pub = netplus::scalar_mul_G(server_priv_ecdhe);
                    server_keyshare_ecdhe = netplus::encode_tls_point(srv_pub);

                    if (server_keyshare_ecdhe.size() != 65 || server_keyshare_ecdhe[0] != 0x04)
                        throwSSL(NetException::Error, "TLS1.3 server keyshare invalid");

                    if (!netplus::ecdh_shared_secret(shared32.data(), server_priv_ecdhe, cli_pub))
                        throwSSL(NetException::Error, "TLS1.3 ECDH failed");

                    server_pub = server_keyshare_ecdhe;
                    ecdhe_shared = shared32;
                }

                tls13_got_key_share = true;

                serverRandom.resize(32);
                fillRandomBytes(serverRandom.data(), 32);

                std::vector<uint8_t> hs = buildServerHello_TLS13(
                    chosenSuite,
                    client_session_id,
                    selected_group,
                    server_pub
                );

                // transcript includes plaintext SH
                handshake_transcript.insert(handshake_transcript.end(), hs.begin(), hs.end());

                // ✅ choose correct shared secret by group, not by "empty"
                
                if (selected_group == 0x001d)
                    tls13_derive_handshake_keys(x25519_shared);
                else
                    tls13_derive_handshake_keys(ecdhe_shared);


                // send plaintext ServerHello record
                std::vector<uint8_t> rec;
                rec.reserve(5 + hs.size());
                rec.push_back(0x16);
                rec.push_back(0x03);
                rec.push_back(0x03);
                rec.push_back(uint8_t(hs.size() >> 8));
                rec.push_back(uint8_t(hs.size() & 0xFF));
                rec.insert(rec.end(), hs.begin(), hs.end());

                queueRaw(rec);
                
                // TLS 1.3 middlebox compatibility: send Change Cipher Spec (CCS)
                // RFC 8446 Section 5: For middlebox compatibility, send CCS after ServerHello
                static const uint8_t ccs[] = { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01 };
                std::vector<uint8_t> ccs_rec(ccs, ccs + sizeof(ccs));
                queueRaw(ccs_rec);
                
                try {
                    flush_out();
                } catch (NetException& e) {
                    if (e.getErrorType() == NetException::Note) {
                        // IOCP: write would block, wait for completion
                        hs_state = HsState::TLS13_SEND_ENCRYPTED_FLIGHT;
                        return;
                    }
                    throw;
                }

                hs_state = HsState::TLS13_SEND_ENCRYPTED_FLIGHT;
                
                // On IOCP, if write is pending, wait for completion before continuing
                if (hasPendingWrite()) {
                    return;
                }
                continue;
            }

            default:
                    throwSSL(netplus::NetException::Error, "invalid handshake state");
                }
            }
        } catch (NetException& e) {
            if (e.getErrorType() == NetException::Note) {
                throw; // re-throw Note (wait for IO)
            }
            throw;
        } catch (std::exception& e) {
            throw;
        } catch (...) {
            throw;
        }

    }

    void tls::handshake_after_connect(){
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        auto note = [&](const std::string& msg){
            NetException n;
            n[NetException::Note] << msg;
            throw n;
        };

        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::handshake_after_connect: " << msg;
            throw e;
        };

        // always flush pending output first
        if (hasPendingWrite()) {
            flush_out(); // may throw Note
        }

        if (handshakeDone)
            return;

        for (;;) {

            switch (hs_state)
            {
                // ---------------------------
                // 1) flush ClientHello
                // ---------------------------
                case HsState::CLI_FLUSH_CH:
                {
                    if (hasPendingWrite()) {
                        flush_out(); // may throw Note
                        return;
                    }
                    hs_state = HsState::CLI_WAIT_SERVER_HELLO;
                    break;
                }

                // ---------------------------
                // 2) wait ServerHello
                // ---------------------------
                case HsState::CLI_WAIT_SERVER_HELLO:
                {
                    // ---------------------------
                    // Parse ServerHello (TLS 1.2 or TLS 1.3)
                    // ---------------------------
                    // sh is full handshake message including header:
                    // [0]=type(0x02) [1..3]=len24 [4..]=body
                    std::vector<uint8_t> sh;
                    sh = fetchNextHandshakePlain();

                    // Handle would-block: fetchNextHandshakePlain returns empty if no data ready
                    if (sh.empty()) {
                        note("ssl::handshake_after_connect: wait ServerHello");
                    }

                    const uint8_t* p = sh.data();
                    size_t n = sh.size();

                    if (n < 4 + 2 + 32 + 1 + 2 + 1) {
                        NetException e;
                        e[NetException::Error] << "ServerHello too short";
                        throw e;
                    }

                    size_t off = 4; // skip handshake header

                    // legacy_version (2 bytes: 0x03, 0x03)
                    off += 2;

                    // server_random (32)
                    serverRandom.assign(p + off, p + off + 32);
                    off += 32;

                    // session id
                    uint8_t sid_len = p[off++];
                    if (off + sid_len > n) {
                        NetException e;
                        e[NetException::Error] << "ServerHello SID overflow";
                        throw e;
                    }
                    // Save server's echoed session_id for resumption check
                    std::vector<uint8_t> server_sid(p + off, p + off + sid_len);
                    off += sid_len;

                    // cipher_suite (2)
                    if (off + 2 > n) {
                        NetException e;
                        e[NetException::Error] << "ServerHello missing cipher_suite";
                        throw e;
                    }
                    chosenSuite = (uint16_t(p[off]) << 8) | p[off+1];
                    off += 2;

                    // compression method (1) - must be 0
                    if (off + 1 > n) {
                        NetException e;
                        e[NetException::Error] << "ServerHello missing compression";
                        throw e;
                    }
                    uint8_t comp = p[off++];
                    (void)comp;

                    // extensions length (2)
                    if (off + 2 > n) {
                        NetException e;
                        e[NetException::Error] << "ServerHello missing extensions";
                        throw e;
                    }
                    uint16_t ext_len = (uint16_t(p[off]) << 8) | p[off+1];
                    off += 2;

                    if (off + ext_len > n) {
                        NetException e;
                        e[NetException::Error] << "ServerHello extensions overflow";
                        throw e;
                    }

                    bool tls13 = false;

                    std::vector<uint8_t> ecdhe_shared; // 32 bytes BE
                    ecdhe_shared.reserve(32);

                    // parse extensions
                    size_t eoff = off;
                    size_t eend = off + ext_len;

                    while (eoff + 4 <= eend) {
                        uint16_t et = (uint16_t(p[eoff]) << 8) | p[eoff+1];
                        uint16_t el = (uint16_t(p[eoff+2]) << 8) | p[eoff+3];
                        eoff += 4;
                        if (eoff + el > eend) {
                            NetException e;
                            e[NetException::Error] << "ServerHello bad extension length";
                            throw e;
                        }

                        const uint8_t* ep = p + eoff;

                        // supported_versions (0x002b): for ServerHello it's 2 bytes selected version
                        if (et == 0x002b && el == 2) {
                            uint16_t sel = (uint16_t(ep[0]) << 8) | ep[1];
                            if (sel == 0x0304) {
                                tls13 = true;
                            }
                        }

                        // key_share (0x0033): group(2) + keylen(2) + key
                        // key_share (RFC 8446) - ClientHello format (list of shares)
                        if (et == 0x0033) {
                            const uint8_t* kp2 = ep;
                            const uint8_t* end2 = ep + el;

                            if (kp2 + 4 > end2)
                                throwSSL(NetException::Error, "ServerHello key_share too short");

                            uint16_t group = (uint16_t(kp2[0]) << 8) | kp2[1];
                            kp2 += 2;

                            uint16_t klen  = (uint16_t(kp2[0]) << 8) | kp2[1];
                            kp2 += 2;

                            if (kp2 + klen > end2)
                                throwSSL(NetException::Error, "ServerHello key_share truncated");

                        if (group == 0x001d) {
                            // ---------------- X25519 ----------------
                            if (klen != 32)
                                throwSSL(NetException::Error, "ServerHello X25519 key_share invalid length");

                            // kp2 points to server's X25519 public key (32 bytes)
                            std::vector<uint8_t> srv_pub(kp2, kp2 + 32);

                            // Compute shared secret = X25519(client_priv, server_pub)
                            std::vector<uint8_t> shared32;
                            shared32.resize(32);

                            if (client_priv_x25519.size() != 32)
                                throwSSL(NetException::Error, "TLS1.3 X25519 client_priv wrong size");

                            if (!netplus::scalarmult_curve25519(shared32, client_priv_x25519, srv_pub))
                                throwSSL(NetException::Error, "TLS1.3 X25519 scalarmult failed");

                            if (shared32.size() != 32)
                                throwSSL(NetException::Error, "TLS1.3 X25519 shared secret wrong size");

                            ecdhe_shared = shared32;

                            tls13_got_key_share = true;
                            x25519_shared = ecdhe_shared;
                        }
                        else if (group == 0x0017) {
                            // ---------------- P-256 ----------------
                            if (klen != 65 || kp2[0] != 0x04)
                                throwSSL(NetException::Error, "ServerHello P-256 key_share invalid");

                            netplus::P256Point srv_pub;
                            if (!netplus::decode_tls_point(srv_pub, kp2, klen))
                                throwSSL(NetException::Error, "TLS1.3 key_share invalid point");

                            uint8_t shared32_raw[32];
                            if (!netplus::ecdh_shared_secret(shared32_raw, client_priv_ecdhe, srv_pub))
                                throwSSL(NetException::Error, "TLS1.3 ECDH failed");

                            // store shared secret
                            ecdhe_shared.assign(shared32_raw, shared32_raw + 32);

                            tls13_got_key_share = true;
                            ecdhe_shared = ecdhe_shared;
                        }
                        else {
                            throwSSL(NetException::Error, "ServerHello unsupported key_share group");
                        }

                        }

                        eoff += el;
                    }

                    // NOTE: ServerHello was already added to transcript by fetchNextHandshakePlain()
                    // Do NOT add it again here!

                    if (tls13) {
                        if (!client_offered_tls13 || !tls13_got_key_share){
                            NetException e;
                            e[NetException::Error] << "Server selected TLS1.3 but no key_share";
                            throw e;
                        }

                        is_tls13 = true;
                        neg_version = 0x0304;
                        tls13_cipher = chosenSuite;

                        // Only accept TLS_AES_128_GCM_SHA256 and TLS_AES_256_GCM_SHA384
                        if (chosenSuite != 0x1301 && chosenSuite != 0x1302) {
                            NetException e;
                            e[NetException::Error] << "TLS1.3 unsupported cipher suite: " << std::hex << chosenSuite;
                            throw e;
                        }

                        // Add ServerHello to transcript before deriving keys
                        // (fetchNextHandshakePlain does NOT add to transcript)
                        handshake_transcript.insert(handshake_transcript.end(),
                                                    sh.begin(), sh.end());

                        // Derive TLS1.3 handshake keys from ECDHE shared
                        tls13_derive_handshake_keys(ecdhe_shared);

                        // switch to TLS 1.3 handshake path
                        hs_state = HsState::CLI_TLS13_WAIT_ENC_EXT;
                        break;
                    }

                    // else: TLS 1.2 flow continues

                    // --- Client-side session resumption check ---
                    // If we attempted resumption and server echoed our session_id,
                    // derive keys from cached master_secret and skip cert/CKE.
                    if (attempt_resumption && !resumption_session_id.empty()
                        && server_sid == resumption_session_id
                        && !resumption_master_secret.empty()) {
                        masterSecret = resumption_master_secret;
                        is_resumption = true;

                        // Add ServerHello to transcript for Finished verification
                        handshake_transcript.insert(handshake_transcript.end(),
                                                    sh.begin(), sh.end());

                        // Derive key_block from cached masterSecret + new randoms
                        std::vector<uint8_t> kbSeed = serverRandom;
                        kbSeed.insert(kbSeed.end(), clientRandom.begin(), clientRandom.end());

                        size_t keyLen = (chosenSuite == 0x0035) ? 32 : 16;
                        size_t kbLen = 20 + 20 + keyLen + keyLen;
                        std::vector<uint8_t> keyBlock = prf(masterSecret, "key expansion", kbSeed, kbLen);

                        size_t k = 0;
                        client_mac_key.assign(keyBlock.begin() + k, keyBlock.begin() + k + 20); k += 20;
                        mac_key.assign(keyBlock.begin() + k, keyBlock.begin() + k + 20); k += 20;
                        std::vector<uint8_t> clientKey(keyBlock.begin() + k, keyBlock.begin() + k + keyLen); k += keyLen;
                        std::vector<uint8_t> serverKey(keyBlock.begin() + k, keyBlock.begin() + k + keyLen);

                        if (keyLen == 32) {
                            aes      = std::make_unique<aes256>(clientKey);
                            aes_recv = std::make_unique<aes256>(serverKey);
                        } else {
                            aes      = std::make_unique<aes128>(clientKey);
                            aes_recv = std::make_unique<aes128>(serverKey);
                        }

                        // Wait for server CCS + Finished (abbreviated flow)
                        hs_state = HsState::CLI_WAIT_SCCS;
                        break;
                    }

                    // Save server's session_id for future resumption
                    client_session_id = server_sid;

                    hs_state = HsState::CLI_WAIT_CERT;
                    break;
                }

                // ---------------------------
                // TLS 1.3: wait EncryptedExtensions (type 0x08)
                // ---------------------------
                case HsState::CLI_TLS13_WAIT_ENC_EXT:
                {
                    // if buffer empty, read and decrypt next record
                    if (rx_handshake_buf.empty() || rx_handshake_off >= rx_handshake_buf.size()) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                    }

                    std::vector<uint8_t> msg;
                    if (!tls13_pop_hs_from_buf(msg)) {
                        // need more
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                        if (!tls13_pop_hs_from_buf(msg))
                            note("ssl::handshake_after_connect: wait EncryptedExtensions");
                    }

                    if (msg.size() < 4 || msg[0] != 0x08) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 expected EncryptedExtensions got " << int(msg.empty()? -1 : msg[0]);
                        throw e;
                    }

                    // Add to transcript
                    handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());

                    hs_state = HsState::CLI_TLS13_WAIT_CERT;
                    break;
                }
                // ---------------------------
                // TLS 1.3: wait Certificate (type 0x0b)
                // ---------------------------
                case HsState::CLI_TLS13_WAIT_CERT:
                {
                    if (rx_handshake_buf.empty() || rx_handshake_off >= rx_handshake_buf.size()) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                    }

                    std::vector<uint8_t> msg;
                    if (!tls13_pop_hs_from_buf(msg)) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                        if (!tls13_pop_hs_from_buf(msg))
                            note("ssl::handshake_after_connect: wait TLS1.3 Certificate");
                    }

                    if (msg.size() < 4 || msg[0] != 0x0b) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 expected Certificate got " << int(msg.empty()? -1 : msg[0]);
                        throw e;
                    }

                    // Add to transcript
                    handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());

                    // TODO: parse TLS1.3 cert chain message format:
                    // msg body begins at msg[4]
                    // We'll reuse your existing cert parsing logic but format differs slightly.
                    // For now, just store raw or parse later.

                    hs_state = HsState::CLI_TLS13_WAIT_CERT_VERIFY;
                    break;
                }

                // ---------------------------
                // TLS 1.3: wait CertificateVerify (type 0x0f)
                // ---------------------------
                case HsState::CLI_TLS13_WAIT_CERT_VERIFY:
                {
                    if (rx_handshake_buf.empty() || rx_handshake_off >= rx_handshake_buf.size()) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                    }

                    std::vector<uint8_t> msg;
                    if (!tls13_pop_hs_from_buf(msg)) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                        if (!tls13_pop_hs_from_buf(msg))
                            note("ssl::handshake_after_connect: wait TLS1.3 CertificateVerify");
                    }

                    if (msg.size() < 4 || msg[0] != 0x0f) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 expected CertificateVerify got " << int(msg.empty()? -1 : msg[0]);
                        throw e;
                    }

                    // Add to transcript
                    handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());

                    // TODO: verify RSA-PSS signature over transcript
                    // For now, skip verification

                    hs_state = HsState::CLI_TLS13_WAIT_FINISHED;
                    break;
                }

                // ---------------------------
                // TLS 1.3: wait server Finished (type 0x14)
                // ---------------------------
                case HsState::CLI_TLS13_WAIT_FINISHED:
                {
                    if (rx_handshake_buf.empty() || rx_handshake_off >= rx_handshake_buf.size()) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                    }

                    std::vector<uint8_t> msg;
                    if (!tls13_pop_hs_from_buf(msg)) {
                        rx_handshake_buf = tls13_read_record_handshake();
                        rx_handshake_off = 0;
                        if (!tls13_pop_hs_from_buf(msg))
                            note("ssl::handshake_after_connect: wait TLS1.3 server Finished");
                    }

                    if (msg.size() < 4 || msg[0] != 0x14) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 expected server Finished got " << int(msg.empty()? -1 : msg[0]);
                        throw e;
                    }

                    // Determine hash length based on cipher suite
                    size_t hash_len = (chosenSuite == 0x1302) ? 48 : 32;

                    // Verify server Finished verify_data
                    if (msg.size() != 4 + hash_len)
                        throwSSL(NetException::Error, "TLS1.3 server Finished wrong size");

                    std::vector<uint8_t> server_verify(msg.begin() + 4, msg.end());

                    // finished_key = HKDF-Expand-Label(s_hs_secret, "finished", "", hash_len)
                    std::vector<uint8_t> finished_key = hkdf_expand_label(
                        tls13_s_hs_secret, "finished", std::vector<uint8_t>{}, hash_len, chosenSuite);

                    // Transcript hash BEFORE server Finished
                    std::vector<uint8_t> th_before_sfin;
                    if (chosenSuite == 0x1302) {
                        th_before_sfin = sha384_hash(handshake_transcript);
                    } else {
                        th_before_sfin = sha256_hash(handshake_transcript);
                    }

                    std::vector<uint8_t> expected;
                    if (chosenSuite == 0x1302) {
                        expected = hmac_sha384(finished_key, th_before_sfin);
                    } else {
                        expected = hmac_sha256(finished_key, th_before_sfin);
                    }

                    if (expected != server_verify)
                        throwSSL(NetException::Error, "TLS1.3 server Finished verify_data mismatch");

                    // transcript add server Finished
                    handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());

                    // Derive application keys using transcript AFTER server Finished
                    tls13_derive_application_keys();

                    hs_state = HsState::CLI_TLS13_SEND_FINISHED;
                    break;
                }

                // ---------------------------
                // TLS 1.3: send client Finished
                // ---------------------------
                case HsState::CLI_TLS13_SEND_FINISHED:
                {
                    // Determine hash length based on cipher suite
                    size_t cli_hash_len = (chosenSuite == 0x1302) ? 48 : 32;

                    // Build client Finished verify_data
                    std::vector<uint8_t> cli_th;
                    if (chosenSuite == 0x1302) {
                        cli_th = sha384_hash(handshake_transcript);
                    } else {
                        cli_th = sha256_hash(handshake_transcript);
                    }

                    std::vector<uint8_t> cli_finished_key = hkdf_expand_label(
                        tls13_c_hs_secret, "finished", std::vector<uint8_t>{}, cli_hash_len, chosenSuite);

                    std::vector<uint8_t> cli_verify_data;
                    if (chosenSuite == 0x1302) {
                        cli_verify_data = hmac_sha384(cli_finished_key, cli_th);
                    } else {
                        cli_verify_data = hmac_sha256(cli_finished_key, cli_th);
                    }

                    // Build Finished handshake message (type 0x14)
                    std::vector<uint8_t> fin_msg;
                    fin_msg.push_back(0x14);
                    fin_msg.push_back(0x00);
                    fin_msg.push_back(0x00);
                    fin_msg.push_back(uint8_t(cli_hash_len)); // length
                    fin_msg.insert(fin_msg.end(), cli_verify_data.begin(), cli_verify_data.end());

                    // Add to transcript before sending
                    handshake_transcript.insert(handshake_transcript.end(), fin_msg.begin(), fin_msg.end());

                    // Send encrypted with handshake keys
                    tls13_send_record(0x16, fin_msg, /*handshake_keys=*/true);

                    try {
                        flush_out();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            return;
                        throw;
                    }

                    handshakeDone = true;
                    hs_state = HsState::DONE;
                    return;
                }

                // ---------------------------
                // 3) wait Certificate
                // ---------------------------
                case HsState::CLI_WAIT_CERT:
                {
                    std::vector<uint8_t> certMsg;
                    try {
                        certMsg = fetchNextHandshakePlain();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            note("ssl::handshake_after_connect: wait Certificate");
                        throw;
                    }

                    if (certMsg.empty())
                        note("ssl::handshake_after_connect: wait Certificate");

                    if (certMsg[0] != 0x0b) {
                        NetException e;
                        e[NetException::Error] << "expected Certificate got type=" << int(certMsg[0]);
                        throw e;
                    }

                    // Parse Certificate message:
                    // [0] = type (0x0b)
                    // [1..3] = length24 of entire body
                    // [4..6] = certificates_list_length (3 bytes)
                    // Then for each certificate:
                    //   [3 bytes] = certificate_length
                    //   [cert_len bytes] = DER certificate
                    if (certMsg.size() < 7) {
                        NetException e;
                        e[NetException::Error] << "Certificate message too short";
                        throw e;
                    }

                    size_t off = 4; // skip handshake header
                    uint32_t listLen = (uint32_t(certMsg[off]) << 16) | (uint32_t(certMsg[off+1]) << 8) | uint32_t(certMsg[off+2]);
                    off += 3;

                    if (off + listLen > certMsg.size()) {
                        NetException e;
                        e[NetException::Error] << "Certificate list truncated";
                        throw e;
                    }

                    // Parse first certificate (server's leaf cert)
                    if (listLen >= 3) {
                        uint32_t certLen = (uint32_t(certMsg[off]) << 16) | (uint32_t(certMsg[off+1]) << 8) | uint32_t(certMsg[off+2]);
                        off += 3;

                        if (off + certLen <= certMsg.size()) {
                            std::vector<uint8_t> derCert(certMsg.begin() + off, certMsg.begin() + off + certLen);

                            // Extract RSA public key from server certificate
                            netplus::x509cert serverCert;
                            serverCert.loadFromBuffer(derCert);
                            if (!serverCert.extractPublicKey(peer_rsa)) {
                                NetException e;
                                e[NetException::Error] << "Failed to extract RSA public key from server certificate";
                                throw e;
                            }
                        }
                    }

                    hs_state = HsState::CLI_WAIT_SHD;
                    break;
                }

                // ---------------------------
                // 4) wait ServerHelloDone
                // ---------------------------
                case HsState::CLI_WAIT_SHD:
                {
                    std::vector<uint8_t> msg;
                    try {
                        msg = fetchNextHandshakePlain();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            note("ssl::handshake_after_connect: wait SHD");
                        throw;
                    }

                    if (msg.empty())
                        note("ssl::handshake_after_connect: wait SHD");

                    if (msg[0] != 0x0e) {
                        NetException e;
                        e[NetException::Error] << "expected ServerHelloDone got type=" << int(msg[0]);
                        throw e;
                    }

                    hs_state = HsState::CLI_SEND_CKE;
                    break;
                }

                // ---------------------------
                // 5) send ClientKeyExchange + derive keys
                // ---------------------------
                case HsState::CLI_SEND_CKE:
                {
                    if (!cli_cke_sent) {
                        // 1) Build PreMasterSecret: version(2) + random(46) = 48 bytes
                        std::vector<uint8_t> preMaster(48);
                        preMaster[0] = 0x03;
                        preMaster[1] = 0x03; // TLS 1.2
                        fillRandomBytes(preMaster.data() + 2, 46);

                        // 2) PKCS#1 v1.5 encrypt: 0x00 0x02 <non-zero padding> 0x00 <data>
                        const size_t kBytes = (peer_rsa.n.bitLength() + 7) / 8;
                        if (kBytes < 11 + 48)
                            throwSSL(NetException::Error, "Server RSA key too small");

                        std::vector<uint8_t> emBlock(kBytes, 0);
                        emBlock[0] = 0x00;
                        emBlock[1] = 0x02;
                        size_t padLen = kBytes - 3 - 48;
                        // Fill padding with non-zero random bytes
                        fillRandomBytes(emBlock.data() + 2, padLen);
                        for (size_t i = 0; i < padLen; ++i) {
                            while (emBlock[2 + i] == 0x00)
                                fillRandomBytes(&emBlock[2 + i], 1);
                        }
                        emBlock[2 + padLen] = 0x00; // separator
                        std::memcpy(emBlock.data() + 2 + padLen + 1, preMaster.data(), 48);

                        // 3) RSA encrypt
                        rsa::bigInt plainBI = rsa::bigIntFromBytesBE(emBlock.data(), kBytes);
                        rsa::bigInt cipherBI = peer_rsa.encrypt(plainBI);
                        std::vector<uint8_t> ciphertext = rsa::bigIntToBytesBE(cipherBI, kBytes);

                        // 4) Build CKE body: uint16 encLen + ciphertext
                        std::vector<uint8_t> ckeBody;
                        ckeBody.reserve(2 + ciphertext.size());
                        ckeBody.push_back(uint8_t(ciphertext.size() >> 8));
                        ckeBody.push_back(uint8_t(ciphertext.size() & 0xFF));
                        ckeBody.insert(ckeBody.end(), ciphertext.begin(), ciphertext.end());

                        // 5) Send ClientKeyExchange handshake (adds to transcript)
                        sendHandshake(0x10, ckeBody);

                        // 6) Derive master_secret
                        std::vector<uint8_t> msSeed = clientRandom;
                        msSeed.insert(msSeed.end(), serverRandom.begin(), serverRandom.end());
                        masterSecret = prf(preMaster, "master secret", msSeed, 48);

                        // 7) Derive key_block: client_mac(20) + server_mac(20) + client_key(16) + server_key(16) = 72
                        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);

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

                        std::vector<uint8_t> clientKey(keyBlock.begin() + k, keyBlock.begin() + k + 16); k += 16;
                        std::vector<uint8_t> serverKey(keyBlock.begin() + k, keyBlock.begin() + k + 16);

                        // Client sends with clientKey, receives with serverKey
                        aes      = std::make_unique<aes128>(clientKey);
                        aes_recv = std::make_unique<aes128>(serverKey);

                        cli_cke_sent = true;
                    }

                    try {
                        flush_out();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            return;
                        throw;
                    }

                    if (!hasPendingWrite()) {
                        hs_state = HsState::CLI_SEND_CCS_FIN;
                    }
                    break;
                }

                // ---------------------------
                // 6) send CCS + Finished (encrypted)
                // ---------------------------
                case HsState::CLI_SEND_CCS_FIN:
                {
                    if (!cli_ccs_fin_sent) {
                        // 1) Send CCS record
                        static const uint8_t ccs[6] = {0x14,0x03,0x03,0x00,0x01,0x01};
                        queueRaw(ccs, sizeof(ccs));
                        send_seq = 0;

                        // 2) Compute client Finished verify_data
                        //    verify_data = PRF(master_secret, "client finished", Hash(transcript))
                        std::vector<uint8_t> th = sha256_hash(handshake_transcript);
                        std::vector<uint8_t> verifyClient = prf(masterSecret, "client finished", th, 12);

                        // 3) Build Finished handshake message
                        std::vector<uint8_t> finMsg;
                        finMsg.reserve(4 + 12);
                        finMsg.push_back(0x14); // Finished type
                        finMsg.push_back(0x00); finMsg.push_back(0x00); finMsg.push_back(0x0c); // length = 12
                        finMsg.insert(finMsg.end(), verifyClient.begin(), verifyClient.end());

                        // 4) Add to transcript
                        handshake_transcript.insert(handshake_transcript.end(), finMsg.begin(), finMsg.end());

                        // 5) Encrypt and send as TLS 1.2 record
                        sendTLS12Record(0x16, finMsg);

                        cli_ccs_fin_sent = true;
                    }

                    try {
                        flush_out();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            return;
                        throw;
                    }

                    if (!hasPendingWrite()) {
                        hs_state = HsState::CLI_WAIT_SCCS;
                    }
                    break;
                }

                // ---------------------------
                // 7) wait Server CCS
                // ---------------------------
                case HsState::CLI_WAIT_SCCS:
                {
                    std::vector<uint8_t> rec;
                    try {
                        rec = readTlsRecordAsync();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            note("ssl::handshake_after_connect: wait server CCS");
                        throw;
                    }

                    if (rec.empty())
                        note("ssl::handshake_after_connect: wait server CCS");

                    if (rec[0] == 0x14) {
                        recv_seq = 0;
                        hs_state = HsState::CLI_WAIT_SFIN;
                        break;
                    }

                    if (rec[0] == 0x15) {
                        NetException e;
                        e[NetException::Error] << "server alert while waiting CCS";
                        throw e;
                    }

                    note("ssl::handshake_after_connect: unexpected record while waiting CCS");
                }

                // ---------------------------
                // 8) wait Server Finished
                // ---------------------------
                case HsState::CLI_WAIT_SFIN:
                {
                    std::vector<uint8_t> rec;
                    try {
                        rec = readTlsRecordAsync();
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note)
                            note("ssl::handshake_after_connect: wait server Finished");
                        throw;
                    }

                    if (rec.empty())
                        note("ssl::handshake_after_connect: wait server Finished");

                    if (rec.size() < 5 + 16 || rec[0] != 0x16)
                        throwSSL(NetException::Error, "Expected Finished handshake record from server");

                    uint16_t finVer = ((uint16_t)rec[1] << 8) | (uint16_t)rec[2];
                    std::vector<uint8_t> finFrag(rec.begin() + 5, rec.end());

                    // Decrypt the record
                    std::vector<uint8_t> finPT = decryptRecordCBC(0x16, finVer, finFrag);

                    if (finPT.size() < 4 + 12 ||
                        finPT[0] != 0x14 || finPT[1] != 0x00 || finPT[2] != 0x00 || finPT[3] != 0x0c) {
                        throwSSL(NetException::Error, "Bad Finished structure from server");
                    }

                    // Verify server Finished: PRF(master_secret, "server finished", Hash(transcript))
                    std::vector<uint8_t> th = sha256_hash(handshake_transcript);
                    std::vector<uint8_t> expectedServer = prf(masterSecret, "server finished", th, 12);

                    if (!std::equal(expectedServer.begin(), expectedServer.end(), finPT.begin() + 4)) {
                        throwSSL(NetException::Error, "server Finished verify_data mismatch");
                    }

                    // Add server Finished to transcript
                    handshake_transcript.insert(handshake_transcript.end(),
                                                finPT.begin(), finPT.begin() + 4 + 12);

                    // In abbreviated (resumption) handshake the client must
                    // still send CCS + Finished after verifying the server's.
                    if (is_resumption && !cli_ccs_fin_sent) {
                        static const uint8_t ccs[6] = {0x14,0x03,0x03,0x00,0x01,0x01};
                        queueRaw(ccs, sizeof(ccs));
                        send_seq = 0;

                        std::vector<uint8_t> cth = sha256_hash(handshake_transcript);
                        std::vector<uint8_t> verifyClient = prf(masterSecret, "client finished", cth, 12);

                        std::vector<uint8_t> finMsg;
                        finMsg.reserve(16);
                        finMsg.push_back(0x14);
                        finMsg.push_back(0x00); finMsg.push_back(0x00); finMsg.push_back(0x0c);
                        finMsg.insert(finMsg.end(), verifyClient.begin(), verifyClient.end());
                        handshake_transcript.insert(handshake_transcript.end(),
                                                    finMsg.begin(), finMsg.end());
                        sendTLS12Record(0x16, finMsg);
                        cli_ccs_fin_sent = true;

                        // Flush before completing
                        try { flush_out(); } catch (NetException& e) {
                            if (e.getErrorType() == NetException::Note) return;
                            throw;
                        }
                    }

                    handshakeDone = true;
                    hs_state = HsState::DONE;

                    // --- Client-side: cache session for future resumption ---
                    if (session_cache && !is_tls13 && !client_session_id.empty()
                        && !masterSecret.empty()) {
                        session_cache->store(client_session_id, masterSecret, chosenSuite);
                    }
                    return;
                }

                default:
                    return;
            }
        }
    }


    size_t tls::recvData(buffer& data, int flags){
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        auto throwSSL = [&](int etype, const std::string& msg) -> void {
            NetException e;
            e[etype] << "ssl::recvData: " << msg;
            throw e;
        };

        if (!handshakeDone) {
            NetException n;
            n[NetException::Note] << "ssl::recvData: handshake not done";
            throw n;
        }


        // ============================================================
        // 1) deliver leftover plaintext (partial read from last record)
        // ============================================================
        if (recv_off < rx_record_buf.size()) {
            const size_t avail  = rx_record_buf.size() - recv_off;
            const size_t outLen = std::min<size_t>((size_t)data.size, avail);


            std::memcpy(data.data.buf, rx_record_buf.data() + recv_off, outLen);
            recv_off += outLen;

            if (recv_off == rx_record_buf.size()) {
                rx_record_buf.clear();
                recv_off = 0;
            }

            data.size = outLen;
            return outLen;
        }

        // ============================================================
        // 2) read records until we find application data
        // ============================================================
        for (int attempts = 0; attempts < 4; ++attempts) {

            std::vector<uint8_t> rec = readTlsRecordAsync();  // may throw Note

            if (rec.size() < 5)
                throwSSL(NetException::Error, "TLS record too short");

            const uint8_t  outer_type = rec[0];
            const uint16_t ver        = (uint16_t(rec[1]) << 8) | uint16_t(rec[2]);

            std::vector<uint8_t> frag(rec.begin() + 5, rec.end());

            // ------------------------------------------------------------
            // TLS 1.2 record handling (CBC in your code)
            // ------------------------------------------------------------
            if (!is_tls13) {

                // ALERT => orderly shutdown
                if (outer_type == 0x15)
                    return 0;

                // ignore non-appdata records
                if (outer_type != 0x17)
                    continue;

                if (!aes_recv)
                    throwSSL(NetException::Error, "aes_recv missing");

                std::vector<uint8_t> plain = decryptRecordCBC(outer_type, ver, frag);

                if (plain.empty())
                    continue;

                // store decrypted bytes for partial reads
                rx_record_buf = std::move(plain);
                recv_off = 0;

                const size_t outLen = std::min<size_t>((size_t)data.size, rx_record_buf.size());
                std::memcpy(data.data.buf, rx_record_buf.data(), outLen);
                recv_off = outLen;
                data.size = outLen;

                if (recv_off == rx_record_buf.size()) {
                    rx_record_buf.clear();
                    recv_off = 0;
                }
                return outLen;
            }

            // ------------------------------------------------------------
            // TLS 1.3 record handling (AEAD in your code)
            // ------------------------------------------------------------
            else {
                // RFC8446: outer record_type MUST be 0x17 for protected records.
                // In practice you may still see alerts in clear during early stages,
                // but once handshakeDone, expect 0x17.
                //
                // If an outer alert arrives anyway => shutdown.
                if (outer_type == 0x15)
                    return 0;

                // ignore non-appdata outer types (shouldn't happen in 1.3 after HS)
                if (outer_type != 0x17)
                    continue;

                std::vector<uint8_t> inner_plain;
                uint8_t inner_type = 0;

                // For application traffic, handshake_keys=false.
                // (Handshake traffic would be processed elsewhere, not in recvData())
                tls13_recv_record(
                    outer_type,
                    ver,
                    frag.data(), frag.size(),
                    inner_plain,
                    inner_type,
                    /*handshake_keys=*/false
                );

                // inner_type defines true content
                if (inner_type == 0x15) {
                    // alert => orderly shutdown
                    return 0;
                }

                // Not application data? ignore and keep reading.
                // (Handshake / NewSessionTicket / KeyUpdate, etc.)
                if (inner_type != 0x17)
                    continue;

                if (inner_plain.empty())
                    continue;

                // store decrypted bytes for partial reads
                rx_record_buf = std::move(inner_plain);
                recv_off = 0;

                const size_t outLen = std::min<size_t>((size_t)data.size, rx_record_buf.size());
                std::memcpy(data.data.buf, rx_record_buf.data(), outLen);
                recv_off = outLen;
                data.size = outLen;

                if (recv_off == rx_record_buf.size()) {
                    rx_record_buf.clear();
                    recv_off = 0;
                }

                return outLen;
            }
        }

        // no appdata found after several records
        NetException n;
        n[NetException::Note] << "ssl::recvData: no appdata yet";
        throw n;
    }

    size_t tls::sendData(buffer& data, int flags) {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        auto throwSSL = [&](int etype, const std::string& msg) -> void {
            NetException e;
            e[etype] << "ssl::sendData: " << msg;
            throw e;
        };

        if (!handshakeDone) {
            NetException n;
            n[NetException::Note] << "ssl::sendData: handshake not done";
            throw n;
        }

    #ifdef Windows
        // If an async write is already pending, throw Note - caller should not consume data yet
        if (pendingIocpWrite.load()) {
            NetException n;
            n[NetException::Note] << "ssl::sendData: write pending";
            throw n;
        }
    #endif

        const char* p = data.data.buf;
        if (!p || data.size == 0) return 0;

        static constexpr size_t TLS_MAX_PLAINTEXT = 16384;
        const size_t take = std::min<size_t>(data.size, TLS_MAX_PLAINTEXT);

        // Check appropriate cipher context based on TLS version
        if (is_tls13) {
            if (!aes13_app_send)
                throwSSL(NetException::Error, "TLS 1.3 application send cipher missing");
        } else {
            if (!aes) throwSSL(NetException::Error, "cipher context missing");
            if (mac_key.empty())
                throwSSL(NetException::Error, "MAC key missing for TLS 1.2");
        }

        // Send directly from buffer — no copy needed
        const uint8_t* plain = reinterpret_cast<const uint8_t*>(p);

        if (is_tls13)
            sendTLS13Record(0x17, plain, take);
        else
            sendTLS12Record(0x17, plain, take);

        try {
            flush_out();
        } catch (NetException& e) {
            if (e.getErrorType() == NetException::Note)
                return take;
            throw;
        }

        return take;
    }


    [[maybe_unused]] static std::vector<uint8_t> readFileBytesDer(const std::string& path) {
        std::ifstream f(path, std::ios::binary | std::ios::ate);
        if (!f.is_open()) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "could not open key file: " << path;
            throw e;
        }
        std::streamsize sz = f.tellg();
        if (sz < 2) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "key file too small: " << path;
            throw e;
        }
        f.seekg(0, std::ios::beg);
        std::vector<uint8_t> buf((size_t)sz);
        if (!f.read((char*)buf.data(), sz)) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "failed reading key file: " << path;
            throw e;
        }
        if (buf[0] != 0x30) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "key is not DER (first byte != 0x30): " << path;
            throw e;
        }
        return buf;
    }

    // Check if OID matches P-256 (prime256v1): 1.2.840.10045.3.1.7
    [[maybe_unused]] static bool isOidP256(const uint8_t* oid, size_t len) {
        static const uint8_t P256_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07};
        return (len == sizeof(P256_OID) && std::memcmp(oid, P256_OID, len) == 0);
    }

    // Check if OID matches ecPublicKey: 1.2.840.10045.2.1
    [[maybe_unused]] static bool isOidEcPublicKey(const uint8_t* oid, size_t len) {
        static const uint8_t EC_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01};
        return (len == sizeof(EC_OID) && std::memcmp(oid, EC_OID, len) == 0);
    }

    bool tls::popHandshakeMsg(std::vector<uint8_t>& out, uint8_t& type) {
        if (rx_handshake_buf.size() < 4) return false;

        uint32_t len = ((uint32_t)rx_handshake_buf[1] << 16) |
                    ((uint32_t)rx_handshake_buf[2] << 8) |
                    ((uint32_t)rx_handshake_buf[3]);

        if (rx_handshake_buf.size() < 4 + len) return false;

        type = rx_handshake_buf[0];
        out.assign(rx_handshake_buf.begin() + 4, rx_handshake_buf.begin() + 4 + len);

        // Aus dem Puffer entfernen
        rx_handshake_buf.erase(rx_handshake_buf.begin(), rx_handshake_buf.begin() + 4 + len);
        return true;
    }

    std::vector<uint8_t> tls::hmac_sha256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& data) {
        return netplus::hmac_sha256(key, data);
    }

    std::vector<uint8_t> tls::hmac_sha384(const std::vector<uint8_t>& key, const std::vector<uint8_t>& data) {
        return netplus::hmac_sha384(key, data);
    }
    
    std::vector<uint8_t> tls::hmac_sha1(const std::vector<uint8_t>& key, const std::vector<uint8_t>& data) {
        // Fallback to manual implementation or sha1_hash if hmac_sha1 is not in sha.h
        const size_t blockSize = 64;
        std::vector<uint8_t> k = key;

        if (k.size() > blockSize) {
            k = sha1_hash(k);
        }
        k.resize(blockSize, 0x00);

        std::vector<uint8_t> ipad(blockSize), opad(blockSize);
        for (size_t i = 0; i < blockSize; ++i) {
            ipad[i] = k[i] ^ 0x36;
            opad[i] = k[i] ^ 0x5c;
        }

        std::vector<uint8_t> innerData = ipad;
        innerData.insert(innerData.end(), data.begin(), data.end());
        std::vector<uint8_t> innerHash = sha1_hash(innerData);

        std::vector<uint8_t> outerData = opad;
        outerData.insert(outerData.end(), innerHash.begin(), innerHash.end());

        return sha1_hash(outerData);
    }

    std::vector<uint8_t> tls::prf(const std::vector<uint8_t>& secret,
                                  const std::string& label,
                                  const std::vector<uint8_t>& seed,
                                  size_t outLen) {
        std::vector<uint8_t> labelSeed;
        labelSeed.insert(labelSeed.end(), label.begin(), label.end());
        labelSeed.insert(labelSeed.end(), seed.begin(), seed.end());

        std::vector<uint8_t> result;
        std::vector<uint8_t> A = labelSeed;

        while (result.size() < outLen) {
            A = hmac_sha256(secret, A);

            std::vector<uint8_t> stepInput = A;
            stepInput.insert(stepInput.end(), labelSeed.begin(), labelSeed.end());

            std::vector<uint8_t> stepHash = hmac_sha256(secret, stepInput);
            result.insert(result.end(), stepHash.begin(), stepHash.end());
        }

        result.resize(outLen);
        return result;
    }

    // Helper for hkdf_expand
    static std::vector<uint8_t> _hkdf_expand(
        const std::vector<uint8_t>& prk,
        const std::vector<uint8_t>& info,
        size_t L,
        uint16_t cipherSuite
    ) {
        std::vector<uint8_t> result;
        std::vector<uint8_t> T;
        size_t n = 0;
        
        // Decide hash function
        auto hmac_func = (cipherSuite == 0x1302) ? tls::hmac_sha384 : tls::hmac_sha256;

        while (result.size() < L) {
            n++;
            std::vector<uint8_t> data;
            data.reserve(T.size() + info.size() + 1);
            data.insert(data.end(), T.begin(), T.end());
            data.insert(data.end(), info.begin(), info.end());
            data.push_back((uint8_t)n);

            T = hmac_func(prk, data);
            result.insert(result.end(), T.begin(), T.end());
        }
        result.resize(L);
        return result;
    }

    std::vector<uint8_t> tls::hkdf_expand_label(
        const std::vector<uint8_t>& secret,
        const std::string& label,
        const std::vector<uint8_t>& context,
        size_t L,
        uint16_t cipherSuite
    ) {
        std::string full = "tls13 " + label;

        std::vector<uint8_t> info;
        info.reserve(2 + 1 + full.size() + 1 + context.size());

        info.push_back((uint8_t)(L >> 8));
        info.push_back((uint8_t)(L & 0xff));

        info.push_back((uint8_t)full.size());
        info.insert(info.end(), full.begin(), full.end());

        info.push_back((uint8_t)context.size());
        info.insert(info.end(), context.begin(), context.end());
        
        return _hkdf_expand(secret, info, L, cipherSuite);
    }

    std::vector<uint8_t> tls::hkdf_extract(
        const std::vector<uint8_t>& salt,
        const std::vector<uint8_t>& ikm,
        uint16_t cipherSuite
    ) {
        size_t hashLen = (cipherSuite == 0x1302) ? 48 : 32;

        std::vector<uint8_t> s = salt;
        if (s.empty()) s.assign(hashLen, 0x00);

        std::vector<uint8_t> in = ikm;
        if (in.empty()) in.assign(hashLen, 0x00);

        if (cipherSuite == 0x1302) {
            return hmac_sha384(s, in);
        }
        return hmac_sha256(s, in);
    }

    // PKCS#1 v1.5 SHA256 Signature
    std::vector<uint8_t> tls::sign_rsa_sha256_pkcs15(
        const std::vector<uint8_t>& data,
        const netplus::rsa& key
    ) {
        // Compute SHA256 hash
        std::vector<uint8_t> mHash = sha256_hash(data);
        if (mHash.size() != 32)
            throw std::runtime_error("SHA256 hash failed");

        // PKCS#1 v1.5 signature digest info for SHA256 (OID 2.16.840.1.101.3.4.2.1)
        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 prefix_len = sizeof(sha256_prefix);

        // Build DigestInfo: prefix || hash
        std::vector<uint8_t> tBuf;
        tBuf.insert(tBuf.end(), sha256_prefix, sha256_prefix + prefix_len);
        tBuf.insert(tBuf.end(), mHash.begin(), mHash.end());

        // We need byte length of modulus N
        size_t modBitLen = key.n.bitLength();
        size_t modBytes = (modBitLen + 7) / 8;

        if (tBuf.size() > modBytes - 11)
            throw std::runtime_error("Message too long for RSA key");

        // EMSA-PKCS1-v1_5 encoding
        std::vector<uint8_t> EM(modBytes, 0x00);
        EM[0] = 0x00;
        EM[1] = 0x01; // Block type 1 (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());

        // RSA Signature Primitive: s = m^d mod n
        rsa::bigInt m = rsa::bytesToBigIntBE(EM);
        rsa::bigInt s = rsa::modPow(m, key.d, key.n); // Access private members due to friendship

        return rsa::bigIntToBytesBE(s, modBytes);
    }

    std::vector<uint8_t> tls::sign_rsa_pss_sha256(
        const std::vector<uint8_t>& data,
        netplus::rsa& key
    ) {
        // Delegate to existing RSA-PSS helper
        return netplus::rsa_pss_sha256::sign(key, data);
    }

    std::vector<uint8_t> tls::sign_ecdsa_sha256(
        const std::vector<uint8_t>& data,
        const std::vector<uint8_t>& privateKey
    ) {
        if (privateKey.size() != 32)
            throw std::runtime_error("TLS1.3: EC private key size mismatch");

        // 1. Hash the message with SHA-256
        std::vector<uint8_t> hash = sha256_hash(data);

        // 2. Generate ephemeral k
        uint8_t k_bytes[32];
        u256 k_val;

        for (int retry = 0; retry < 100; ++retry) {
            std::vector<uint8_t> rnd(32);
            fillRandom(rnd);
            std::memcpy(k_bytes, rnd.data(), 32);

            k_val = u256_from_be(k_bytes);
            if (u256_is_zero(k_val)) continue;
            if (u256_cmp(k_val, P256_N) < 0) break;
            
            if (retry == 99) throw std::runtime_error("ECDSA: failed to generate k");
        }

        // 3. Compute R = k*G
        P256Point R = scalar_mul_G(k_bytes);
        if (R.inf) throw std::runtime_error("ECDSA: R at infinity");

        // 4. Get r = R.x mod n
        std::vector<uint8_t> rx_be = encode_tls_point(R);
        uint8_t r_bytes[32];
        std::memcpy(r_bytes, rx_be.data() + 1, 32);

        u256 r_val = u256_from_be(r_bytes);

        while (u256_cmp(r_val, P256_N) >= 0) {
            uint32_t br = 0;
            r_val = u256_sub_raw(r_val, P256_N, br);
        }

        if (u256_is_zero(r_val)) throw std::runtime_error("ECDSA: r = 0");

        // 5. Convert hash (z) and private key (d) to u256
        u256 z_val = u256_from_be(hash.data());
        u256 d_val = u256_from_be(privateKey.data());

        // 6. Compute s = k^-1 * (z + r*d) mod n
        u256 rd = scalar_mul_mod_n(r_val, d_val);
        u256 sum = scalar_add_mod_n(z_val, rd);
        u256 k_inv = scalar_inv_mod_n(k_val);
        u256 s_val = scalar_mul_mod_n(k_inv, sum);

        if (u256_is_zero(s_val)) throw std::runtime_error("ECDSA: s = 0");

        // 7. Convert r and s back to big-endian bytes
        uint8_t r_be[32], s_be[32];
        u256_to_be(r_be, r_val);
        u256_to_be(s_be, s_val);

        // 8. Encode as DER
        auto encodeInteger = [](const uint8_t* val, size_t len) -> std::vector<uint8_t> {
            std::vector<uint8_t> out;
            out.push_back(0x02);
            size_t start = 0;
            while (start < len - 1 && val[start] == 0) ++start;
            bool needPad = (val[start] & 0x80) != 0;
            size_t outLen = len - start + (needPad ? 1 : 0);
            out.push_back((uint8_t)outLen);
            if (needPad) out.push_back(0x00);
            out.insert(out.end(), val + start, val + len);
            return out;
        };

        std::vector<uint8_t> r_der = encodeInteger(r_be, 32);
        std::vector<uint8_t> s_der = encodeInteger(s_be, 32);

        std::vector<uint8_t> sig;
        sig.push_back(0x30);
        size_t inner_len = r_der.size() + s_der.size();
        if (inner_len >= 128) {
            sig.push_back(0x81);
            sig.push_back((uint8_t)inner_len);
        } else {
            sig.push_back((uint8_t)inner_len);
        }
        sig.insert(sig.end(), r_der.begin(), r_der.end());
        sig.insert(sig.end(), s_der.begin(), s_der.end());

        return sig;
    }

    void tls::resetTLS() {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        // MUST be false so next handshake is treated as fresh
        handshakeStarted = false;

        // also important: go back to known start state
        hs_state = HsState::IDLE;
        serverFlightQueued = false;
        serverFinishedQueued = false;
        tls13_server_hello_queued = false;
        tls13_encflight_queued = false;
        ccs_received = false;

        // Reset session resumption flags (keep session_cache pointer and
        // resumption_* data — they are set externally for the next handshake)
        is_resumption = false;

        // -------------------------
        // generic
        // -------------------------
        send_seq = 0;
        recv_seq = 0;

        handshake_transcript.clear();
        clientRandom.clear();
        serverRandom.clear();

        rx_handshake_buf.clear();
        rx_tcp_buf.clear();
        
        // -------------------------
        // Send/receive buffers (IOCP)
        // -------------------------
        send_queue.clear();
        send_record.clear();
        send_off = 0;
        pendingIocpWrite.store(false);
        
        rx_record_buf.clear();
        recv_off = 0;

        // -------------------------
        // TLS 1.2 crypto reset
        // -------------------------
        aes.reset();
        aes_recv.reset();
        mac_key.clear();
        client_mac_key.clear();

        // -------------------------
        // TLS 1.3 reset
        // -------------------------
        is_tls13 = false;
        neg_version = 0x0303;

        client_offered_tls13 = false;
        selected_group = 0;

        client_keyshare_ecdhe.clear();
        server_keyshare_ecdhe.clear();
        client_keyshare_x25519.clear();
        server_keyshare_x25519.clear();

        tls13_got_key_share = false;

        memset(client_priv_ecdhe, 0, sizeof(client_priv_ecdhe));
        memset(server_priv_ecdhe, 0, sizeof(server_priv_ecdhe));

        ecdhe_shared.clear();
        x25519_shared.clear();

        tls13_early_secret.clear();
        tls13_hs_secret.clear();
        tls13_master_secret.clear();

        tls13_c_hs_secret.clear();
        tls13_s_hs_secret.clear();

        tls13_c_ap_secret.clear();
        tls13_s_app_secret.clear();

        memset(tls13_hs_key_c2s, 0, sizeof(tls13_hs_key_c2s));
        memset(tls13_hs_key_s2c, 0, sizeof(tls13_hs_key_s2c));
        memset(tls13_hs_iv_c2s,  0, sizeof(tls13_hs_iv_c2s));
        memset(tls13_hs_iv_s2c,  0, sizeof(tls13_hs_iv_s2c));

        memset(tls13_app_key_c2s, 0, sizeof(tls13_app_key_c2s));
        memset(tls13_app_key_s2c, 0, sizeof(tls13_app_key_s2c));
        memset(tls13_app_iv_c2s,  0, sizeof(tls13_app_iv_c2s));
        memset(tls13_app_iv_s2c,  0, sizeof(tls13_app_iv_s2c));

        aes13_hs_send.reset();
        aes13_hs_recv.reset();
        aes13_app_send.reset();
        aes13_app_recv.reset();

        tls13_hs_send_seq = 0;
        tls13_hs_recv_seq = 0;
        tls13_app_send_seq = 0;
        tls13_app_recv_seq = 0;
    }

    // =================================================================
    // Helper Methods for TLS Record Management and Sending
    // =================================================================

    void tls::queueRaw(const std::vector<uint8_t>& v) {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        if (v.empty()) return;
        send_queue.emplace_back(v);
    }

    void tls::queueRaw(const uint8_t* data, size_t len) {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        if (!data || len == 0) return;
        send_queue.emplace_back(data, data + len);
    }

    void tls::queueRaw(std::vector<uint8_t>&& v) {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        if (v.empty()) return;
        send_queue.emplace_back(std::move(v));
    }

    void tls::flush_out() {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        if (!_socket) return;

        // Drain all queued records in a single call instead of one-at-a-time.
        // This lets a full TLS handshake flight (4-5 records) go out in one
        // event-loop cycle rather than requiring one cycle per record.
        while (!send_queue.empty() || (!send_record.empty() && send_off < send_record.size())) {
            // Load next queued record if current one is fully sent
            if (send_off >= send_record.size() && !send_queue.empty()) {
                send_record = std::move(send_queue.front());
                send_queue.pop_front();
                send_off = 0;
            }

            if (send_record.empty() || send_off >= send_record.size())
                break;

            size_t remaining = send_record.size() - send_off;
            buffer raw_buf((const char*)(send_record.data() + send_off), remaining);

            size_t sent = _socket->sendRaw(raw_buf, 0);
            send_off += sent;

            if (send_off < send_record.size()) {
                // Socket would block — caller retries later
                return;
            }

            // Record fully sent
            send_record.clear();
            send_off = 0;
        }
    }

    // ============================================================================
    // readTlsRecordAsync - Read a complete TLS record from the buffer
    // ============================================================================
    std::vector<uint8_t> tls::readTlsRecordAsync() {
        std::lock_guard<std::recursive_mutex> lk(mutex_);
        // Read raw TCP data into rx_tcp_buf for client-side connections.
        // Uses prime_recv() which calls tcp::recvData() (not ssl::recvData())
        // so it works during handshake when handshakeDone is still false.
        auto tryReadFromSocket = [this]() -> bool {
            if (!is_client || !_socket) return false;
            
            buffer tmp(16384);
            try {
                size_t n = _socket->prime_recv(tmp, 0);
                // prime_recv already pushes data into rx_tcp_buf
                // via pushReceivedData(), so no manual insert needed.
                return (n > 0);
            } catch (NetException& e) {
                if (e.getErrorType() == NetException::Note) {
                    return false;
                }
                throw;
            }
            return false;
        };

        while (rx_tcp_buf.size() < 5) {
            if (is_client) {
                if (!tryReadFromSocket()) {
                    NetException n;
                    n[NetException::Note] << "tls: record incomplete (need header)";
                    throw n;
                }
            } else {
                NetException n;
                n[NetException::Note] << "tls: record incomplete (need header)";
                throw n;
            }
        }

        uint16_t recLen = (uint16_t(rx_tcp_buf[3]) << 8) | uint16_t(rx_tcp_buf[4]);
        size_t total = 5 + recLen;

        while (rx_tcp_buf.size() < total) {
            if (is_client) {
                if (!tryReadFromSocket()) {
                    NetException n;
                    n[NetException::Note] << "tls: record incomplete";
                    throw n;
                }
            } else {
                NetException n;
                n[NetException::Note] << "tls: record incomplete";
                throw n;
            }
        }

        std::vector<uint8_t> rec(rx_tcp_buf.begin(), rx_tcp_buf.begin() + total);
        rx_tcp_buf.erase(rx_tcp_buf.begin(), rx_tcp_buf.begin() + total);

        return rec;
    }

    // ============================================================================
    // decryptRecordCBC - Decrypt TLS 1.2 CBC record
    // ============================================================================
    std::vector<uint8_t> tls::decryptRecordCBC(
        uint8_t type, uint16_t ver, const std::vector<uint8_t>& payload) 
    {
        if (!aes_recv) {
            NetException e;
            e[NetException::Error] << "tls: decryptRecordCBC called but aes_recv is NULL";
            throw e;
        }

        const size_t macLen = 20;
        const size_t block = 16;

        auto throwTLS = [](const std::string& msg) {
            NetException e;
            e[NetException::Error] << "tls::decryptRecordCBC: " << msg;
            throw e;
        };

        if (payload.size() < 16 + block)
            throwTLS("record too short");

        if ((payload.size() % 16) != 0)
            throwTLS("payload length not multiple of block size");

        std::vector<uint8_t> iv(payload.begin(), payload.begin() + 16);
        std::vector<uint8_t> ct(payload.begin() + 16, payload.end());

        std::vector<uint8_t> p;
        try {
            p = aes_recv->decryptCBC(ct, iv);
        } catch (const std::exception& ex) {
            throwTLS(std::string("AES-CBC decrypt failed: ") + ex.what());
        }

        if (p.size() < macLen + 1)
            throwTLS("plaintext too short");

        uint8_t padLen = p.back();
        size_t padTotal = size_t(padLen) + 1;
        if (padTotal > p.size())
            throwTLS("invalid padding length");

        for (size_t i = 0; i < padTotal; ++i) {
            if (p[p.size() - 1 - i] != padLen)
                throwTLS("bad padding bytes");
        }

        p.resize(p.size() - padTotal);

        if (p.size() < macLen)
            throwTLS("plaintext too short after padding strip");

        std::vector<uint8_t> mac(p.end() - macLen, p.end());
        p.resize(p.size() - macLen);

        uint8_t seqBytes[8];
        seqToBytes(recv_seq, seqBytes);

        std::vector<uint8_t> hdr5 = {
            type,
            uint8_t(ver >> 8), uint8_t(ver & 0xFF),
            uint8_t(p.size() >> 8), uint8_t(p.size() & 0xFF)
        };

        std::vector<uint8_t> macIn(seqBytes, seqBytes + 8);
        macIn.insert(macIn.end(), hdr5.begin(), hdr5.end());
        macIn.insert(macIn.end(), p.begin(), p.end());

        const std::vector<uint8_t>& key = is_client ? mac_key : client_mac_key;
        std::vector<uint8_t> expected = hmac_sha1(key, macIn);

        if (expected.size() != mac.size() || !std::equal(expected.begin(), expected.end(), mac.begin()))
            throwTLS("record MAC mismatch");

        recv_seq++;
        return p;
    }

    // ============================================================================
    // sendTLS12Record - Encrypt and send TLS 1.2 record
    // ============================================================================
    void tls::sendTLS12Record(uint8_t type, const std::vector<uint8_t>& plain) {
        const uint16_t ver = 0x0303;
        const size_t macLen = 20;
        const size_t blockSize = 16;
        const size_t ivLen = 16;

        auto throwErr = [](const std::string& msg) {
            NetException e;
            e[NetException::Error] << "tls::sendTLS12Record: " << msg;
            throw e;
        };

        if (!aes) throwErr("AES send cipher not initialized");

        // Server: mac_key = server write MAC; Client: client_mac_key = client write MAC
        const std::vector<uint8_t>& sendMacKey = is_client ? client_mac_key : mac_key;
        if (sendMacKey.size() != macLen) throwErr("MAC key len invalid");

        uint8_t seqBytes[8];
        seqToBytes(send_seq, seqBytes);

        uint8_t hdr[5];
        hdr[0] = type;
        hdr[1] = uint8_t(ver >> 8);
        hdr[2] = uint8_t(ver & 0xFF);
        hdr[3] = uint8_t((plain.size() >> 8) & 0xFF);
        hdr[4] = uint8_t(plain.size() & 0xFF);

        std::vector<uint8_t> macIn;
        macIn.reserve(8 + 5 + plain.size());
        macIn.insert(macIn.end(), seqBytes, seqBytes + 8);
        macIn.insert(macIn.end(), hdr, hdr + 5);
        macIn.insert(macIn.end(), plain.begin(), plain.end());

        std::vector<uint8_t> mac = hmac_sha1(sendMacKey, macIn);

        std::vector<uint8_t> fragment;
        fragment.reserve(plain.size() + macLen + blockSize + 1);
        fragment.insert(fragment.end(), plain.begin(), plain.end());
        fragment.insert(fragment.end(), mac.begin(), mac.end());

        size_t curLen = fragment.size();
        size_t padLen = (blockSize - ((curLen + 1) % blockSize)) % blockSize;

        for (size_t i = 0; i < padLen + 1; ++i)
            fragment.push_back(uint8_t(padLen));

        std::vector<uint8_t> iv(ivLen);
        fillRandom(iv);

        std::vector<uint8_t> ct = aes->encryptCBC(fragment, iv);

        std::vector<uint8_t> payload;
        payload.reserve(ivLen + ct.size());
        payload.insert(payload.end(), iv.begin(), iv.end());
        payload.insert(payload.end(), ct.begin(), ct.end());

        uint8_t recHdr[5];
        recHdr[0] = type;
        recHdr[1] = uint8_t(ver >> 8);
        recHdr[2] = uint8_t(ver & 0xFF);
        recHdr[3] = uint8_t((payload.size() >> 8) & 0xFF);
        recHdr[4] = uint8_t(payload.size() & 0xFF);

        queueRaw(recHdr, 5);
        queueRaw(payload);

        send_seq++;
    }

    void tls::sendTLS12Record(uint8_t type, const uint8_t* plain_data, size_t plain_len) {
        const uint16_t ver = 0x0303;
        const size_t macLen = 20;
        const size_t blockSize = 16;
        const size_t ivLen = 16;

        auto throwErr = [](const std::string& msg) {
            NetException e;
            e[NetException::Error] << "tls::sendTLS12Record: " << msg;
            throw e;
        };

        if (!aes) throwErr("AES send cipher not initialized");

        const std::vector<uint8_t>& sendMacKey = is_client ? client_mac_key : mac_key;
        if (sendMacKey.size() != macLen) throwErr("MAC key len invalid");

        uint8_t seqBytes[8];
        seqToBytes(send_seq, seqBytes);

        uint8_t hdr[5];
        hdr[0] = type;
        hdr[1] = uint8_t(ver >> 8);
        hdr[2] = uint8_t(ver & 0xFF);
        hdr[3] = uint8_t((plain_len >> 8) & 0xFF);
        hdr[4] = uint8_t(plain_len & 0xFF);

        std::vector<uint8_t> macIn;
        macIn.reserve(8 + 5 + plain_len);
        macIn.insert(macIn.end(), seqBytes, seqBytes + 8);
        macIn.insert(macIn.end(), hdr, hdr + 5);
        macIn.insert(macIn.end(), plain_data, plain_data + plain_len);

        std::vector<uint8_t> mac = hmac_sha1(sendMacKey, macIn);

        std::vector<uint8_t> fragment;
        fragment.reserve(plain_len + macLen + blockSize + 1);
        fragment.insert(fragment.end(), plain_data, plain_data + plain_len);
        fragment.insert(fragment.end(), mac.begin(), mac.end());

        size_t curLen = fragment.size();
        size_t padLen = (blockSize - ((curLen + 1) % blockSize)) % blockSize;

        for (size_t i = 0; i < padLen + 1; ++i)
            fragment.push_back(uint8_t(padLen));

        std::vector<uint8_t> iv(ivLen);
        fillRandom(iv);

        std::vector<uint8_t> ct = aes->encryptCBC(fragment, iv);

        std::vector<uint8_t> payload;
        payload.reserve(ivLen + ct.size());
        payload.insert(payload.end(), iv.begin(), iv.end());
        payload.insert(payload.end(), ct.begin(), ct.end());

        uint8_t recHdr[5];
        recHdr[0] = type;
        recHdr[1] = uint8_t(ver >> 8);
        recHdr[2] = uint8_t(ver & 0xFF);
        recHdr[3] = uint8_t((payload.size() >> 8) & 0xFF);
        recHdr[4] = uint8_t(payload.size() & 0xFF);

        queueRaw(recHdr, 5);
        queueRaw(payload);

        send_seq++;
    }

    // ============================================================================
    // sendTLS13Record - Encrypt and send TLS 1.3 application data record
    // ============================================================================
    void tls::sendTLS13Record(uint8_t innerType, const std::vector<uint8_t>& plain) {
        tls13_send_record(innerType, plain, false);
    }

    void tls::sendTLS13Record(uint8_t innerType, const uint8_t* data, size_t len) {
        tls13_send_record(innerType, data, len, false);
    }

    // ============================================================================
    // tls13_read_record_handshake - Read TLS 1.3 handshake record
    // ============================================================================
    std::vector<uint8_t> tls::tls13_read_record_handshake() {
        std::vector<uint8_t> rec = readTlsRecordAsync();
        if (rec.empty()) return {};

        uint8_t recType = rec[0];
        uint16_t ver = (uint16_t(rec[1]) << 8) | uint16_t(rec[2]);
        
        if (recType == 0x14) {
            // ChangeCipherSpec - ignore in TLS 1.3
            return tls13_read_record_handshake();
        }

        if (recType == 0x17) {
            // Application data (encrypted)
            const uint8_t* data = rec.data() + 5;
            size_t data_len = rec.size() - 5;

            std::vector<uint8_t> plain;
            uint8_t inner_type = 0;

            bool ok = tls13_recv_record(recType, ver, data, data_len, plain, inner_type, true);
            if (!ok) {
                NetException e;
                e[NetException::Error] << "tls13: decryption failed";
                throw e;
            }

            if (inner_type == 0x15) {
                // Alert record
                NetException e;
                if (plain.size() >= 2) {
                    e[NetException::Error] << "tls13: received alert level="
                        << int(plain[0]) << " desc=" << int(plain[1]);
                } else {
                    e[NetException::Error] << "tls13: received alert (malformed)";
                }
                throw e;
            }

            if (inner_type != 0x16) {
                NetException e;
                e[NetException::Error] << "tls13: expected handshake inner type, got 0x"
                    << std::hex << int(inner_type);
                throw e;
            }

            rx_handshake_buf.insert(rx_handshake_buf.end(), plain.begin(), plain.end());
            return plain;
        }

        if (recType == 0x15) {
            // Alert
            NetException e;
            e[NetException::Error] << "tls13: received alert";
            throw e;
        }

        return rec;
    }

    // ============================================================================
    // tls13_pop_hs_from_buf - Pop handshake message from buffer
    // ============================================================================
    bool tls::tls13_pop_hs_from_buf(std::vector<uint8_t>& out_msg) {
        if (rx_handshake_buf.size() < 4) return false;

        // uint8_t hsType = rx_handshake_buf[0]; // unused, type is in out_msg[0]
        uint32_t hsLen = (uint32_t(rx_handshake_buf[1]) << 16) |
                         (uint32_t(rx_handshake_buf[2]) << 8) |
                         uint32_t(rx_handshake_buf[3]);

        size_t total = 4 + hsLen;
        if (rx_handshake_buf.size() < total) return false;

        out_msg.assign(rx_handshake_buf.begin(), rx_handshake_buf.begin() + total);
        rx_handshake_buf.erase(rx_handshake_buf.begin(), rx_handshake_buf.begin() + total);

        return true;
    }

    // ============================================================================
    // tls13_derive_handshake_keys - Derive TLS 1.3 handshake keys
    // ============================================================================
    void tls::tls13_derive_handshake_keys(const std::vector<uint8_t>& ecdhe_shared) {
        size_t hashLen = (tls13_cipher == 0x1302) ? 48 : 32;  // SHA-384 or SHA-256
        

        std::vector<uint8_t> zero_ikm(hashLen, 0);
        std::vector<uint8_t> zero_salt(hashLen, 0);

        tls13_early_secret = hkdf_extract(zero_salt, zero_ikm, tls13_cipher);

        // RFC 8446: "derived" uses Hash("") as context, NOT empty vector
        std::vector<uint8_t> empty_hash = (tls13_cipher == 0x1302) 
            ? sha384_hash({}) 
            : sha256_hash({});
        std::vector<uint8_t> derived = hkdf_expand_label(tls13_early_secret, "derived", empty_hash, hashLen, tls13_cipher);

        tls13_hs_secret = hkdf_extract(derived, ecdhe_shared, tls13_cipher);


        std::vector<uint8_t> transcript = tls13_transcript_hash();
        

        tls13_c_hs_secret = hkdf_expand_label(tls13_hs_secret, "c hs traffic", transcript, hashLen, tls13_cipher);
        tls13_s_hs_secret = hkdf_expand_label(tls13_hs_secret, "s hs traffic", transcript, hashLen, tls13_cipher);


        size_t keyLen = (tls13_cipher == 0x1302) ? 32 : 16;
        size_t ivLen = 12;

        auto c_key = hkdf_expand_label(tls13_c_hs_secret, "key", {}, keyLen, tls13_cipher);
        auto c_iv = hkdf_expand_label(tls13_c_hs_secret, "iv", {}, ivLen, tls13_cipher);
        auto s_key = hkdf_expand_label(tls13_s_hs_secret, "key", {}, keyLen, tls13_cipher);
        auto s_iv = hkdf_expand_label(tls13_s_hs_secret, "iv", {}, ivLen, tls13_cipher);


        std::memcpy(tls13_hs_key_c2s, c_key.data(), keyLen);
        std::memcpy(tls13_hs_iv_c2s, c_iv.data(), ivLen);
        std::memcpy(tls13_hs_key_s2c, s_key.data(), keyLen);
        std::memcpy(tls13_hs_iv_s2c, s_iv.data(), ivLen);

        if (is_client) {
            if (keyLen == 32) {
                aes13_hs_send = std::make_unique<aes256>(c_key);
                aes13_hs_recv = std::make_unique<aes256>(s_key);
            } else {
                aes13_hs_send = std::make_unique<aes128>(c_key);
                aes13_hs_recv = std::make_unique<aes128>(s_key);
            }
        } else {
            if (keyLen == 32) {
                aes13_hs_send = std::make_unique<aes256>(s_key);
                aes13_hs_recv = std::make_unique<aes256>(c_key);
            } else {
                aes13_hs_send = std::make_unique<aes128>(s_key);
                aes13_hs_recv = std::make_unique<aes128>(c_key);
            }
        }

        tls13_hs_send_seq = 0;
        tls13_hs_recv_seq = 0;
    }

    // ============================================================================
    // tls13_recv_record - Decrypt TLS 1.3 record
    // ============================================================================
    bool tls::tls13_recv_record(
        uint8_t record_type, uint16_t legacy_ver,
        const uint8_t* data, size_t data_len,
        std::vector<uint8_t>& out_plain, uint8_t& out_inner_type,
        bool handshake_keys)
    {
        if (data_len < 16) return false;  // need at least tag

        netplus::aes* cipher = handshake_keys ? aes13_hs_recv.get() : aes13_app_recv.get();
        if (!cipher) return false;

        uint64_t& seq = handshake_keys ? tls13_hs_recv_seq : tls13_app_recv_seq;
        const uint8_t* base_iv = handshake_keys ?
            (is_client ? tls13_hs_iv_s2c : tls13_hs_iv_c2s) :
            (is_client ? tls13_app_iv_s2c : tls13_app_iv_c2s);

        uint8_t nonce[12];
        std::memcpy(nonce, base_iv, 12);
        for (int i = 0; i < 8; ++i) {
            nonce[11 - i] ^= uint8_t((seq >> (8 * i)) & 0xFF);
        }

        // AAD: record_type || 0x0303 || length
        uint8_t aad[5] = {record_type, 0x03, 0x03, 
                          uint8_t((data_len >> 8) & 0xFF), 
                          uint8_t(data_len & 0xFF)};

        // Split ciphertext and tag
        size_t enc_len = data_len - 16;
        const uint8_t* ct = data;
        const uint8_t* tag = data + enc_len;

        std::vector<uint8_t> plain(enc_len);
        if (!cipher->aes_gcm_decrypt(nonce, aad, 5, ct, enc_len, tag, plain.data())) {
            return false;
        }

        seq++;

        // Strip padding and get inner type
        while (!plain.empty() && plain.back() == 0) {
            plain.pop_back();
        }
        if (plain.empty()) return false;

        out_inner_type = plain.back();
        plain.pop_back();
        out_plain = std::move(plain);

        return true;
    }

    // ============================================================================
    // fetchNextHandshakePlain - Fetch next TLS 1.2 handshake message
    // ============================================================================
    std::vector<uint8_t> tls::fetchNextHandshakePlain() {
        while (true) {
            if (rx_handshake_buf.size() >= 4) {
                uint32_t len = (uint32_t(rx_handshake_buf[1]) << 16) |
                               (uint32_t(rx_handshake_buf[2]) << 8) |
                               uint32_t(rx_handshake_buf[3]);
                size_t total = 4 + len;

                if (rx_handshake_buf.size() >= total) {
                    std::vector<uint8_t> msg(rx_handshake_buf.begin(), 
                                             rx_handshake_buf.begin() + total);
                    rx_handshake_buf.erase(rx_handshake_buf.begin(), 
                                           rx_handshake_buf.begin() + total);
                    return msg;
                }
            }

            std::vector<uint8_t> rec = readTlsRecordAsync();
            if (rec.empty()) {
                NetException e;
                e[NetException::Note] << "tls: no record available";
                throw e;
            }

            uint8_t recType = rec[0];
            if (recType == 0x14) {
                // ChangeCipherSpec
                ccs_received = true;
                continue;
            }

            if (recType == 0x15) {
                // Alert
                NetException e;
                e[NetException::Error] << "tls: received alert";
                throw e;
            }

            if (recType != 0x16) {
                NetException e;
                e[NetException::Error] << "tls: expected handshake record";
                throw e;
            }

            std::vector<uint8_t> fragment(rec.begin() + 5, rec.end());

            if (ccs_received && aes_recv) {
                uint16_t ver = (uint16_t(rec[1]) << 8) | uint16_t(rec[2]);
                fragment = decryptRecordCBC(recType, ver, fragment);
            }

            rx_handshake_buf.insert(rx_handshake_buf.end(), 
                                    fragment.begin(), fragment.end());
        }
    }

    // =================================================================
    // TLS 1.2 Handshake Methods
    // =================================================================

    void tls::sendHandshake(uint8_t type, const std::vector<uint8_t>& data) {
        // 1. HANDSHAKE LAYER (The "Letter")
        std::vector<uint8_t> handshake;
        handshake.push_back(type);                   // e.g., 0x01 for ClientHello
        handshake.push_back((data.size() >> 16) & 0xFF); // Length (3 bytes)
        handshake.push_back((data.size() >> 8) & 0xFF);
        handshake.push_back(data.size() & 0xFF);
        handshake.insert(handshake.end(), data.begin(), data.end());

        // IMPORTANT: Add the Handshake Layer to the transcript for Finished verification
        handshake_transcript.insert(handshake_transcript.end(),
                                    handshake.begin(), handshake.end());

        // 2. RECORD LAYER (The "Envelope")
        std::vector<uint8_t> record;
        record.push_back(0x16);               // Type: Handshake
        record.push_back(0x03);               // Version Major (3)
        record.push_back(0x03);               // Version Minor (3 for TLS 1.2)
        record.push_back((handshake.size() >> 8) & 0xFF); // Record Length MSB
        record.push_back(handshake.size() & 0xFF);        // Record Length LSB
        record.insert(record.end(), handshake.begin(), handshake.end());

        // 3. SEND TO SOCKET
        queueRaw(record);
    }

    void tls::sendServerHello_TLS12(bool secureReneg, uint16_t chosenSuiteArg) {
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::sendServerHello: " << msg;
            throw e;
        };

        // Sanity: allow only TLS1.2 suites here
        if (chosenSuiteArg != 0x002F && chosenSuiteArg != 0x0035) {
            throwSSL(netplus::NetException::Error, "Invalid TLS1.2 cipher suite selected");
        }

        std::vector<uint8_t> body;
        body.reserve(128);

        // 1) TLS version = 0x0303 (TLS 1.2)
        body.push_back(0x03);
        body.push_back(0x03);

        // 2) ServerRandom (32 bytes)
        serverRandom.resize(32);
        fillRandomBytes(serverRandom.data(), 32);
        body.insert(body.end(), serverRandom.begin(), serverRandom.end());

        // 3) SessionID — echo back for resumption support
        body.push_back(static_cast<uint8_t>(client_session_id.size()));
        if (!client_session_id.empty()) {
            body.insert(body.end(), client_session_id.begin(), client_session_id.end());
        }

        // 4) CipherSuite
        body.push_back((chosenSuiteArg >> 8) & 0xFF);
        body.push_back((chosenSuiteArg >> 0) & 0xFF);

        // 5) CompressionMethod = null (0)
        body.push_back(0x00);

        // 6) Extensions
        std::vector<uint8_t> exts;

        if (secureReneg) {
            // renegotiation_info (RFC 5746)
            // type: ff01, len: 0001, body: 00
            exts.push_back(0xFF); exts.push_back(0x01);
            exts.push_back(0x00); exts.push_back(0x01);
            exts.push_back(0x00);
        }

        // Write extensions length (always present in TLS1.2 ServerHello!)
        body.push_back((exts.size() >> 8) & 0xFF);
        body.push_back((exts.size() >> 0) & 0xFF);

        // Write extensions payload
        body.insert(body.end(), exts.begin(), exts.end());

        // Send handshake message type 0x02 (ServerHello)
        sendHandshake(0x02, body);
    }

    // =================================================================
    // TLS 1.3 ServerHello Builder
    // =================================================================

    std::vector<uint8_t> tls::buildServerHello_TLS13(
        uint16_t cipher13,
        const std::vector<uint8_t>& client_session_id,
        uint16_t named_group,
        const std::vector<uint8_t>& pubkey
    ){
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::buildServerHello_TLS13: " << msg;
            throw e;
        };

        if (serverRandom.size() != 32)
            throwSSL(NetException::Error, "TLS1.3 ServerHello: serverRandom not set");

        if (client_session_id.size() > 32)
            throwSSL(NetException::Error, "TLS1.3 ServerHello: session_id too long");

        if (cipher13 != 0x1301 && cipher13 != 0x1302 && cipher13 != 0x1303)
            throwSSL(NetException::Error, "TLS1.3 ServerHello: invalid cipher");

        if (named_group != 0x0017 && named_group != 0x001d)
            throwSSL(NetException::Error, "TLS1.3 ServerHello: invalid group");

        if (named_group == 0x0017 && (pubkey.size() != 65 || pubkey[0] != 0x04))
            throwSSL(NetException::Error, "TLS1.3 ServerHello: bad P-256 key");

        if (named_group == 0x001d && pubkey.size() != 32)
            throwSSL(NetException::Error, "TLS1.3 ServerHello: bad X25519 key");

        std::vector<uint8_t> body;

        body.push_back(0x03); body.push_back(0x03); // legacy_version
        body.insert(body.end(), serverRandom.begin(), serverRandom.end());

        body.push_back((uint8_t)client_session_id.size());
        body.insert(body.end(), client_session_id.begin(), client_session_id.end());

        body.push_back(uint8_t(cipher13 >> 8));
        body.push_back(uint8_t(cipher13));

        body.push_back(0x00); // legacy_compression

        // --- extensions ---
        std::vector<uint8_t> exts;
        auto u16 = [&](uint16_t v){ exts.push_back(v>>8); exts.push_back(v&0xff); };

        // supported_versions
        u16(0x002b); u16(2); u16(0x0304);

        // key_share
        u16(0x0033);
        uint16_t keylen = (uint16_t)pubkey.size();
        uint16_t payload_len = 2 + 2 + keylen;
        u16(payload_len);
        u16(named_group);
        u16(keylen);
        exts.insert(exts.end(), pubkey.begin(), pubkey.end());

        body.push_back(uint8_t(exts.size() >> 8));
        body.push_back(uint8_t(exts.size() & 0xFF));
        body.insert(body.end(), exts.begin(), exts.end());

        // wrap handshake header
        std::vector<uint8_t> hs;
        hs.push_back(0x02);
        uint32_t blen = (uint32_t)body.size();
        hs.push_back(uint8_t(blen >> 16));
        hs.push_back(uint8_t(blen >> 8));
        hs.push_back(uint8_t(blen));
        hs.insert(hs.end(), body.begin(), body.end());

        return hs;
    }

    // =================================================================
    // TLS 1.3 Record and Handshake Layer
    // =================================================================

    void tls::tls13_send_record(uint8_t inner_type,
                                const std::vector<uint8_t>& plaintext,
                                bool handshake_keys)
    {
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::tls13_send_record: " << msg;
            throw e;
        };

        // Choose correct key/iv + seq depending on phase (HS or APP)
        netplus::aes* aead = nullptr;
        const uint8_t* base_iv = nullptr;
        uint64_t* seqp = nullptr;

        if (handshake_keys) {
            aead = aes13_hs_send.get();
            base_iv = is_client ? tls13_hs_iv_c2s : tls13_hs_iv_s2c;
            seqp = &tls13_hs_send_seq;
        } else {
            aead = aes13_app_send.get();
            base_iv = is_client ? tls13_app_iv_c2s : tls13_app_iv_s2c;
            seqp = &tls13_app_send_seq;
        }

        if (!aead || !base_iv || !seqp)
            throwSSL(NetException::Error, "TLS1.3 send_record: missing AEAD state");

        uint64_t seq = *seqp;


        // Build TLSInnerPlaintext = plaintext || inner_type
        std::vector<uint8_t> inner = plaintext;
        inner.push_back(inner_type);   // MUST include inner content type byte

        // Compute nonce = base_iv XOR seq (seq big-endian into last 8 bytes)
        uint8_t nonce[12];
        std::memcpy(nonce, base_iv, 12);

        uint64_t s = seq;
        for (int i = 0; i < 8; i++) {
            nonce[11 - i] ^= uint8_t(s & 0xFF);
            s >>= 8;
        }


        // Outer TLSCiphertext header (this is the AEAD AAD)
        constexpr size_t TAG_LEN = 16;

        const size_t ct_len = inner.size();
        const size_t rec_payload_len = ct_len + TAG_LEN;

        uint8_t hdr[5];
        hdr[0] = 0x17; // application_data (always, for protected TLS1.3 records)
        hdr[1] = 0x03;
        hdr[2] = 0x03;
        hdr[3] = uint8_t(rec_payload_len >> 8);
        hdr[4] = uint8_t(rec_payload_len & 0xFF);

        // AEAD encrypt
        std::vector<uint8_t> ct(ct_len);
        uint8_t tag16[16];

        bool ok = aead->aes_gcm_encrypt(
            nonce,
            hdr, sizeof(hdr),
            inner.data(), inner.size(),
            ct.data(),
            tag16
        );

        if (!ok)
            throwSSL(NetException::Error, "TLS1.3 send_record: AES-GCM encrypt failed");

        // Assemble final TLSCiphertext record: hdr || ct || tag
        std::vector<uint8_t> rec;
        rec.reserve(5 + rec_payload_len);

        rec.insert(rec.end(), hdr, hdr + 5);
        rec.insert(rec.end(), ct.begin(), ct.end());
        rec.insert(rec.end(), tag16, tag16 + 16);

        queueRaw(rec);

        // Increment sequence number
        (*seqp)++;
    }

    void tls::tls13_send_record(uint8_t inner_type,
                                const uint8_t* plain_data, size_t plain_len,
                                bool handshake_keys)
    {
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::tls13_send_record: " << msg;
            throw e;
        };

        netplus::aes* aead = nullptr;
        const uint8_t* base_iv = nullptr;
        uint64_t* seqp = nullptr;

        if (handshake_keys) {
            aead = aes13_hs_send.get();
            base_iv = is_client ? tls13_hs_iv_c2s : tls13_hs_iv_s2c;
            seqp = &tls13_hs_send_seq;
        } else {
            aead = aes13_app_send.get();
            base_iv = is_client ? tls13_app_iv_c2s : tls13_app_iv_s2c;
            seqp = &tls13_app_send_seq;
        }

        if (!aead || !base_iv || !seqp)
            throwSSL(NetException::Error, "TLS1.3 send_record: missing AEAD state");

        uint64_t seq = *seqp;

        // Build TLSInnerPlaintext = data || inner_type
        std::vector<uint8_t> inner;
        inner.reserve(plain_len + 1);
        inner.insert(inner.end(), plain_data, plain_data + plain_len);
        inner.push_back(inner_type);

        uint8_t nonce[12];
        std::memcpy(nonce, base_iv, 12);
        uint64_t s = seq;
        for (int i = 0; i < 8; i++) {
            nonce[11 - i] ^= uint8_t(s & 0xFF);
            s >>= 8;
        }

        constexpr size_t TAG_LEN = 16;
        const size_t ct_len = inner.size();
        const size_t rec_payload_len = ct_len + TAG_LEN;

        uint8_t hdr[5];
        hdr[0] = 0x17;
        hdr[1] = 0x03;
        hdr[2] = 0x03;
        hdr[3] = uint8_t(rec_payload_len >> 8);
        hdr[4] = uint8_t(rec_payload_len & 0xFF);

        std::vector<uint8_t> ct(ct_len);
        uint8_t tag16[16];

        bool ok = aead->aes_gcm_encrypt(
            nonce, hdr, sizeof(hdr),
            inner.data(), inner.size(),
            ct.data(), tag16
        );

        if (!ok)
            throwSSL(NetException::Error, "TLS1.3 send_record: AES-GCM encrypt failed");

        std::vector<uint8_t> rec;
        rec.reserve(5 + rec_payload_len);
        rec.insert(rec.end(), hdr, hdr + 5);
        rec.insert(rec.end(), ct.begin(), ct.end());
        rec.insert(rec.end(), tag16, tag16 + 16);

        queueRaw(rec);
        (*seqp)++;
    }

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
    void tls::tls13_send_handshake(uint8_t hs_type,
                                   const std::vector<uint8_t>& hs_body,
                                   bool handshake_keys)
    {
        std::vector<uint8_t> msg;
        msg.reserve(4 + hs_body.size());
        msg.push_back(hs_type);
        uint32_t L = (uint32_t)hs_body.size();
        msg.push_back(uint8_t((L >> 16) & 0xFF));
        msg.push_back(uint8_t((L >>  8) & 0xFF));
        msg.push_back(uint8_t((L >>  0) & 0xFF));
        msg.insert(msg.end(), hs_body.begin(), hs_body.end());

        // transcript includes plaintext handshake
        handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());

        // inner content type must be HANDSHAKE (0x16)
        tls13_send_record(0x16, msg, handshake_keys);
    }
#pragma GCC diagnostic pop

    // =================================================================
    // TLS 1.3 Certificate and Verify
    // =================================================================

    std::vector<uint8_t> tls::tls13_build_certificate()
    {
        // Always use selected bundle's cert
        if (!selected_cert_bundle || selected_cert_bundle->cert.derData().empty())
            throw std::runtime_error("TLS1.3: no certificate loaded");

        const auto& rawCert = selected_cert_bundle->cert.derData();
        uint32_t certLen = (uint32_t)rawCert.size();

        // Calculate total certificate_list length:
        // leaf entry = cert_len(3) + cert + ext_len(2)
        uint32_t listLen = 3 + certLen + 2;
        // chain entries: each = cert_len(3) + cert_data + ext_len(2)
        for (const auto& chainCert : selected_cert_bundle->chain) {
            listLen += 3 + (uint32_t)chainCert.size() + 2;
        }

        std::vector<uint8_t> out;
        out.reserve(1 + 3 + listLen);

        // certificate_request_context length (0)
        out.push_back(0x00);

        // certificate_list length (3 bytes)
        out.push_back((listLen >> 16) & 0xFF);
        out.push_back((listLen >>  8) & 0xFF);
        out.push_back((listLen >>  0) & 0xFF);

        // Leaf certificate entry
        out.push_back((certLen >> 16) & 0xFF);
        out.push_back((certLen >>  8) & 0xFF);
        out.push_back((certLen >>  0) & 0xFF);
        out.insert(out.end(), rawCert.begin(), rawCert.end());
        out.push_back(0x00);  // extensions length (2 bytes)
        out.push_back(0x00);

        // Chain certificate entries (intermediate/root CA certs)
        for (const auto& chainCert : selected_cert_bundle->chain) {
            uint32_t ccLen = (uint32_t)chainCert.size();
            out.push_back((ccLen >> 16) & 0xFF);
            out.push_back((ccLen >>  8) & 0xFF);
            out.push_back((ccLen >>  0) & 0xFF);
            out.insert(out.end(), chainCert.begin(), chainCert.end());
            out.push_back(0x00);  // extensions length (2 bytes)
            out.push_back(0x00);
        }

        return out;
    }

    std::vector<uint8_t> tls::tls13_build_certificate_verify()
    {
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::tls13_build_certificate_verify: " << msg;
            throw e;
        };

        // RFC 8446: Transcript hash must use the cipher suite's hash function
        std::vector<uint8_t> th;
        if (chosenSuite == 0x1302) {
            th = sha384_hash(handshake_transcript);
        } else {
            th = sha256_hash(handshake_transcript);
        }

        std::vector<uint8_t> toSign;
        toSign.reserve(64 + 34 + 1 + th.size());
        toSign.resize(64, 0x20);
        const char* ctx = "TLS 1.3, server CertificateVerify";
        toSign.insert(toSign.end(), ctx, ctx + std::strlen(ctx));
        toSign.push_back(0x00);
        toSign.insert(toSign.end(), th.begin(), th.end());

        std::vector<uint8_t> sig;
        std::vector<uint8_t> cv;

        // Ensure RSA key is loaded from privateKeyDer if not already
        if (selected_cert_bundle && !selected_cert_bundle->rsa_key && !selected_cert_bundle->privateKeyDer.empty()) {
            try {
                selected_cert_bundle->rsa_key = netplus::rsa(selected_cert_bundle->privateKeyDer);
            } catch (const std::exception& e) {
                // Warning: Failed to load RSA key
            }
        }
        
        if (selected_cert_bundle && selected_cert_bundle->rsa_key) {
            // For TLS 1.3, we MUST use RSA-PSS-RSAE-SHA256 (0x0804)
            sig = sign_rsa_pss_sha256(toSign, selected_cert_bundle->rsa_key);
            if (sig.empty())
                throwSSL(NetException::Error, "TLS1.3 CertificateVerify: RSA-PSS signature empty");

            cv.push_back(0x08); cv.push_back(0x04);  // rsa_pss_rsae_sha256
        } else if (has_ec_key) {
            // Use ECDSA-SHA256 with P-256 curve (0x0403)
            std::vector<uint8_t> ecPriv(ec_priv, ec_priv + 32);
            sig = sign_ecdsa_sha256(toSign, ecPriv);
            if (sig.empty())
                throwSSL(NetException::Error, "TLS1.3 CertificateVerify: ECDSA signature empty");
            cv.push_back(0x04); cv.push_back(0x03);  // ecdsa_secp256r1_sha256
        } else {
            throwSSL(NetException::Error, "TLS1.3 CertificateVerify: no private key available");
        }

        cv.push_back(uint8_t(sig.size() >> 8));
        cv.push_back(uint8_t(sig.size() & 0xFF));
        cv.insert(cv.end(), sig.begin(), sig.end());

        return cv;
    }

    std::vector<uint8_t> tls::tls13_build_server_finished() {
        // RFC 8446: Transcript hash and finished MAC must use the cipher suite's hash function
        std::vector<uint8_t> th;
        size_t hash_len;
        if (chosenSuite == 0x1302) {
            th = sha384_hash(handshake_transcript);
            hash_len = 48;
        } else {
            th = sha256_hash(handshake_transcript);
            hash_len = 32;
        }

        std::vector<uint8_t> empty;
        std::vector<uint8_t> finished_key =
            hkdf_expand_label(tls13_s_hs_secret, "finished", empty, hash_len, chosenSuite);

        std::vector<uint8_t> verify_data;
        if (chosenSuite == 0x1302) {
            verify_data = hmac_sha384(finished_key, th);
        } else {
            verify_data = hmac_sha256(finished_key, th);
        }

        return verify_data;
    }

    // =================================================================
    // TLS 1.3 Key Derivation (Application Keys)
    // =================================================================

    void tls::tls13_derive_application_keys(){
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::tls13_derive_application_keys: " << msg;
            throw e;
        };

        // transcript hash up to server Finished included
        std::vector<uint8_t> th;
        std::vector<uint8_t> empty_hash;
        size_t hash_size;
        
        if (chosenSuite == 0x1302) {
            th = sha384_hash(handshake_transcript);
            empty_hash = sha384_hash({});
            hash_size = 48;
        } else {
            th = sha256_hash(handshake_transcript);
            empty_hash = sha256_hash({});
            hash_size = 32;
        }

        // derived_secret = HKDF-Expand-Label(handshake_secret, "derived", Hash(""), hash_size)
        std::vector<uint8_t> derived_secret =
            hkdf_expand_label(tls13_hs_secret, "derived", empty_hash, hash_size, chosenSuite);

        if (derived_secret.size() != hash_size)
            throwSSL(NetException::Error, "TLS1.3 derive: derived_secret wrong size");

        // master_secret = HKDF-Extract(derived_secret, 0^hash_size)
        std::vector<uint8_t> zero(hash_size, 0x00);
        std::vector<uint8_t> master_secret = hkdf_extract(derived_secret, zero, chosenSuite);

        if (master_secret.size() != hash_size)
            throwSSL(NetException::Error, "TLS1.3 derive: master_secret wrong size");

        // server/client application traffic secrets
        tls13_s_ap_secret = hkdf_expand_label(master_secret, "s ap traffic", th, hash_size, chosenSuite);
        tls13_c_ap_secret = hkdf_expand_label(master_secret, "c ap traffic", th, hash_size, chosenSuite);

        auto derive_key_iv = [&](const std::vector<uint8_t>& secret,
                                 std::vector<uint8_t>& out_key,
                                 std::vector<uint8_t>& out_iv,
                                 size_t key_size = 16)
        {
            out_key = hkdf_expand_label(secret, "key", {}, key_size, chosenSuite);
            out_iv  = hkdf_expand_label(secret, "iv",  {}, 12, chosenSuite);

            if (out_key.size() != key_size || out_iv.size() != 12)
                throwSSL(NetException::Error, "TLS1.3 derive: key/iv wrong size");
        };

        // Determine key size based on cipher suite
        size_t key_size = 16;
        if (chosenSuite == 0x1302) {
            key_size = 32;
        }

        std::vector<uint8_t> send_key, send_iv;
        std::vector<uint8_t> recv_key, recv_iv;

        if (is_client) {
            // client: send=c_ap, recv=s_ap
            derive_key_iv(tls13_c_ap_secret, send_key, send_iv, key_size);
            derive_key_iv(tls13_s_ap_secret, recv_key, recv_iv, key_size);

            if (chosenSuite == 0x1302) {
                aes13_app_send.reset(new aes256(send_key));
                aes13_app_recv.reset(new aes256(recv_key));
            } else {
                aes13_app_send.reset(new aes128(send_key));
                aes13_app_recv.reset(new aes128(recv_key));
            }

            std::memcpy(tls13_app_iv_c2s, send_iv.data(), 12);
            std::memcpy(tls13_app_iv_s2c, recv_iv.data(), 12);
        } else {
            // server: send=s_ap, recv=c_ap
            derive_key_iv(tls13_s_ap_secret, send_key, send_iv, key_size);
            derive_key_iv(tls13_c_ap_secret, recv_key, recv_iv, key_size);

            if (chosenSuite == 0x1302) {
                aes13_app_send.reset(new aes256(send_key));
                aes13_app_recv.reset(new aes256(recv_key));
            } else {
                aes13_app_send.reset(new aes128(send_key));
                aes13_app_recv.reset(new aes128(recv_key));
            }

            std::memcpy(tls13_app_iv_s2c, send_iv.data(), 12);
            std::memcpy(tls13_app_iv_c2s, recv_iv.data(), 12);
        }

        // reset app seq numbers
        tls13_app_send_seq = 0;
        tls13_app_recv_seq = 0;
    }

    // =================================================================
    // TLS 1.3 Transcript
    // =================================================================

    void tls::tls13_transcript_add_raw(const std::vector<uint8_t>& hsmsg){
        handshake_transcript.insert(handshake_transcript.end(), hsmsg.begin(), hsmsg.end());
    }

    // =================================================================
    // TLS 1.3 Client Hello and Finished
    // =================================================================

    void tls::queueClientHello() {
        // Build ClientHello message body
        std::vector<uint8_t> ch;

        // Legacy version (TLS 1.2)
        ch.push_back(0x03);
        ch.push_back(0x03);

        // Client random (32 bytes)
        clientRandom.resize(32);
        fillRandomBytes(clientRandom.data(), 32);
        ch.insert(ch.end(), clientRandom.begin(), clientRandom.end());

        // Session ID — use saved session_id for resumption, else random for middlebox compat
        if (attempt_resumption && !resumption_session_id.empty()) {
            client_session_id = resumption_session_id;
        } else {
            client_session_id.resize(32);
            fillRandomBytes(client_session_id.data(), 32);
        }
        ch.push_back(uint8_t(client_session_id.size()));
        ch.insert(ch.end(), client_session_id.begin(), client_session_id.end());

        // Cipher suites: TLS 1.3 + TLS 1.2
        std::vector<uint16_t> suites = {0x1301, 0x1302, 0x002F, 0x0035};
        ch.push_back(uint8_t((suites.size() * 2) >> 8));
        ch.push_back(uint8_t((suites.size() * 2) & 0xFF));
        for (uint16_t s : suites) {
            ch.push_back(uint8_t(s >> 8));
            ch.push_back(uint8_t(s & 0xFF));
        }

        // Compression methods (null only)
        ch.push_back(0x01);
        ch.push_back(0x00);

        // ---- Extensions ----
        std::vector<uint8_t> exts;

        // 1) SNI (Server Name Indication) - if hostname is not an IP
        if (!hostname.empty()) {
            // Check if it looks like an IP address (contains only digits and dots or colons)
            bool isIP = true;
            for (char c : hostname) {
                if (!std::isdigit(c) && c != '.' && c != ':') {
                    isIP = false;
                    break;
                }
            }
            if (!isIP) {
                std::vector<uint8_t> sni;
                // server_name_list length (2 bytes)
                uint16_t name_entry_len = 1 + 2 + hostname.size(); // type(1) + len(2) + name
                sni.push_back(uint8_t(name_entry_len >> 8));
                sni.push_back(uint8_t(name_entry_len & 0xFF));
                // name type: host_name (0)
                sni.push_back(0x00);
                // host name length
                sni.push_back(uint8_t(hostname.size() >> 8));
                sni.push_back(uint8_t(hostname.size() & 0xFF));
                sni.insert(sni.end(), hostname.begin(), hostname.end());

                // extension header: type 0x0000, length
                exts.push_back(0x00); exts.push_back(0x00);
                exts.push_back(uint8_t(sni.size() >> 8));
                exts.push_back(uint8_t(sni.size() & 0xFF));
                exts.insert(exts.end(), sni.begin(), sni.end());
            }
        }

        // 2) supported_versions extension (TLS 1.3 + TLS 1.2)
        {
            exts.push_back(0x00); exts.push_back(0x2b); // type
            exts.push_back(0x00); exts.push_back(0x05); // length = 5
            exts.push_back(0x04);                        // versions length = 4
            exts.push_back(0x03); exts.push_back(0x04);  // TLS 1.3
            exts.push_back(0x03); exts.push_back(0x03);  // TLS 1.2
        }

        // 3) supported_groups extension (X25519 + secp256r1)
        {
            exts.push_back(0x00); exts.push_back(0x0a); // type
            exts.push_back(0x00); exts.push_back(0x06); // length = 6
            exts.push_back(0x00); exts.push_back(0x04); // named_group_list length = 4
            exts.push_back(0x00); exts.push_back(0x1d); // x25519
            exts.push_back(0x00); exts.push_back(0x17); // secp256r1
        }

        // 4) signature_algorithms extension
        {
            // rsa_pss_rsae_sha256 (0x0804), rsa_pkcs1_sha256 (0x0401),
            // ecdsa_secp256r1_sha256 (0x0403), rsa_pss_rsae_sha384 (0x0805)
            exts.push_back(0x00); exts.push_back(0x0d); // type
            exts.push_back(0x00); exts.push_back(0x0a); // length = 10
            exts.push_back(0x00); exts.push_back(0x08); // sig_alg_list length = 8
            exts.push_back(0x08); exts.push_back(0x04); // rsa_pss_rsae_sha256
            exts.push_back(0x04); exts.push_back(0x01); // rsa_pkcs1_sha256
            exts.push_back(0x04); exts.push_back(0x03); // ecdsa_secp256r1_sha256
            exts.push_back(0x08); exts.push_back(0x05); // rsa_pss_rsae_sha384
        }

        // 5) key_share extension (X25519 + P-256)
        {
            // Generate X25519 ephemeral key pair
            client_priv_x25519.resize(32);
            fillRandomBytes(client_priv_x25519.data(), 32);
            std::vector<uint8_t> x25519_pub;
            if (!netplus::scalarmult_curve25519_base(x25519_pub, client_priv_x25519)) {
                throw std::runtime_error("X25519 base scalar mult failed");
            }

            // Generate P-256 ephemeral key pair
            for (int retry = 0; retry < 100; ++retry) {
                fillRandomBytes(client_priv_ecdhe, 32);
                bool allZero = true;
                for (int j = 0; j < 32; j++) if (client_priv_ecdhe[j]) { allZero = false; break; }
                if (allZero) continue;
                u256 k = bytes_be_to_u256(client_priv_ecdhe);
                if (u256_cmp(k, P256_N) < 0) break;
            }
            netplus::P256Point cli_pub_pt = netplus::scalar_mul_G(client_priv_ecdhe);
            std::vector<uint8_t> p256_pub = netplus::encode_tls_point(cli_pub_pt); // 65 bytes (0x04 + x + y)

            // Build key_share entries
            std::vector<uint8_t> shares;
            // X25519 entry: group(2) + key_len(2) + key(32)
            shares.push_back(0x00); shares.push_back(0x1d); // x25519
            shares.push_back(0x00); shares.push_back(0x20); // 32 bytes
            shares.insert(shares.end(), x25519_pub.begin(), x25519_pub.end());
            // P-256 entry: group(2) + key_len(2) + key(65)
            shares.push_back(0x00); shares.push_back(0x17); // secp256r1
            shares.push_back(0x00); shares.push_back(uint8_t(p256_pub.size()));
            shares.insert(shares.end(), p256_pub.begin(), p256_pub.end());

            // key_share extension: type(2) + ext_len(2) + client_shares_len(2) + shares
            uint16_t shares_len = uint16_t(shares.size());
            uint16_t ext_data_len = 2 + shares_len;
            exts.push_back(0x00); exts.push_back(0x33); // type = key_share
            exts.push_back(uint8_t(ext_data_len >> 8)); exts.push_back(uint8_t(ext_data_len & 0xFF));
            exts.push_back(uint8_t(shares_len >> 8)); exts.push_back(uint8_t(shares_len & 0xFF));
            exts.insert(exts.end(), shares.begin(), shares.end());
        }

        // Mark that we offered TLS 1.3
        client_offered_tls13 = true;

        // Extensions length
        ch.push_back(uint8_t(exts.size() >> 8));
        ch.push_back(uint8_t(exts.size() & 0xFF));
        ch.insert(ch.end(), exts.begin(), exts.end());

        // Send as handshake (adds to transcript and queues TLS record)
        sendHandshake(0x01, ch);
    }

    void tls::tls13_send_finished(bool handshake_keys){
        auto throwSSL = [&](int type, const std::string& msg) {
            netplus::NetException e;
            e[type] << "tls::tls13_send_finished: " << msg;
            throw e;
        };

        if (!handshake_keys)
            throwSSL(NetException::Error, "TLS1.3 send_finished called with handshake_keys=false");

        // RFC 8446: Transcript hash and finished MAC must use the cipher suite's hash function
        std::vector<uint8_t> th;
        size_t hash_len;
        if (chosenSuite == 0x1302) {
            th = sha384_hash(handshake_transcript);
            hash_len = 48;
        } else {
            th = sha256_hash(handshake_transcript);
            hash_len = 32;
        }
        if (th.size() != hash_len)
            throwSSL(NetException::Error, "TLS1.3 Finished: transcript hash wrong size");

        // 2) finished_key = HKDF-Expand-Label(s_hs_secret, "finished", "", hash_len)
        std::vector<uint8_t> finished_key = hkdf_expand_label(
            tls13_s_hs_secret,
            "finished",
            std::vector<uint8_t>{},
            hash_len,
            chosenSuite
        );
        if (finished_key.size() != hash_len)
            throwSSL(NetException::Error, "TLS1.3 Finished: finished_key wrong size");

        // 3) verify_data = HMAC(finished_key, transcript_hash)
        std::vector<uint8_t> verify_data;
        if (chosenSuite == 0x1302) {
            verify_data = hmac_sha384(finished_key, th);
        } else {
            verify_data = hmac_sha256(finished_key, th);
        }
        if (verify_data.size() != hash_len)
            throwSSL(NetException::Error, "TLS1.3 Finished: verify_data wrong size");

        // 4) Send Finished message using tls13_send_handshake
        tls13_send_handshake(0x14, verify_data, handshake_keys);
    }

    // ---- CertificateBundle::loadFromFile ----
    // Auto-detect format by file extension:
    //   .p12/.pfx  → PKCS#12 (certPath only)
    //   everything else → PEM or DER with auto-detection
    bool tls::CertificateBundle::loadFromFile(const std::string& certPath,
                                               const std::string& keyPath,
                                               const std::string& password) {
        // Helper: get lowercase extension
        auto getExt = [](const std::string& path) -> std::string {
            auto dot = path.rfind('.');
            if (dot == std::string::npos) return "";
            std::string ext = path.substr(dot);
            for (auto& c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
            return ext;
        };

        std::string ext = getExt(certPath);

        if (ext == ".p12" || ext == ".pfx") {
            // PKCS#12: single file contains cert + key (+ optional chain)
            Pkcs12Result p12;
            if (!pkcs12ParseFile(certPath, password, p12))
                return false;

            if (!p12.certDer.empty()) {
                if (!cert.loadFromBuffer(std::move(p12.certDer)))
                    return false;
            }
            chain = std::move(p12.chainDer);

            if (!p12.keyDer.empty()) {
                privateKeyDer = p12.keyDer;
                rsa_key = netplus::rsa(p12.keyDer);
            }
            return true;
        }

        // PEM / DER cert file (auto-detected inside loadFromFile / loadAllFromPem)
        if (ext == ".pem") {
            // PEM may contain multiple certs (chain)
            if (!cert.loadAllFromPem(certPath, chain))
                return false;
        } else {
            // .crt, .cer, .der, or any other extension
            if (!cert.loadFromFile(certPath))
                return false;
        }

        // Load private key
        std::string kp = keyPath.empty() ? certPath : keyPath;
        std::string kext = getExt(kp);

        std::ifstream keyFile(kp, std::ios::binary | std::ios::ate);
        if (!keyFile.is_open()) return false;

        std::streamsize ksize = keyFile.tellg();
        if (ksize <= 0) return false;
        keyFile.seekg(0, std::ios::beg);

        std::vector<uint8_t> keyData(static_cast<size_t>(ksize));
        if (!keyFile.read(reinterpret_cast<char*>(keyData.data()), ksize))
            return false;

        privateKeyDer = keyData;
        rsa_key = netplus::rsa(keyData);  // auto-detects PEM vs DER
        return true;
    }

} // namespace netplus
