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

test

parent 4a8f7eaa
Loading
Loading
Loading
Loading
+101 −5
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@
#include <fstream>

#include "tls.h"
#include "ecdsa_verify.h"
#include "x509.h"
#include "sha.h"
#include "base64.h"
#include "rsa_pss_sha256.h"
@@ -36,6 +38,44 @@ void setCertRequest(const netplus::tls *t, std::vector<uint8_t> context) {
}

// true (and the context) once if a certificate was asked for
// Client, TLS 1.2: the leaf certificate's EC key, for the ServerKeyExchange
// signature (kept here for the same ABI reason)
struct EcKey {
    std::string curve;
    std::vector<uint8_t> pub;
};
std::map<const netplus::tls *, EcKey> g_ecKeys;
// Client, TLS 1.2: the ECDHE group the server chose (secp256r1 or x25519)
std::map<const netplus::tls *, uint16_t> g_ecdheGroups;

void setEcdheGroup(const netplus::tls *t, uint16_t g) {
    std::lock_guard<std::mutex> l(g_certRequestsLock);
    g_ecdheGroups[t] = g;
}

uint16_t takeEcdheGroup(const netplus::tls *t) {
    std::lock_guard<std::mutex> l(g_certRequestsLock);
    auto it = g_ecdheGroups.find(t);
    if (it == g_ecdheGroups.end()) return 0x0017;
    uint16_t g = it->second;
    g_ecdheGroups.erase(it);
    return g;
}

void setEcKey(const netplus::tls *t, EcKey k) {
    std::lock_guard<std::mutex> l(g_certRequestsLock);
    g_ecKeys[t] = std::move(k);
}

bool takeEcKey(const netplus::tls *t, EcKey &k) {
    std::lock_guard<std::mutex> l(g_certRequestsLock);
    auto it = g_ecKeys.find(t);
    if (it == g_ecKeys.end()) return false;
    k = std::move(it->second);
    g_ecKeys.erase(it);
    return true;
}

bool takeCertRequest(const netplus::tls *t, std::vector<uint8_t> &context) {
    std::lock_guard<std::mutex> l(g_certRequestsLock);
    auto it = g_certRequests.find(t);
@@ -2349,7 +2389,11 @@ namespace netplus {
                            serverCert.loadFromBuffer(derCert);
                            if (serverCert.isECKey()) {
                                server_cert_is_ecdsa = true;
                                // EC public key will be used in ECDHE; no per-cert key needed here
                                // its key checks the ServerKeyExchange signature
                                EcKey k;
                                k.curve = serverCert.getECCurveOID();
                                if (k.curve.empty()) k.curve = netplus::CurveP256;
                                if (serverCert.extractECPublicKey(k.pub)) setEcKey(this, std::move(k));
                            } else {
                                server_cert_is_ecdsa = false;
                                if (!serverCert.extractPublicKey(peer_rsa)) {
@@ -2432,8 +2476,13 @@ namespace netplus {
                    }
                    size_t off = 4; // skip handshake header
                    uint8_t curve_type = msg[off++]; // 0x03 = named_curve
                    (void)curve_type;
                    off += 2; // skip named_curve (0x0017 = secp256r1)
                    uint16_t group = (uint16_t(msg[off]) << 8) | msg[off + 1];
                    off += 2;
                    // secp256r1, or x25519 (offered in supported_groups for TLS 1.3, so a
                    // TLS 1.2 server may pick it for ECDHE too)
                    if (curve_type != 3 || (group != 0x0017 && group != 0x001d))
                        throwSSL(NetException::Error, "ServerKeyExchange: unsupported ECDHE group " + std::to_string(group));
                    setEcdheGroup(this, group);
                    uint8_t pubkey_len = msg[off++];
                    if (off + pubkey_len > msg.size()) {
                        NetException e;
@@ -2441,7 +2490,35 @@ namespace netplus {
                        throw e;
                    }
                    tls12_srv_ecdhe_pub.assign(msg.begin() + off, msg.begin() + off + pubkey_len);
                    // Signature is after the key — skip verification (like cert verification)
                    off += pubkey_len;

                    // The signature (RFC 5246 7.4.3, RFC 8422 5.4): over client_random |
                    // server_random | the ECDH parameters, with the certificate's key.
                    // Without it a man in the middle could put in an ECDH key of its own
                    // while passing the real certificate through.
                    {
                        EcKey key;
                        bool haveKey = takeEcKey(this, key);
                        if (trust_policy.verifyPeer) {
                            if (off + 4 > msg.size())
                                throwSSL(NetException::Error, "ServerKeyExchange without signature");
                            uint8_t hashAlg = msg[off], sigAlg = msg[off + 1];
                            size_t sigLen = (size_t(msg[off + 2]) << 8) | msg[off + 3];
                            if (off + 4 + sigLen > msg.size())
                                throwSSL(NetException::Error, "ServerKeyExchange signature truncated");
                            std::vector<uint8_t> signedData = clientRandom;
                            signedData.insert(signedData.end(), serverRandom.begin(), serverRandom.end());
                            signedData.insert(signedData.end(), msg.begin() + 4, msg.begin() + off);
                            std::vector<uint8_t> digest = hashAlg == 4 ? sha256_hash(signedData)
                                                        : hashAlg == 5 ? sha384_hash(signedData)
                                                        : std::vector<uint8_t>();
                            if (sigAlg != 3 || digest.empty())
                                throwSSL(NetException::Error, "ServerKeyExchange: unsupported signature algorithm");
                            std::vector<uint8_t> sig(msg.begin() + off + 4, msg.begin() + off + 4 + sigLen);
                            if (!haveKey || !netplus::ecdsa_verify_digest(key.curve, key.pub, digest, sig))
                                throwSSL(NetException::Error, "ServerKeyExchange signature invalid");
                        }
                    }

                    // Add ServerKeyExchange to transcript (RFC 5246)
                    handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());
@@ -2497,7 +2574,23 @@ namespace netplus {
                        std::vector<uint8_t> preMaster;
                        std::vector<uint8_t> ckeBody;

                        if (server_cert_is_ecdsa && !tls12_srv_ecdhe_pub.empty()) {
                        uint16_t group = server_cert_is_ecdsa ? takeEcdheGroup(this) : 0;
                        if (group == 0x001d && !tls12_srv_ecdhe_pub.empty()) {
                            // ECDHE over x25519 (RFC 8422 5.11): 32-byte keys, the shared secret is the premaster
                            if (tls12_srv_ecdhe_pub.size() != 32)
                                throwSSL(NetException::Error, "ECDHE CKE: bad x25519 server key");
                            std::vector<uint8_t> priv(32), pub, shared;
                            fillRandomBytes(priv.data(), priv.size());
                            if (!netplus::scalarmult_curve25519_base(pub, priv) ||
                                !netplus::scalarmult_curve25519(shared, priv, tls12_srv_ecdhe_pub))
                                throwSSL(NetException::Error, "ECDHE CKE: x25519 failed");
                            bool zero = true;
                            for (uint8_t b : shared) zero = zero && b == 0;
                            if (zero) throwSSL(NetException::Error, "ECDHE CKE: x25519 gave a zero secret");
                            preMaster = shared;
                            ckeBody.push_back(uint8_t(pub.size()));
                            ckeBody.insert(ckeBody.end(), pub.begin(), pub.end());
                        } else if (server_cert_is_ecdsa && !tls12_srv_ecdhe_pub.empty()) {
                            // ECDHE-ECDSA: generate ephemeral client key pair and compute shared secret
                            uint8_t cli_priv[32];
                            for (int retry = 0; retry < 10; ++retry) {
@@ -4930,6 +5023,9 @@ namespace netplus {
        {
            std::vector<uint8_t> stale;
            takeCertRequest(this, stale);
            EcKey staleKey;
            takeEcKey(this, staleKey);
            takeEcdheGroup(this);
        }

        // Build ClientHello message body