#ifndef __TLS_h__ #define __TLS_h__ #include "ZString.h" #include "TLSInfo.h" #include #include #include namespace core { /// /// TLS /// /// This object provides the support methods to handle TLS on the server core and /// session environment. /// class TLS { public: /// /// /// TLS(); /// /// Use this constructor when the SSL context needs to be created as when opening /// a server TCPSocket. /// TLS(TLSInfo *tlsInfo); /// /// Use this constructor on creation of a new TCPSocket that needs access to /// the generating server's SSL context. /// TLS(SSL_CTX *ctx); /// /// The destructor for this object. /// ~TLS(); void createContext(TLSInfo *tlsInfo); /// /// Registers a second (or third, etc.) certificate/key pair for a /// specific hostname on THIS SAME listening socket, via TLS's /// Server Name Indication (SNI) extension - lets one TCPServer /// terminate TLS for multiple unrelated domains, each with its own /// real certificate, without needing a separate listening port or /// process per domain. Must be called after createContext() (or the /// TLSInfo* constructor, which calls it) has already established the /// base `ctx` - that base context keeps serving as both the /// fallback for hostnames not registered here AND the cert offered /// to any client that sends no SNI hostname at all (a bare-IP /// request, or any TLS client old enough to predate SNI). Callers /// that never call this at all (every existing single-site /// TLSInfo* user - BARANTMail, Zephora, ClockPlanet, and a /// single-site APIServer config) see zero behavior change: the SNI /// callback is only ever registered on `ctx` the first time this is /// called, not unconditionally in createContext(). /// void addSNIContext(const std::string &hostname, TLSInfo *tlsInfo); // A never-configured TLS object (either the listening TCPServer // itself when constructed with tlsInfo=NULL, or a TCPSession spawned // from one via TLS(SSL_CTX*)) must default to a real NULL here, not // garbage - TCPSocket::receiveData()/sendData() key their TLS-vs- // plain dispatch on this exact value (see TCPSocket.cpp). SSL_CTX *ctx = NULL; protected: int receiveData(coreutils::ZString &buffer); int sendData(const char *data, int length); void registerSocket(int fd); void acceptSocket(); protected: // Set by sendData() when the last SSL_write() failed specifically // with SSL_ERROR_WANT_READ (needs a READ to make progress - e.g. // mid-handshake application data, or a post-handshake session // ticket exchange) rather than any other reason. TCPSocket:: // sendNeedsRead() reads this (protected, so a subclass can reach // it directly) to tell Socket::writeSocket()/resetSocket() not to // busy-spin retrying the write via EPOLLWRNORM - see their own // doc comments for the confirmed real damage (a 15GB+ debug log, // and every affected connection dropped before ever reading the // client's first command) this caused when unaddressed. bool lastSendWantedRead = false; private: char *sip_cacert = (char *)"../testkeys/certs/pbxca.crt"; char *sip_cert = (char *)"../testkeys/certs/pbxserver.crt"; char *sip_key = (char *)"../testkeys/certs/pbxserver.key"; bool initialized = false; SSL *ssl; // The actual cert/key-loading + cipher/session-cache setup shared // by both the base context (createContext(), unchanged) and every // additional per-hostname context addSNIContext() builds - factored // out so there's exactly one place that does this, not two copies // drifting apart. SSL_CTX *buildContext(TLSInfo *tlsInfo); // Owns every SSL_CTX* built by addSNIContext() (the base `ctx` is // owned/freed the same way it always was, untouched by this map). // Keyed by hostname exactly as configured - matched case- // insensitively against the ClientHello's SNI value in the // callback (see TLS.cpp). std::map sniContexts; bool sniCallbackRegistered = false; // OpenSSL's own SSL_CTX_set_tlsext_servername_callback signature - // a static member (not a free function) so it can reach the owning // TLS instance's private sniContexts via the `arg` parameter // (SSL_CTX_set_tlsext_servername_arg(ctx, this), set alongside the // callback itself in addSNIContext()). static int sniCallback(SSL *ssl, int *ad, void *arg); }; } #endif