Hyperman

 view release on metacpan or  search on metacpan

include/hyperman/hm_tls.h  view on Meta::CPAN

#endif
#ifdef SSL_OP_NO_RENEGOTIATION
                             /* client-initiated TLS 1.2 renegotiation is an
                              * asymmetric-CPU DoS and nothing here wants it;
                              * refusing it also retires the only case that
                              * makes SSL_write block wanting a read */
                             | SSL_OP_NO_RENEGOTIATION
#endif
                             );
#ifdef HM_HAVE_KTLS
    /* There is no kernel record layer for QUIC: ngtcp2 encrypts every packet
     * itself, so asking for kTLS here is at best inert and at worst a
     * handshake OpenSSL sets up and nothing uses. */
    if (quic) SSL_CTX_clear_options(ctx, SSL_OP_ENABLE_KTLS);
#endif
    /* PARTIAL_WRITE is about SSL_write, which a QUIC context never calls. */
    if (!quic)
    SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE
                          | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
#ifdef SSL_MODE_RELEASE_BUFFERS
                          /* hand OpenSSL's record buffers back whenever they
                           * drain, rather than pinning them for a
                           * connection's whole life. A keep-alive server is
                           * mostly idle connections, which is exactly the
                           * case this covers. How much it saves depends on
                           * the OpenSSL version's buffer sizing and on the
                           * allocator actually returning the pages - worth
                           * measuring on the deployment platform (Linux
                           * /proc/PID/status VmRSS; macOS RSS is far too
                           * noisy to read anything off). */
                          | SSL_MODE_RELEASE_BUFFERS
#endif
                          );
    /* Without a session id context OpenSSL declines to resume a session on a
     * context that verifies peers, so every mTLS connection would pay a full
     * handshake plus a full chain verification. */
    SSL_CTX_set_session_id_context(ctx, sid, sizeof(sid) - 1);
#ifdef HM_HAVE_NUM_TICKETS
    /* TLS 1.3 issues two NewSessionTickets per handshake by default; one is
     * enough to resume with, and the second is pure post-handshake write. */
    SSL_CTX_set_num_tickets(ctx, 1);
#endif
#ifdef HM_HAVE_TICKET_KEYS
    /* copied rather than cast: the setter takes a non-const void * */
    if (tkey && tkeylen && tkeylen <= HM_TLS_TKEY_MAX) {
        unsigned char tk[HM_TLS_TKEY_MAX];
        memcpy(tk, tkey, tkeylen);
        SSL_CTX_set_tlsext_ticket_keys(ctx, tk, (long)tkeylen);
    }
#else
    (void)tkey; (void)tkeylen;
#endif
    if (SSL_CTX_use_certificate_chain_file(ctx, cert) <= 0) {
        fprintf(stderr, "Hyperman TLS: cannot load certificate '%s'\n", cert);
        ERR_print_errors_fp(stderr); SSL_CTX_free(ctx); return NULL;
    }
    if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
        fprintf(stderr, "Hyperman TLS: cannot load private key '%s'\n", key);
        ERR_print_errors_fp(stderr); SSL_CTX_free(ctx); return NULL;
    }
    if (!SSL_CTX_check_private_key(ctx)) {
        fprintf(stderr, "Hyperman TLS: certificate and key do not match\n");
        SSL_CTX_free(ctx); return NULL;
    }
#ifdef HM_HAVE_ALPN
    /* h3 only on a QUIC context: offering h2 or http/1.1 over QUIC is a
     * protocol error. The TCP list is untouched - h3 is discovered through
     * Alt-Svc, never through ALPN over TCP. */
    if (quic)         SSL_CTX_set_alpn_select_cb(ctx, hm_tls_alpn_h3_cb, NULL);
    else if (alpn_h2) SSL_CTX_set_alpn_select_cb(ctx, hm_tls_alpn_cb, NULL);
#else
    (void)alpn_h2;   /* ALPN unavailable on this OpenSSL; h2-over-TLS not offered */
#endif
    /* 0-RTT refused explicitly rather than left at a default: accepting it
     * means accepting replayable application data, and that is a decision
     * this server has not made. The setter is 1.1.1+, and a library without
     * it has no 0-RTT to refuse - nor any QUIC context to refuse it on. */
#ifdef HM_HAVE_TLS13
    if (quic) SSL_CTX_set_max_early_data(ctx, 0);
#endif
    if (verify != HM_TLS_VERIFY_NONE) {
        int flags = SSL_VERIFY_PEER;
        if (ca && SSL_CTX_load_verify_locations(ctx, ca, NULL) <= 0) {
            fprintf(stderr, "Hyperman TLS: cannot load CA '%s'\n", ca);
            ERR_print_errors_fp(stderr); SSL_CTX_free(ctx); return NULL;
        }
        if (ca) {   /* tell the client which CAs we accept */
            STACK_OF(X509_NAME) *names = SSL_load_client_CA_file(ca);
            if (names) SSL_CTX_set_client_CA_list(ctx, names);
        }
        if (verify == HM_TLS_VERIFY_REQUIRE) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
        SSL_CTX_set_verify(ctx, flags,
            verify == HM_TLS_VERIFY_OPTIONAL ? hm_tls_verify_cb : NULL);
    }
    return ctx;
}

/* Copy a context's session-ticket key into buf (at most HM_TLS_TKEY_MAX
 * bytes) and report its length. The size is asked of the library rather than
 * assumed - it differs between 1.1.1 and 3.x, and the getter answers a
 * mismatched length with a plain 0. Returns 1 on success, 0 if the library
 * cannot report one (built without TLSEXT, or TLS not compiled in here). */
static int hm_tls_get_ticket_key(void *ctxv, unsigned char *buf, size_t *len) {
#ifdef HM_HAVE_TICKET_KEYS
    long need;
    if (!ctxv) return 0;
    need = SSL_CTX_ctrl((SSL_CTX *)ctxv, SSL_CTRL_GET_TLSEXT_TICKET_KEYS,
                        0, NULL);                    /* 0/NULL asks the size */
    if (need <= 0 || (size_t)need > HM_TLS_TKEY_MAX) return 0;
    if (SSL_CTX_get_tlsext_ticket_keys((SSL_CTX *)ctxv, buf, need) != 1)
        return 0;
    *len = (size_t)need;
    return 1;
#else
    (void)ctxv; (void)buf; (void)len;
    return 0;
#endif
}

/* Build the default SSL_CTX plus any SNI per-host contexts (sni_hv:
 * { host => { cert => ..., key => ... }, ... }). The registry is attached to



( run in 0.958 second using v1.01-cache-2.11-cpan-8dfa8b56332 )