Commit caaaf9a7 authored by jan.koester's avatar jan.koester
Browse files

aes 256 sha 384 works now

parent 53dfa48e
Loading
Loading
Loading
Loading
+92 −36
Original line number Diff line number Diff line
@@ -1508,8 +1508,15 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_certificate()

std::vector<uint8_t> netplus::ssl::_tls13_build_certificate_verify()
{
    // transcript hash up to Certificate (inclusive!)
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    // RFC 8446: Transcript hash must use the cipher suite's hash function
    // For 0x1302 (AES-256-GCM-SHA384), use SHA384
    // For 0x1301 (AES-128-GCM-SHA256), use SHA256
    std::vector<uint8_t> th;
    if (_chosenSuite == 0x1302) {
        th = sha384_hash(_handshake_transcript);  // SHA384 for AES-256
    } else {
        th = sha256_hash(_handshake_transcript);  // SHA256 for AES-128
    }

    std::vector<uint8_t> toSign(64, 0x20);
    const char* ctx = "TLS 1.3, server CertificateVerify";
@@ -1613,25 +1620,29 @@ static inline void dumpServerHelloStructure(const std::vector<uint8_t>&) {}

void netplus::ssl::_tls13_derive_application_keys(){
    // transcript hash up to server Finished included
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    // RFC 8446: Use cipher suite's hash function
    std::vector<uint8_t> th;
    std::vector<uint8_t> empty_hash;
    size_t hash_size;  // Determine hash size based on cipher suite
    
    // SHA-256 hash of empty string - needed for "derived" context per RFC 8446
    std::vector<uint8_t> empty_hash = sha256_hash({});
    if (_chosenSuite == 0x1302) {
        th = sha384_hash(_handshake_transcript);
        empty_hash = sha384_hash({});
        hash_size = 48;  // SHA384
    } else {
        th = sha256_hash(_handshake_transcript);
        empty_hash = sha256_hash({});
        hash_size = 32;  // SHA256
    }

    // derived_secret = HKDF-Expand-Label(handshake_secret, "derived", SHA256(""), 32)
    // RFC 8446: Derive-Secret uses Transcript-Hash(Messages), for empty messages that's SHA256("")
    // derived_secret = HKDF-Expand-Label(handshake_secret, "derived", SHA256(""), hash_size)
    // RFC 8446: Derive-Secret uses Transcript-Hash(Messages), for empty messages that's Hash("")
    std::vector<uint8_t> derived_secret =
        _hkdf_expand_label(_tls13_hs_secret, "derived", empty_hash, 32);
        _hkdf_expand_label(_tls13_hs_secret, "derived", empty_hash, hash_size);

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

    // Determine hash size based on cipher suite
    size_t hash_size = 32;  // SHA256
    if (_chosenSuite == 0x1302) {
        hash_size = 48;  // SHA384
    }

    // 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);
@@ -1706,24 +1717,39 @@ void netplus::ssl::_tls13_send_finished(bool handshake_keys){
    if (!handshake_keys)
        throwSSL(NetException::Error, "TLS1.3 send_finished called with handshake_keys=false");

    // 1) transcript hash bis jetzt (CH..CV)
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    if (th.size() != 32)
    // RFC 8446: Transcript hash and finished MAC must use the cipher suite's hash function
    // For 0x1302 (AES-256-GCM-SHA384), use SHA384 (48-byte output)
    // For 0x1301 (AES-128-GCM-SHA256), use SHA256 (32-byte output)
    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", "", 32)
    // 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>{},
        32
        hash_len
    );
    if (finished_key.size() != 32)
    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 = _hmac_sha256(finished_key, th);
    if (verify_data.size() != 32)
    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) Finished Handshake senden (type 0x14)
@@ -2611,7 +2637,16 @@ void netplus::ssl::handshake_after_accept(){

            // ⚠️ Save transcript hash BEFORE fetching client Finished
            // The client computes its Finished over CH..server_Finished (not including client Finished)
            std::vector<uint8_t> th_before_client_finished = sha256_hash(_handshake_transcript);
            // 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
@@ -2633,23 +2668,28 @@ void netplus::ssl::handshake_after_accept(){
            if (ht != 0x14)
                throwSSL(NetException::Error, "TLS1.3 expected Finished from client");

            if (len != 32 || msg.size() != 4 + 32)
            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", "", 32)
            // 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>{},
                32
                hash_len
            );
            if (finished_key.size() != 32)
            if (finished_key.size() != hash_len)
                throwSSL(NetException::Error, "TLS1.3 Finished: finished_key wrong size");

            std::vector<uint8_t> expected = _hmac_sha256(finished_key, th_before_client_finished);
            if (expected.size() != 32)
            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)
@@ -2660,7 +2700,7 @@ void netplus::ssl::handshake_after_accept(){
            client_finished_msg.push_back(0x14);  // Finished type
            client_finished_msg.push_back(0x00);
            client_finished_msg.push_back(0x00);
            client_finished_msg.push_back(0x20);  // length = 32
            client_finished_msg.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(),
@@ -4827,15 +4867,31 @@ bool netplus::ssl::_tls13_recv_record(
}

std::vector<uint8_t> netplus::ssl::_tls13_build_server_finished() {
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    // RFC 8446: Transcript hash and finished MAC must use the cipher suite's hash function
    // For 0x1302 (AES-256-GCM-SHA384), use SHA384 (48-byte output)
    // For 0x1301 (AES-128-GCM-SHA256), use SHA256 (32-byte output)
    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, 32);
        _hkdf_expand_label(_tls13_s_hs_secret, "finished", empty, hash_len);

    std::vector<uint8_t> verify_data = _hmac_sha256(finished_key, th);
    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 just the verify_data (32 bytes)
    // Return just the verify_data (32 or 48 bytes depending on cipher suite)
    // The handshake header (type + len24) is added by _tls13_send_handshake
    return verify_data;
}
+105 −36
Original line number Diff line number Diff line
@@ -1387,7 +1387,15 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_certificate()
std::vector<uint8_t> netplus::ssl::_tls13_build_certificate_verify()
{
    // transcript hash up to Certificate (inclusive!)
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    // RFC 8446: Transcript hash must use the cipher suite's hash function
    // For 0x1302 (AES-256-GCM-SHA384), use SHA384
    // For 0x1301 (AES-128-GCM-SHA256), use SHA256
    std::vector<uint8_t> th;
    if (_chosenSuite == 0x1302) {
        th = sha384_hash(_handshake_transcript);  // SHA384 for AES-256
    } else {
        th = sha256_hash(_handshake_transcript);  // SHA256 for AES-128
    }

    std::vector<uint8_t> toSign(64, 0x20);
    const char* ctx = "TLS 1.3, server CertificateVerify";
@@ -1491,38 +1499,54 @@ static inline void dumpServerHelloStructure(const std::vector<uint8_t>&) {}

void netplus::ssl::_tls13_derive_application_keys(){
    // transcript hash up to server Finished included
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);

    // SHA-256 hash of empty string - needed for "derived" context per RFC 8446
    std::vector<uint8_t> empty_hash = sha256_hash({});
    // RFC 8446: Use cipher suite's hash function
    std::vector<uint8_t> th;
    std::vector<uint8_t> empty_hash;
    size_t hash_size;  // Determine hash size based on cipher suite
    
    if (_chosenSuite == 0x1302) {
        th = sha384_hash(_handshake_transcript);
        empty_hash = sha384_hash({});
        hash_size = 48;  // SHA384
    } else {
        th = sha256_hash(_handshake_transcript);
        empty_hash = sha256_hash({});
        hash_size = 32;  // SHA256
    }

    // derived_secret = HKDF-Expand-Label(handshake_secret, "derived", SHA256(""), 32)
    // RFC 8446: Derive-Secret uses Transcript-Hash(Messages), for empty messages that's SHA256("")
    // derived_secret = HKDF-Expand-Label(handshake_secret, "derived", Hash(""), hash_size)
    // RFC 8446: Derive-Secret uses Transcript-Hash(Messages), for empty messages that's Hash("")
    std::vector<uint8_t> derived_secret =
        _hkdf_expand_label(_tls13_hs_secret, "derived", empty_hash, 32);
        _hkdf_expand_label(_tls13_hs_secret, "derived", empty_hash, hash_size);

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

    // master_secret = HKDF-Extract(derived_secret, 0^32)
    std::vector<uint8_t> zero(32, 0x00);
    // 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);

    if (master_secret.size() != 32)
    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, 32);
    _tls13_c_ap_secret = _hkdf_expand_label(master_secret, "c ap traffic", th, 32);
    _tls13_s_ap_secret = _hkdf_expand_label(master_secret, "s ap traffic", th, hash_size);
    _tls13_c_ap_secret = _hkdf_expand_label(master_secret, "c ap traffic", th, hash_size);

    // Determine key size based on cipher suite
    size_t key_size = 16; // default to AES-128 (16 bytes)
    if (_chosenSuite == 0x1302) {
        key_size = 32; // AES-256 (32 bytes)
    }

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

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

@@ -1561,24 +1585,39 @@ void netplus::ssl::_tls13_send_finished(bool handshake_keys){
    if (!handshake_keys)
        throwSSL(NetException::Error, "TLS1.3 send_finished called with handshake_keys=false");

    // 1) transcript hash bis jetzt (CH..CV)
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    if (th.size() != 32)
    // RFC 8446: Transcript hash and finished MAC must use the cipher suite's hash function
    // For 0x1302 (AES-256-GCM-SHA384), use SHA384 (48-byte output)
    // For 0x1301 (AES-128-GCM-SHA256), use SHA256 (32-byte output)
    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", "", 32)
    // 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>{},
        32
        hash_len
    );
    if (finished_key.size() != 32)
    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 = _hmac_sha256(finished_key, th);
    if (verify_data.size() != 32)
    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) Finished Handshake senden (type 0x14)
@@ -2421,7 +2460,16 @@ void netplus::ssl::handshake_after_accept(){

            // ⚠️ Save transcript hash BEFORE fetching client Finished
            // The client computes its Finished over CH..server_Finished (not including client Finished)
            std::vector<uint8_t> th_before_client_finished = sha256_hash(_handshake_transcript);
            // 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
@@ -2443,23 +2491,28 @@ void netplus::ssl::handshake_after_accept(){
            if (ht != 0x14)
                throwSSL(NetException::Error, "TLS1.3 expected Finished from client");

            if (len != 32 || msg.size() != 4 + 32)
            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", "", 32)
            // 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>{},
                32
                hash_len
            );
            if (finished_key.size() != 32)
            if (finished_key.size() != hash_len)
                throwSSL(NetException::Error, "TLS1.3 Finished: finished_key wrong size");

            std::vector<uint8_t> expected = _hmac_sha256(finished_key, th_before_client_finished);
            if (expected.size() != 32)
            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)
@@ -2470,7 +2523,7 @@ void netplus::ssl::handshake_after_accept(){
            client_finished_msg.push_back(0x14);  // Finished type
            client_finished_msg.push_back(0x00);
            client_finished_msg.push_back(0x00);
            client_finished_msg.push_back(0x20);  // length = 32
            client_finished_msg.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(),
@@ -4618,15 +4671,31 @@ bool netplus::ssl::_tls13_recv_record(
}

std::vector<uint8_t> netplus::ssl::_tls13_build_server_finished() {
    std::vector<uint8_t> th = sha256_hash(_handshake_transcript);
    // RFC 8446: Transcript hash and finished MAC must use the cipher suite's hash function
    // For 0x1302 (AES-256-GCM-SHA384), use SHA384 (48-byte output)
    // For 0x1301 (AES-128-GCM-SHA256), use SHA256 (32-byte output)
    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, 32);
        _hkdf_expand_label(_tls13_s_hs_secret, "finished", empty, hash_len);

    std::vector<uint8_t> verify_data = _hmac_sha256(finished_key, th);
    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 just the verify_data (32 bytes)
    // Return just the verify_data (32 or 48 bytes depending on cipher suite)
    // The handshake header (type + len24) is added by _tls13_send_handshake
    return verify_data;
}