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 )