Loading src/socket.h +5 −2 Original line number Diff line number Diff line Loading @@ -500,7 +500,6 @@ namespace netplus { std::vector<uint8_t> _tls13_client_keyshare; //debug std::vector<uint8_t> _tls13_ecdhe_shared; // 32 bytes shared secret bool _tls13_got_key_share = false; netplus::x509cert _peer_cert; Loading Loading @@ -608,11 +607,15 @@ namespace netplus { std::vector<uint8_t> _server_keyshare_x25519; std::vector<uint8_t> _server_priv_x25519; std::vector<uint8_t> _server_pub_x25519; std::vector<uint8_t> _client_priv_x25519; std::vector<uint8_t> _x25519_shared; std::vector<uint8_t> _client_keyshare_ecdhe; std::vector<uint8_t> _server_keyshare_ecdhe; uint8_t _client_priv_ecdhe[32] = {0}; // client ephemeral scalar (BE) uint8_t _server_priv_ecdhe[32] = {0}; // server ephemeral scalar (BE) uint8_t _server_priv_ecdhe[32] = {0}; std::vector<uint8_t> _ecdhe_shared; // 32 bytes shared secret // server ephemeral scalar (BE) enum class HsState { // server READ_CLIENT_HELLO, Loading src/ssl.cpp +125 −66 Original line number Diff line number Diff line Loading @@ -2136,7 +2136,43 @@ void netplus::ssl::handshake_after_accept(){ const uint8_t* key = ep + 4; if (group == 0x0017) { // P-256 // --------------------------------------------------------- // ✅ 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"; Loading @@ -2152,16 +2188,22 @@ void netplus::ssl::handshake_after_accept(){ throw e; } uint8_t shared32[32]; if (!netplus::ecdh_shared_secret(shared32, _client_priv_ecdhe, srv_pub)) { 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; } _tls13_ecdhe_shared.assign(shared32, shared32 + 32); _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; Loading Loading @@ -2516,7 +2558,6 @@ void netplus::ssl::handshake_after_accept(){ } case HsState::TLS13_SEND_ENCRYPTED_FLIGHT: { if (!_tls13_encflight_queued) { TLSDBG("[DEBUG] TLS 1.3: Preparing EncryptedExtensions"); if (!_aes13_hs_send || !_aes13_hs_recv) Loading @@ -2526,46 +2567,31 @@ void netplus::ssl::handshake_after_accept(){ std::vector<uint8_t> ee = {0x00, 0x00}; TLSDBG("[DEBUG] TLS 1.3: Sending EncryptedExtensions"); _tls13_send_handshake(0x08, ee, true); std::vector<uint8_t> th_ee = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after EncryptedExtensions: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_ee) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; // ---- 2) Certificate ---- TLSDBG("[DEBUG] TLS 1.3: Preparing Certificate"); std::vector<uint8_t> cert = _tls13_build_certificate(); TLSDBG("[DEBUG] TLS 1.3: Sending Certificate, size=" << cert.size()); _tls13_send_handshake(0x0b, cert, true); std::vector<uint8_t> th_cert = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after Certificate: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_cert) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; // ---- 3) CertificateVerify ---- TLSDBG("[DEBUG] TLS 1.3: Preparing CertificateVerify"); std::vector<uint8_t> cv = _tls13_build_certificate_verify(); TLSDBG("[DEBUG] TLS 1.3: Sending CertificateVerify, size=" << cv.size()); _tls13_send_handshake(0x0f, cv, true); std::vector<uint8_t> th_cv = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after CertificateVerify: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_cv) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; // ---- 4) Finished ---- TLSDBG("[DEBUG] TLS 1.3: Preparing Finished"); std::vector<uint8_t> fin = _tls13_build_server_finished(); TLSDBG("[DEBUG] TLS 1.3: Sending Finished, size=" << fin.size()); // Must append Finished to transcript BEFORE deriving app keys // (either _tls13_send_handshake does it internally, or do it here explicitly) // This returns verify_data (32 bytes) only std::vector<uint8_t> fin_body = _tls13_build_server_finished_body(); _tls13_send_handshake(0x14, fin, true); std::vector<uint8_t> th_fin = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after Finished: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_fin) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; TLSDBG("[DEBUG] TLS 1.3: Sending Finished, verify_data size=" << fin_body.size()); // Send handshake msg type=0x14 with body=verify_data _tls13_send_handshake(0x14, fin_body, true); // ---- 5) derive application keys AFTER transcript includes server Finished ---- // ---- 5) derive application keys AFTER Finished is in transcript ---- TLSDBG("[DEBUG] TLS 1.3: Deriving application keys"); _tls13_derive_application_keys(); Loading @@ -2586,8 +2612,6 @@ void netplus::ssl::handshake_after_accept(){ return; } case HsState::FAIL:{ NetException e; e[NetException::Error] << "Handshake Failed"; Loading @@ -2612,9 +2636,9 @@ void netplus::ssl::handshake_after_accept(){ _selected_group = use_x25519 ? 0x001d : 0x0017; std::vector<uint8_t> server_pub; std::vector<uint8_t> shared32; if (_selected_group == 0x001d) { std::vector<uint8_t> shared32; // ------------------- X25519 ------------------- _server_priv_x25519.resize(32); fillRandom(_server_priv_x25519); Loading @@ -2629,8 +2653,10 @@ void netplus::ssl::handshake_after_accept(){ throwSSL(NetException::Error, "TLS1.3 X25519 shared secret failed"); std::copy(_server_pub_x25519.begin(),_server_pub_x25519.end(),std::back_inserter(server_pub)); _x25519_shared=shared32; } else { std::vector<uint8_t> shared32; // ------------------- P-256 ------------------- netplus::P256Point cli_pub; if (!netplus::decode_tls_point(cli_pub, _client_keyshare_ecdhe.data(), 65)) Loading @@ -2651,10 +2677,10 @@ void netplus::ssl::handshake_after_accept(){ throwSSL(NetException::Error, "TLS1.3 ECDH failed"); server_pub = _server_keyshare_ecdhe; _ecdhe_shared=shared32; } // ✅ Store shared secret for HKDF key schedule _tls13_ecdhe_shared=shared32; _tls13_got_key_share = true; // ✅ Generate ServerRandom Loading @@ -2674,7 +2700,10 @@ void netplus::ssl::handshake_after_accept(){ _handshake_transcript.insert(_handshake_transcript.end(), hs.begin(), hs.end()); // ✅ Derive handshake traffic secrets now (CH..SH hash) _tls13_derive_handshake_keys(_tls13_ecdhe_shared); if(_ecdhe_shared.empty()) _tls13_derive_handshake_keys(_x25519_shared); else _tls13_derive_handshake_keys(_ecdhe_shared); // ✅ Send plaintext ServerHello record std::vector<uint8_t> rec; Loading Loading @@ -2890,7 +2919,6 @@ std::vector<uint8_t> netplus::ssl::_hkdf_extract( return _hmac_sha256(s, in); } std::vector<uint8_t> netplus::ssl::_hkdf_expand( const std::vector<uint8_t>& prk, const std::vector<uint8_t>& info, Loading Loading @@ -2991,6 +3019,18 @@ void netplus::ssl::_tls13_derive_handshake_keys(const std::vector<uint8_t>& ecdh memcpy(_tls13_hs_iv_s2c, s_iv.data(), 12); memcpy(_tls13_hs_iv_c2s, c_iv.data(), 12); } auto hex = [](const std::vector<uint8_t>& v) { std::ostringstream os; for (auto b : v) os << std::hex << std::setw(2) << std::setfill('0') << int(b); return os.str(); }; std::cerr << "[DBG] client_random=" << hex(_clientRandom) << "\n"; std::cerr << "[DBG] transcript_size=" << _handshake_transcript.size() << "\n"; std::cerr << "[DBG] transcript_hash=" << hex(sha256_hash(_handshake_transcript)) << "\n"; std::cerr << "[DBG] s_hs_secret=" << hex(_tls13_s_hs_secret) << "\n"; } Loading Loading @@ -3317,7 +3357,34 @@ void netplus::ssl::handshake_after_connect(){ if (kp2 + klen > end2) throwSSL(NetException::Error, "ServerHello key_share truncated"); if (group == 0x0017) { 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"); Loading @@ -3325,16 +3392,20 @@ void netplus::ssl::handshake_after_connect(){ if (!netplus::decode_tls_point(srv_pub, kp2, klen)) throwSSL(NetException::Error, "TLS1.3 key_share invalid point"); uint8_t shared32[32]; if (!netplus::ecdh_shared_secret(shared32, _client_priv_ecdhe, srv_pub)) 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, shared32 + 32); ecdhe_shared.assign(shared32_raw, shared32_raw + 32); _tls13_got_key_share = true; _tls13_ecdhe_shared = ecdhe_shared; _ecdhe_shared = ecdhe_shared; } else { throwSSL(NetException::Error, "ServerHello unsupported key_share group"); } } eoff += el; Loading Loading @@ -4048,10 +4119,8 @@ void netplus::ssl::_tls13_send_record( full.insert(full.end(), ct.begin(), ct.end()); full.insert(full.end(), tag, tag+16); // queue record queueRaw(hdr, 5); queueRaw(ct.data(), ct.size()); queueRaw(tag, 16); // queue ONE record queueRaw(std::move(full)); seq++; } Loading Loading @@ -4110,7 +4179,8 @@ void netplus::ssl::resetTLS() { memset(_client_priv_ecdhe, 0, sizeof(_client_priv_ecdhe)); memset(_server_priv_ecdhe, 0, sizeof(_server_priv_ecdhe)); _tls13_ecdhe_shared.clear(); _ecdhe_shared.clear(); _x25519_shared.clear(); _tls13_early_secret.clear(); _tls13_hs_secret.clear(); Loading Loading @@ -4205,16 +4275,6 @@ bool netplus::ssl::_tls13_recv_record( uint8_t& out_inner_type, bool handshake_keys ){ switch(out_inner_type){ case 0x16: case 0x17: case 0x15: case 0x14: break; default: throwSSL(NetException::Error, "TLS1.3 recv: illegal inner content type"); } if (data_len < 17) throwSSL(NetException::Error, "TLS1.3 recv: illegal datalen"); Loading Loading @@ -4313,8 +4373,7 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_server_finished_body() std::vector<uint8_t> finished_key = _hkdf_expand_label(_tls13_s_hs_secret, "finished", empty, 32); // verify_data = HMAC(finished_key, th) => 32 bytes return _hmac_sha256(finished_key, th); return _hmac_sha256(finished_key, th); // verify_data (32 bytes) } std::vector<uint8_t> netplus::ssl::_rsa_pss_sha256_sign(const std::vector<uint8_t>& in){ Loading test/x25519.cpp +28 −37 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ #include <vector> #include <algorithm> #include <cstdint> #include <cassert> #include "../src/crypto/curve25519.h" Loading @@ -17,21 +18,33 @@ bool equal32(const std::vector<uint8_t>& x, const std::vector<uint8_t>& y) { } int main() { netplus::FieldElement a, b; a.limbs[0] = 1; b.limbs[0] = 2; a.sel25519(b, 0); assert(a.limbs[0] == 1 && b.limbs[0] == 2); a.sel25519(b, 1); assert(a.limbs[0] == 2 && b.limbs[0] == 1); std::cout << "Running X25519 RFC7748 vectors + 1000-iteration KAT...\n"; std::vector<uint8_t> out; std::vector<uint8_t> out(32,0); int ok = 1; // --------------------------------------------------------- // RFC7748 vector #1: scalar1 * base(9) // --------------------------------------------------------- const std::vector<uint8_t> scalar1 = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 0x1c,0x1d,0x95,0x59,0xa7,0x4c,0x1d,0x32, 0x0b,0x8d,0x5b,0x39,0xa0,0x74,0x04,0x2a, 0x71,0x1c,0x1f,0x79,0x1d,0x2d,0x76,0xc9, 0xbf,0x6a,0x6c,0xf2,0x6b,0xe3,0x46,0xa5 }; const std::vector<uint8_t> expect1 = { 0xe6,0xdb,0x68,0x67,0x58,0x30,0x30,0xdb, 0x35,0x94,0xc1,0xa4,0x24,0xb1,0x5f,0x7c, Loading @@ -49,6 +62,8 @@ int main() { std::cout << "PASS: RFC7748 vector #1\n"; } out.clear(); // --------------------------------------------------------- // RFC7748 vector #2: scalar2 * point2 // --------------------------------------------------------- Loading Loading @@ -99,31 +114,23 @@ int main() { k[0] = 9; u[0] = 9; std::cout << "After initialization: k = "; print_hex(k); std::cout << "\n"; std::cout << "After initialization: u = "; print_hex(u); std::cout << "\n"; for (int i = 0; i < 1000; ++i) { std::vector<uint8_t> r; std::vector<uint8_t> prev_k = k; // Perform scalar multiplication // r = X25519(k, u) netplus::scalarmult_curve25519(r, k, u); // Update u to the previous value of k for the next iteration u = prev_k; // u = k; k = r u = k; k = r; // Reset size to ensure it stays at 32 bytes k.resize(32, 0); u.resize(32, 0); if (i == 0 || i == 1 || i == 999) { std::cout << " iter " << (i + 1) << ": "; print_hex(k, 8); std::cout << "...\n"; } } // expected after 1000 iterations // expected after 1000 iterations (RFC7748) const std::vector<uint8_t> kat_k = { 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, Loading @@ -131,13 +138,6 @@ int main() { 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51 }; const std::vector<uint8_t> kat_u = { 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24 }; if (!equal32(k, kat_k)) { ok = 0; std::cerr << "FAIL: KAT 1000 - final k mismatch\n"; Loading @@ -147,15 +147,6 @@ int main() { std::cout << "PASS: KAT 1000 final k\n"; } if (!equal32(u, kat_u)) { ok = 0; std::cerr << "FAIL: KAT 1000 - final u mismatch\n"; std::cerr << " got u: "; print_hex(u, 32, std::cerr); std::cerr << "\n"; std::cerr << " exp u: "; print_hex(kat_u, 32, std::cerr); std::cerr << "\n"; } else { std::cout << "PASS: KAT 1000 final u\n"; } // --------------------------------------------------------- // Summary // --------------------------------------------------------- Loading Loading
src/socket.h +5 −2 Original line number Diff line number Diff line Loading @@ -500,7 +500,6 @@ namespace netplus { std::vector<uint8_t> _tls13_client_keyshare; //debug std::vector<uint8_t> _tls13_ecdhe_shared; // 32 bytes shared secret bool _tls13_got_key_share = false; netplus::x509cert _peer_cert; Loading Loading @@ -608,11 +607,15 @@ namespace netplus { std::vector<uint8_t> _server_keyshare_x25519; std::vector<uint8_t> _server_priv_x25519; std::vector<uint8_t> _server_pub_x25519; std::vector<uint8_t> _client_priv_x25519; std::vector<uint8_t> _x25519_shared; std::vector<uint8_t> _client_keyshare_ecdhe; std::vector<uint8_t> _server_keyshare_ecdhe; uint8_t _client_priv_ecdhe[32] = {0}; // client ephemeral scalar (BE) uint8_t _server_priv_ecdhe[32] = {0}; // server ephemeral scalar (BE) uint8_t _server_priv_ecdhe[32] = {0}; std::vector<uint8_t> _ecdhe_shared; // 32 bytes shared secret // server ephemeral scalar (BE) enum class HsState { // server READ_CLIENT_HELLO, Loading
src/ssl.cpp +125 −66 Original line number Diff line number Diff line Loading @@ -2136,7 +2136,43 @@ void netplus::ssl::handshake_after_accept(){ const uint8_t* key = ep + 4; if (group == 0x0017) { // P-256 // --------------------------------------------------------- // ✅ 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"; Loading @@ -2152,16 +2188,22 @@ void netplus::ssl::handshake_after_accept(){ throw e; } uint8_t shared32[32]; if (!netplus::ecdh_shared_secret(shared32, _client_priv_ecdhe, srv_pub)) { 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; } _tls13_ecdhe_shared.assign(shared32, shared32 + 32); _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; Loading Loading @@ -2516,7 +2558,6 @@ void netplus::ssl::handshake_after_accept(){ } case HsState::TLS13_SEND_ENCRYPTED_FLIGHT: { if (!_tls13_encflight_queued) { TLSDBG("[DEBUG] TLS 1.3: Preparing EncryptedExtensions"); if (!_aes13_hs_send || !_aes13_hs_recv) Loading @@ -2526,46 +2567,31 @@ void netplus::ssl::handshake_after_accept(){ std::vector<uint8_t> ee = {0x00, 0x00}; TLSDBG("[DEBUG] TLS 1.3: Sending EncryptedExtensions"); _tls13_send_handshake(0x08, ee, true); std::vector<uint8_t> th_ee = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after EncryptedExtensions: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_ee) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; // ---- 2) Certificate ---- TLSDBG("[DEBUG] TLS 1.3: Preparing Certificate"); std::vector<uint8_t> cert = _tls13_build_certificate(); TLSDBG("[DEBUG] TLS 1.3: Sending Certificate, size=" << cert.size()); _tls13_send_handshake(0x0b, cert, true); std::vector<uint8_t> th_cert = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after Certificate: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_cert) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; // ---- 3) CertificateVerify ---- TLSDBG("[DEBUG] TLS 1.3: Preparing CertificateVerify"); std::vector<uint8_t> cv = _tls13_build_certificate_verify(); TLSDBG("[DEBUG] TLS 1.3: Sending CertificateVerify, size=" << cv.size()); _tls13_send_handshake(0x0f, cv, true); std::vector<uint8_t> th_cv = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after CertificateVerify: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_cv) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; // ---- 4) Finished ---- TLSDBG("[DEBUG] TLS 1.3: Preparing Finished"); std::vector<uint8_t> fin = _tls13_build_server_finished(); TLSDBG("[DEBUG] TLS 1.3: Sending Finished, size=" << fin.size()); // Must append Finished to transcript BEFORE deriving app keys // (either _tls13_send_handshake does it internally, or do it here explicitly) // This returns verify_data (32 bytes) only std::vector<uint8_t> fin_body = _tls13_build_server_finished_body(); _tls13_send_handshake(0x14, fin, true); std::vector<uint8_t> th_fin = sha256_hash(_handshake_transcript); std::cerr << "[DEBUG] Transcript after Finished: size=" << _handshake_transcript.size() << ", hash="; for (auto b : th_fin) std::cerr << std::hex << (int)b << " "; std::cerr << std::dec << std::endl; TLSDBG("[DEBUG] TLS 1.3: Sending Finished, verify_data size=" << fin_body.size()); // Send handshake msg type=0x14 with body=verify_data _tls13_send_handshake(0x14, fin_body, true); // ---- 5) derive application keys AFTER transcript includes server Finished ---- // ---- 5) derive application keys AFTER Finished is in transcript ---- TLSDBG("[DEBUG] TLS 1.3: Deriving application keys"); _tls13_derive_application_keys(); Loading @@ -2586,8 +2612,6 @@ void netplus::ssl::handshake_after_accept(){ return; } case HsState::FAIL:{ NetException e; e[NetException::Error] << "Handshake Failed"; Loading @@ -2612,9 +2636,9 @@ void netplus::ssl::handshake_after_accept(){ _selected_group = use_x25519 ? 0x001d : 0x0017; std::vector<uint8_t> server_pub; std::vector<uint8_t> shared32; if (_selected_group == 0x001d) { std::vector<uint8_t> shared32; // ------------------- X25519 ------------------- _server_priv_x25519.resize(32); fillRandom(_server_priv_x25519); Loading @@ -2629,8 +2653,10 @@ void netplus::ssl::handshake_after_accept(){ throwSSL(NetException::Error, "TLS1.3 X25519 shared secret failed"); std::copy(_server_pub_x25519.begin(),_server_pub_x25519.end(),std::back_inserter(server_pub)); _x25519_shared=shared32; } else { std::vector<uint8_t> shared32; // ------------------- P-256 ------------------- netplus::P256Point cli_pub; if (!netplus::decode_tls_point(cli_pub, _client_keyshare_ecdhe.data(), 65)) Loading @@ -2651,10 +2677,10 @@ void netplus::ssl::handshake_after_accept(){ throwSSL(NetException::Error, "TLS1.3 ECDH failed"); server_pub = _server_keyshare_ecdhe; _ecdhe_shared=shared32; } // ✅ Store shared secret for HKDF key schedule _tls13_ecdhe_shared=shared32; _tls13_got_key_share = true; // ✅ Generate ServerRandom Loading @@ -2674,7 +2700,10 @@ void netplus::ssl::handshake_after_accept(){ _handshake_transcript.insert(_handshake_transcript.end(), hs.begin(), hs.end()); // ✅ Derive handshake traffic secrets now (CH..SH hash) _tls13_derive_handshake_keys(_tls13_ecdhe_shared); if(_ecdhe_shared.empty()) _tls13_derive_handshake_keys(_x25519_shared); else _tls13_derive_handshake_keys(_ecdhe_shared); // ✅ Send plaintext ServerHello record std::vector<uint8_t> rec; Loading Loading @@ -2890,7 +2919,6 @@ std::vector<uint8_t> netplus::ssl::_hkdf_extract( return _hmac_sha256(s, in); } std::vector<uint8_t> netplus::ssl::_hkdf_expand( const std::vector<uint8_t>& prk, const std::vector<uint8_t>& info, Loading Loading @@ -2991,6 +3019,18 @@ void netplus::ssl::_tls13_derive_handshake_keys(const std::vector<uint8_t>& ecdh memcpy(_tls13_hs_iv_s2c, s_iv.data(), 12); memcpy(_tls13_hs_iv_c2s, c_iv.data(), 12); } auto hex = [](const std::vector<uint8_t>& v) { std::ostringstream os; for (auto b : v) os << std::hex << std::setw(2) << std::setfill('0') << int(b); return os.str(); }; std::cerr << "[DBG] client_random=" << hex(_clientRandom) << "\n"; std::cerr << "[DBG] transcript_size=" << _handshake_transcript.size() << "\n"; std::cerr << "[DBG] transcript_hash=" << hex(sha256_hash(_handshake_transcript)) << "\n"; std::cerr << "[DBG] s_hs_secret=" << hex(_tls13_s_hs_secret) << "\n"; } Loading Loading @@ -3317,7 +3357,34 @@ void netplus::ssl::handshake_after_connect(){ if (kp2 + klen > end2) throwSSL(NetException::Error, "ServerHello key_share truncated"); if (group == 0x0017) { 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"); Loading @@ -3325,16 +3392,20 @@ void netplus::ssl::handshake_after_connect(){ if (!netplus::decode_tls_point(srv_pub, kp2, klen)) throwSSL(NetException::Error, "TLS1.3 key_share invalid point"); uint8_t shared32[32]; if (!netplus::ecdh_shared_secret(shared32, _client_priv_ecdhe, srv_pub)) 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, shared32 + 32); ecdhe_shared.assign(shared32_raw, shared32_raw + 32); _tls13_got_key_share = true; _tls13_ecdhe_shared = ecdhe_shared; _ecdhe_shared = ecdhe_shared; } else { throwSSL(NetException::Error, "ServerHello unsupported key_share group"); } } eoff += el; Loading Loading @@ -4048,10 +4119,8 @@ void netplus::ssl::_tls13_send_record( full.insert(full.end(), ct.begin(), ct.end()); full.insert(full.end(), tag, tag+16); // queue record queueRaw(hdr, 5); queueRaw(ct.data(), ct.size()); queueRaw(tag, 16); // queue ONE record queueRaw(std::move(full)); seq++; } Loading Loading @@ -4110,7 +4179,8 @@ void netplus::ssl::resetTLS() { memset(_client_priv_ecdhe, 0, sizeof(_client_priv_ecdhe)); memset(_server_priv_ecdhe, 0, sizeof(_server_priv_ecdhe)); _tls13_ecdhe_shared.clear(); _ecdhe_shared.clear(); _x25519_shared.clear(); _tls13_early_secret.clear(); _tls13_hs_secret.clear(); Loading Loading @@ -4205,16 +4275,6 @@ bool netplus::ssl::_tls13_recv_record( uint8_t& out_inner_type, bool handshake_keys ){ switch(out_inner_type){ case 0x16: case 0x17: case 0x15: case 0x14: break; default: throwSSL(NetException::Error, "TLS1.3 recv: illegal inner content type"); } if (data_len < 17) throwSSL(NetException::Error, "TLS1.3 recv: illegal datalen"); Loading Loading @@ -4313,8 +4373,7 @@ std::vector<uint8_t> netplus::ssl::_tls13_build_server_finished_body() std::vector<uint8_t> finished_key = _hkdf_expand_label(_tls13_s_hs_secret, "finished", empty, 32); // verify_data = HMAC(finished_key, th) => 32 bytes return _hmac_sha256(finished_key, th); return _hmac_sha256(finished_key, th); // verify_data (32 bytes) } std::vector<uint8_t> netplus::ssl::_rsa_pss_sha256_sign(const std::vector<uint8_t>& in){ Loading
test/x25519.cpp +28 −37 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ #include <vector> #include <algorithm> #include <cstdint> #include <cassert> #include "../src/crypto/curve25519.h" Loading @@ -17,21 +18,33 @@ bool equal32(const std::vector<uint8_t>& x, const std::vector<uint8_t>& y) { } int main() { netplus::FieldElement a, b; a.limbs[0] = 1; b.limbs[0] = 2; a.sel25519(b, 0); assert(a.limbs[0] == 1 && b.limbs[0] == 2); a.sel25519(b, 1); assert(a.limbs[0] == 2 && b.limbs[0] == 1); std::cout << "Running X25519 RFC7748 vectors + 1000-iteration KAT...\n"; std::vector<uint8_t> out; std::vector<uint8_t> out(32,0); int ok = 1; // --------------------------------------------------------- // RFC7748 vector #1: scalar1 * base(9) // --------------------------------------------------------- const std::vector<uint8_t> scalar1 = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 0x1c,0x1d,0x95,0x59,0xa7,0x4c,0x1d,0x32, 0x0b,0x8d,0x5b,0x39,0xa0,0x74,0x04,0x2a, 0x71,0x1c,0x1f,0x79,0x1d,0x2d,0x76,0xc9, 0xbf,0x6a,0x6c,0xf2,0x6b,0xe3,0x46,0xa5 }; const std::vector<uint8_t> expect1 = { 0xe6,0xdb,0x68,0x67,0x58,0x30,0x30,0xdb, 0x35,0x94,0xc1,0xa4,0x24,0xb1,0x5f,0x7c, Loading @@ -49,6 +62,8 @@ int main() { std::cout << "PASS: RFC7748 vector #1\n"; } out.clear(); // --------------------------------------------------------- // RFC7748 vector #2: scalar2 * point2 // --------------------------------------------------------- Loading Loading @@ -99,31 +114,23 @@ int main() { k[0] = 9; u[0] = 9; std::cout << "After initialization: k = "; print_hex(k); std::cout << "\n"; std::cout << "After initialization: u = "; print_hex(u); std::cout << "\n"; for (int i = 0; i < 1000; ++i) { std::vector<uint8_t> r; std::vector<uint8_t> prev_k = k; // Perform scalar multiplication // r = X25519(k, u) netplus::scalarmult_curve25519(r, k, u); // Update u to the previous value of k for the next iteration u = prev_k; // u = k; k = r u = k; k = r; // Reset size to ensure it stays at 32 bytes k.resize(32, 0); u.resize(32, 0); if (i == 0 || i == 1 || i == 999) { std::cout << " iter " << (i + 1) << ": "; print_hex(k, 8); std::cout << "...\n"; } } // expected after 1000 iterations // expected after 1000 iterations (RFC7748) const std::vector<uint8_t> kat_k = { 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, Loading @@ -131,13 +138,6 @@ int main() { 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51 }; const std::vector<uint8_t> kat_u = { 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24 }; if (!equal32(k, kat_k)) { ok = 0; std::cerr << "FAIL: KAT 1000 - final k mismatch\n"; Loading @@ -147,15 +147,6 @@ int main() { std::cout << "PASS: KAT 1000 final k\n"; } if (!equal32(u, kat_u)) { ok = 0; std::cerr << "FAIL: KAT 1000 - final u mismatch\n"; std::cerr << " got u: "; print_hex(u, 32, std::cerr); std::cerr << "\n"; std::cerr << " exp u: "; print_hex(kat_u, 32, std::cerr); std::cerr << "\n"; } else { std::cout << "PASS: KAT 1000 final u\n"; } // --------------------------------------------------------- // Summary // --------------------------------------------------------- Loading