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

test

parent 7635098c
Loading
Loading
Loading
Loading
+100 −0
Original line number Diff line number Diff line
@@ -19,6 +19,33 @@
#include "../socket.h"
#include "../exception.h"

#include <map>
#include <mutex>

namespace {
// Client: the server sent a CertificateRequest; we answer with an empty
// Certificate (no client certificate), echoing the TLS 1.3 request
// context. Kept here rather than in netplus::tls so that its layout --
// the library's ABI -- stays the same. Cleared at every ClientHello.
std::mutex g_certRequestsLock;
std::map<const netplus::tls *, std::vector<uint8_t>> g_certRequests;

void setCertRequest(const netplus::tls *t, std::vector<uint8_t> context) {
    std::lock_guard<std::mutex> l(g_certRequestsLock);
    g_certRequests[t] = std::move(context);
}

// true (and the context) once if a certificate was asked for
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);
    if (it == g_certRequests.end()) return false;
    context = std::move(it->second);
    g_certRequests.erase(it);
    return true;
}
} // namespace

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

@@ -1965,6 +1992,19 @@ namespace netplus {
                            note("ssl::handshake_after_connect: wait TLS1.3 Certificate");
                    }

                    // RFC 8446 §4.3.2: a CertificateRequest may come first (Active
                    // Directory's LDAPS asks for an optional client certificate).
                    // Remember its context; SEND_FINISHED answers with an empty
                    // Certificate -- we have none to offer.
                    if (msg.size() >= 5 && msg[0] == 0x0d) {
                        size_t ctxLen = msg[4];
                        if (5 + ctxLen > msg.size())
                            throwSSL(NetException::Error, "TLS1.3 CertificateRequest truncated");
                        setCertRequest(this, std::vector<uint8_t>(msg.begin() + 5, msg.begin() + 5 + ctxLen));
                        handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());
                        break;  // the Certificate comes next
                    }

                    if (msg.size() < 4 || msg[0] != 0x0b) {
                        NetException e;
                        e[NetException::Error] << "TLS1.3 expected Certificate got " << int(msg.empty()? -1 : msg[0]);
@@ -2186,6 +2226,25 @@ namespace netplus {
                    // Determine hash length based on cipher suite
                    size_t cli_hash_len = (chosenSuite == 0x1302) ? 48 : 32;

                    // Asked for a certificate: an empty Certificate (no
                    // CertificateVerify then), part of the transcript the
                    // Finished below covers (RFC 8446 §4.4.2)
                    std::vector<uint8_t> certContext;
                    if (takeCertRequest(this, certContext)) {
                        std::vector<uint8_t> body;
                        body.push_back(uint8_t(certContext.size()));
                        body.insert(body.end(), certContext.begin(), certContext.end());
                        body.push_back(0x00); body.push_back(0x00); body.push_back(0x00);  // certificate_list: empty
                        std::vector<uint8_t> cert_msg;
                        cert_msg.push_back(0x0b);
                        cert_msg.push_back(uint8_t(body.size() >> 16));
                        cert_msg.push_back(uint8_t(body.size() >> 8));
                        cert_msg.push_back(uint8_t(body.size()));
                        cert_msg.insert(cert_msg.end(), body.begin(), body.end());
                        handshake_transcript.insert(handshake_transcript.end(), cert_msg.begin(), cert_msg.end());
                        tls13_send_record(0x16, cert_msg, /*handshake_keys=*/true);
                    }

                    // Build client Finished verify_data
                    std::vector<uint8_t> cli_th;
                    if (chosenSuite == 0x1302) {
@@ -2302,6 +2361,30 @@ namespace netplus {
                        }
                    }

                    // Full chain-of-trust check, as in the TLS 1.3 path: every
                    // certificate of the list, leaf first.
                    {
                        std::vector<std::vector<uint8_t>> presented;
                        size_t p = 7, end = 7 + listLen;
                        while (p + 3 <= end) {
                            uint32_t len = (uint32_t(certMsg[p]) << 16) | (uint32_t(certMsg[p+1]) << 8) | uint32_t(certMsg[p+2]);
                            p += 3;
                            if (p + len > end) {
                                NetException e;
                                e[NetException::Error] << "Certificate entry truncated";
                                throw e;
                            }
                            presented.emplace_back(certMsg.begin() + p, certMsg.begin() + p + len);
                            p += len;
                        }
                        if (trust_policy.verifyPeer && presented.empty()) {
                            NetException e;
                            e[NetException::Error] << "TLS1.2: server sent no certificate";
                            throw e;
                        }
                        verifyPeerChain(presented, trust_policy);
                    }

                    // Add Certificate to transcript (RFC 5246)
                    handshake_transcript.insert(handshake_transcript.end(), certMsg.begin(), certMsg.end());

@@ -2384,6 +2467,14 @@ namespace netplus {
                    if (msg.empty())
                        note("ssl::handshake_after_connect: wait SHD");

                    // RFC 5246 §7.4.4: CertificateRequest before ServerHelloDone;
                    // answered with an empty Certificate in CLI_SEND_CKE
                    if (msg[0] == 0x0d) {
                        setCertRequest(this, {});
                        handshake_transcript.insert(handshake_transcript.end(), msg.begin(), msg.end());
                        break;
                    }

                    if (msg[0] != 0x0e) {
                        NetException e;
                        e[NetException::Error] << "expected ServerHelloDone got type=" << int(msg[0]);
@@ -2466,6 +2557,10 @@ namespace netplus {
                            ckeBody.insert(ckeBody.end(), ciphertext.begin(), ciphertext.end());
                        }

                        // asked for a certificate: an empty one first (RFC 5246 §7.4.6)
                        std::vector<uint8_t> certContext;
                        if (takeCertRequest(this, certContext))
                            sendHandshake(0x0b, std::vector<uint8_t>{0x00, 0x00, 0x00});
                        sendHandshake(0x10, ckeBody);

                        // Derive master_secret (sendHandshake above already added CKE to transcript)
@@ -4832,6 +4927,11 @@ namespace netplus {
    // =================================================================

    void tls::queueClientHello() {
        {
            std::vector<uint8_t> stale;
            takeCertRequest(this, stale);
        }

        // Build ClientHello message body
        std::vector<uint8_t> ch;