/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
/* _ _ *___________||______||mod_ssl *|'_`_\/_\/_`|/__/__||ApacheInterfacetoOpenSSL *||||||(_)|(_||\__\__\| *|_||_||_|\___/\__,_|___|___/___/_| *|_____| *ssl_engine_kernel.c *TheSSLenginekernel
*/ /* ``It took me fifteen years to discover Ihadnotalentforprogramming,but Icouldn'tgiveitupbecausebythat timeIwastoofamous.''
-- Unknown */ #include"ssl_private.h" #include"mod_ssl.h" #include"util_md5.h" #include"scoreboard.h"
/* Perform a speculative (and non-blocking) read from the connection *filtersforthegivenrequest,todeterminewhetherthereisany
* pending data to read. Return non-zero if there is, else zero. */ staticint has_buffered_data(request_rec *r)
{
apr_bucket_brigade *bb;
apr_off_t len;
apr_status_t rv; int result;
/* If a renegotiation is required for the location, and the request *includesamessagebody(andtheclienthasnotrequesteda"100 *Continue"response),thentheclientwillbestreamingtherequest *bodyoverthewirealready.Inthatcase,itisnotpossibleto *stopandperformanewSSLhandshakeimmediately;oncetheSSL *librarymovestothe"accept"state,itwillrejecttheSSLpackets *whichtheclientissendingfortherequestbody. * *Toallowauthenticationtocompleteinthehook,thesolutionused *hereistofilla(bounded)bufferwiththerequestbody,andthen *toreinjectthatrequestbodylater. * *Thisfunctioniscalledtofilltherenegotiationbufferforthe *locationasrequired,orfail.ReturnszeroonsuccessorHTTP_ *errorcodeonfailure.
*/ staticint fill_reneg_buffer(request_rec *r, SSLDirConfigRec *dc)
{ int rv;
apr_size_t rsize;
/* ### this is HTTP/1.1 specific, special case for protocol? */ if (r->expecting_100 || !ap_request_has_body(r)) { return0;
}
rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : dc->nRenegBufferSize; if (rsize > 0) { /* Fill the I/O buffer with the request body if possible. */
rv = ssl_io_buffer_fill(r, rsize);
} else { /* If the reneg buffer size is set to zero, just fail. */
rv = HTTP_REQUEST_ENTITY_TOO_LARGE;
}
for (i = 0; i < s1->nelts; i++) {
c = APR_ARRAY_IDX(s1, i, constchar *); if (!c || !ap_array_str_contains(s2, c)) { return0;
}
} return1;
}
staticint ssl_pk_server_compatible(modssl_pk_server_t *pks1,
modssl_pk_server_t *pks2)
{ if (!pks1 || !pks2) { return0;
} /* both have the same certificates? */ if ((pks1->ca_name_path != pks2->ca_name_path)
&& (!pks1->ca_name_path || !pks2->ca_name_path
|| strcmp(pks1->ca_name_path, pks2->ca_name_path))) { return0;
} if ((pks1->ca_name_file != pks2->ca_name_file)
&& (!pks1->ca_name_file || !pks2->ca_name_file
|| strcmp(pks1->ca_name_file, pks2->ca_name_file))) { return0;
} if (!ap_array_same_str_set(pks1->cert_files, pks2->cert_files)
|| !ap_array_same_str_set(pks1->key_files, pks2->key_files)) { return0;
} return1;
}
staticint ssl_auth_compatible(modssl_auth_ctx_t *a1,
modssl_auth_ctx_t *a2)
{ if (!a1 || !a2) { return0;
} /* both have the same verification */ if ((a1->verify_depth != a2->verify_depth)
|| (a1->verify_mode != a2->verify_mode)) { return0;
} /* both have the same ca path/file */ if ((a1->ca_cert_path != a2->ca_cert_path)
&& (!a1->ca_cert_path || !a2->ca_cert_path
|| strcmp(a1->ca_cert_path, a2->ca_cert_path))) { return0;
} if ((a1->ca_cert_file != a2->ca_cert_file)
&& (!a1->ca_cert_file || !a2->ca_cert_file
|| strcmp(a1->ca_cert_file, a2->ca_cert_file))) { return0;
} /* both have the same ca cipher suite string */ if ((a1->cipher_suite != a2->cipher_suite)
&& (!a1->cipher_suite || !a2->cipher_suite
|| strcmp(a1->cipher_suite, a2->cipher_suite))) { return0;
} /* both have the same ca cipher suite string */ if ((a1->tls13_ciphers != a2->tls13_ciphers)
&& (!a1->tls13_ciphers || !a2->tls13_ciphers
|| strcmp(a1->tls13_ciphers, a2->tls13_ciphers))) { return0;
} return1;
}
/* If we are on a slave connection, we do not expect to have an SSLConnRec,
* but our master connection might. */
sslconn = myConnConfig(r->connection); if (!(sslconn && sslconn->ssl) && r->connection->master) {
sslconn = myConnConfig(r->connection->master);
}
if (!sslconn) { return DECLINED;
}
if (sslconn->service_unavailable) { /* This is set when the SSL properties of this connection are *incompleteorifthisconnectionwasmadetochallengea *particularhostname(ACME).Weneverserveanyrequeston
* such a connection. */ /* TODO: a retry-after indicator would be nice here */ return HTTP_SERVICE_UNAVAILABLE;
}
if (sslconn->non_ssl_request == NON_SSL_SET_ERROR_MSG) {
apr_table_setn(r->notes, "error-notes", "Reason: You're speaking plain HTTP to an SSL-enabled " "server port.<br />\n Instead use the HTTPS scheme to " "access this URL, please.<br />\n");
/* Now that we have caught this error, forget it. we are done *withusingSSLonthisrequest.
*/
sslconn->non_ssl_request = NON_SSL_OK;
/* SetEnvIf ssl-*-shutdown flags can only be per-server, *sotheywon'tchangeacrosskeepaliverequests
*/ if (sslconn->shutdown_type == SSL_SHUTDOWN_TYPE_UNSET) {
ssl_configure_env(r, sslconn);
}
/* cleanup */ if (cipher_list_old) {
sk_SSL_CIPHER_free(cipher_list_old);
}
if (renegotiate) { if (r->connection->master) { /* The request causes renegotiation on a slave connection. *Thisisnotallowedsincewemighthaveconcurrentrequests *onthisconnection.
*/
apr_table_setn(r->notes, "ssl-renegotiate-forbidden", "cipher-suite"); return HTTP_FORBIDDEN;
}
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE if (sc->cipher_server_pref == TRUE) {
SSL_set_options(ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
} #endif /* tracing */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02220) "Reconfigured cipher suite will force renegotiation");
}
}
/* TODO: this seems premature since we do not know if there *areanychangesrequired.
*/
SSL_set_verify(ssl, verify, ssl_callback_SSLVerify);
SSL_set_verify_result(ssl, X509_V_OK);
/* determine whether we've to force a renegotiation */ if (!renegotiate && verify != verify_old) { if (((verify_old == SSL_VERIFY_NONE) &&
(verify != SSL_VERIFY_NONE)) ||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02255) "Changed client verification type will force " "%srenegotiation",
renegotiate_quick ? "quick " : "");
} elseif (verify != SSL_VERIFY_NONE) { /* *overrideofSSLVerifyDepth * *Thedepthchecksarehandledbyusmanuallyinsidethe *verifycallbackfunctionandnotbyOpenSSLinternally *(andourfunctionisawareofboththeper-serverand *per-directorycontexts).SowecannotaskOpenSSLabout *thecurrentlyverifydepth.Insteadwerememberitinour *SSLConnRecattachedtotheSSL*ofOpenSSL.We'vetoforce *therenegotiationifthereconfigured/newverifydepthis *lessthanthecurrentlyactive/rememberedverifydepth *(becausethismeansmorerestrictiononthecertificate *chain).
*/
n = (sslconn->verify_depth != UNSET)
? sslconn->verify_depth
: hssc->server->auth.verify_depth; /* determine the new depth */
sslconn->verify_depth = (dc->nVerifyDepth != UNSET)
? dc->nVerifyDepth
: sc->server->auth.verify_depth; if (sslconn->verify_depth < n) {
renegotiate = TRUE;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02254) "Reduced client verification depth will " "force renegotiation");
}
}
} /* If we're handling a request for a vhost other than the default one, *thenweneedtomakesurethatclientauthenticationisproperly *enforced.ForclientssupplyinganSNIextension,thepeer *certificateverificationhashappenedinthehandshakealready *(andr->server==handshakeserver).Fornon-SNIrequests, *anadditionalcheckisneededhere.Ifclientauthentication *isconfiguredasmandatory,thenwecanonlyproceedifthe *CAlistdoesn'thavetobechanged(OpenSSLdoesn'tprovide *anoptiontochangethelistforanexistingsession).
*/ if ((r->server != handshakeserver)
&& renegotiate
&& ((verify & SSL_VERIFY_PEER) ||
(verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) { #define MODSSL_CFG_CA_NE(f, sc1, sc2) \
(sc1->server->auth.f && \
(!sc2->server->auth.f || \
strNE(sc1->server->auth.f, sc2->server->auth.f)))
if (MODSSL_CFG_CA_NE(ca_cert_file, sc, hssc) ||
MODSSL_CFG_CA_NE(ca_cert_path, sc, hssc)) { if (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02256) "Non-default virtual host with SSLVerify set to " "'require' and VirtualHost-specific CA certificate " "list is only available to clients with TLS server " "name indication (SNI) support");
SSL_set_verify(ssl, verify_old, NULL); return HTTP_FORBIDDEN;
} else /* let it pass, possibly with an "incorrect" peer cert, *somakesuretheSSL_CLIENT_VERIFYenvironmentvariable *willindicatepartialsuccessonly,lateron.
*/
sslconn->verify_info = "GENEROUS";
}
}
}
/* Fill reneg buffer if required. */ if (renegotiate && !renegotiate_quick) {
rc = fill_reneg_buffer(r, dc); if (rc) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02257) "could not buffer message body to allow " "SSL renegotiation to proceed"); return rc;
}
}
if (renegotiate_quick) {
STACK_OF(X509) *cert_stack;
X509 *cert;
/* perform just a manual re-verification of the peer */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02258) "Performing quick renegotiation: " "just re-verifying the peer");
if (!cert_stack || (sk_X509_num(cert_stack) == 0)) { if (!cert) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02222) "Cannot find peer certificate chain");
return HTTP_FORBIDDEN;
}
/* client cert is in the session cache, but there is *nochain,sincessl3_get_client_certificate() *sk_X509_shift-edthepeercertoutofthechain. *weputitbackhereforthepurposeofquick_renegotiation.
*/
cert_stack = sk_X509_new_null();
sk_X509_push(cert_stack, cert);
}
if (cert_stack != SSL_get_peer_cert_chain(ssl)) { /* we created this ourselves, so free it */
sk_X509_pop_free(cert_stack, X509_free);
}
} else { char peekbuf[1]; constchar *reneg_support;
request_rec *id = r->main ? r->main : r;
/* Additional mitigation for CVE-2009-3555: At this point, *beforerenegotiating,an(entire)requesthasbeenread *fromtheconnection.Anattackermayhavesentfurther *datato"prefix"anysubsequentrequestbythevictim's *clientaftertherenegotiation;thisdatamayalready *havebeenreadandbuffered.Forcingaconnection *closureaftertheresponseensuressuchdatawillbe *discarded.LegimatelypipelinedHTTPrequestswillbe
* retried anyway with this approach. */ if (has_buffered_data(r)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02259) "insecure SSL re-negotiation required, but " "a pipelined request is present; keepalive " "disabled");
r->connection->keepalive = AP_CONN_CLOSE;
}
#ifdefined(SSL_get_secure_renegotiation_support)
reneg_support = SSL_get_secure_renegotiation_support(ssl) ? "client does" : "client does not"; #else
reneg_support = "server does not"; #endif /* Perform a full renegotiation. */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02260) "Performing full renegotiation: complete handshake " "protocol (%s support secure renegotiation)",
reneg_support);
/* XXX: Should replace setting state with SSL_renegotiate(ssl); *However,thiscausesfailuresinperl-frameworkcurrently, *perhapspre-testifwehavealreadynegotiated?
*/ /* Need to trigger renegotiation handshake by reading. *Peeking0bytesactuallyworks. *See:http://marc.info/?t=145493359200002&r=1&w=2
*/
SSL_peek(ssl, peekbuf, 0);
/* *AlsocheckthatSSLCipherSuitehasbeenenforcedasexpected.
*/ if (cipher_list) {
cipher = SSL_get_current_cipher(ssl); if (sk_SSL_CIPHER_find(cipher_list, cipher) < 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02264) "SSL cipher suite not renegotiated: " "access to %s denied using cipher %s",
r->filename,
SSL_CIPHER_get_name(cipher)); return HTTP_FORBIDDEN;
}
} /* remember any new cipher suite used in renegotiation */ if (ncipher_suite) {
sslconn->cipher_suite = ncipher_suite;
}
}
return DECLINED;
}
#if SSL_HAVE_PROTOCOL_TLSV1_3 /* *AccessHandler,modernflavour,forSSL/TLSv1.3andonward. *Onlyclientcertificatescanberequested,everythingelsestays.
*/ staticint ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirConfigRec *dc,
SSLConnRec *sslconn, SSL *ssl)
{ if ((dc->nVerifyClient != SSL_CVERIFY_UNSET) ||
(sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) { int vmode_inplace, vmode_needed; int change_vmode = FALSE; int n, rc;
if (vmode_needed == SSL_VERIFY_NONE) { return DECLINED;
}
vmode_needed |= SSL_VERIFY_CLIENT_ONCE; if (vmode_inplace != vmode_needed) { /* Need to change, if new setting is more restrictive than existing one */
if ((vmode_inplace == SSL_VERIFY_NONE)
|| (!(vmode_inplace & SSL_VERIFY_PEER)
&& (vmode_needed & SSL_VERIFY_PEER))
|| (!(vmode_inplace & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
&& (vmode_needed & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) { /* need to change the effective verify mode */
change_vmode = TRUE;
} else { /* FIXME: does this work with TLSv1.3? Is this more than re-inspecting
* the certificate we should already have? */ /* *overrideofSSLVerifyDepth * *Thedepthchecksarehandledbyusmanuallyinsidethe *verifycallbackfunctionandnotbyOpenSSLinternally *(andourfunctionisawareofboththeper-serverand *per-directorycontexts).SowecannotaskOpenSSLabout *thecurrentlyverifydepth.Insteadwerememberitinour *SSLConnRecattachedtotheSSL*ofOpenSSL.We'vetoforce *therenegotiationifthereconfigured/newverifydepthis *lessthanthecurrentlyactive/rememberedverifydepth *(becausethismeansmorerestrictiononthecertificate *chain).
*/
n = (sslconn->verify_depth != UNSET)?
sslconn->verify_depth : sc->server->auth.verify_depth; /* determine the new depth */
sslconn->verify_depth = (dc->nVerifyDepth != UNSET)
? dc->nVerifyDepth
: sc->server->auth.verify_depth; if (sslconn->verify_depth < n) {
change_vmode = TRUE;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(10128) "Reduced client verification depth will " "force renegotiation");
}
}
}
/* Fill reneg buffer if required. */ if (change_vmode) { char peekbuf[1];
if (r->connection->master) { /* FIXME: modifying the SSL on a slave connection is no good. *Wewouldneedtopushthisbacktothemasterconnection *somehow.
*/
apr_table_setn(r->notes, "ssl-renegotiate-forbidden", "verify-client"); return HTTP_FORBIDDEN;
}
rc = fill_reneg_buffer(r, dc); if (rc) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10228) "could not buffer message body to allow " "TLS Post-Handshake Authentication to proceed"); return rc;
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(10129) "verify client post handshake");
SSL_do_handshake(ssl); /* Need to trigger renegotiation handshake by reading. *Peeking0bytesactuallyworks. *See:http://marc.info/?t=145493359200002&r=1&w=2
*/
SSL_peek(ssl, peekbuf, 0);
/* On a slave connection, we do not expect to have an SSLConnRec, but
* our master connection might have one. */ if (!(sslconn && ssl) && r->connection->master) {
sslconn = myConnConfig(r->connection->master);
ssl = sslconn ? sslconn->ssl : NULL;
}
#if SSL_HAVE_PROTOCOL_TLSV1_3 /* TLSv1.3+ is less complicated here. Branch off into a new codeline
* and avoid messing with the past. */ if (SSL_version(ssl) >= TLS1_3_VERSION) {
ret = ssl_hook_Access_modern(r, sc, dc, sslconn, ssl);
} else #endif
{
ret = ssl_hook_Access_classic(r, sc, dc, sslconn, ssl);
}
if (ret != DECLINED) { return ret;
}
/* If we're trying to have the user name set from a client *certificatethenweneedtosetithere.Thisshouldbesafeas *theusernameprobablyisn'timportantfromanauthcheckingpoint *ofviewasthecertificatesuppliedactsinthatcapacity. *However,ifFakeAuthisbeingusedthenthisisn'tthecaseso *weneedtopostponesettingtheusernameuntillater.
*/ if ((dc->nOptions & SSL_OPT_FAKEBASICAUTH) == 0 && dc->szUserName) { char *val = ssl_var_lookup(r->pool, r->server, r->connection,
r, (char *)dc->szUserName); if (val && val[0])
r->user = val; else
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02227) "Failed to set r->user to '%s'", dc->szUserName);
}
if (!modssl_request_is_tls(r, &sslconn)) { return DECLINED;
}
ssl = sslconn->ssl;
/* *AnnotatetheSSI/CGIenvironmentwithstandardSSLinformation
*/ /* the always present HTTPS (=HTTP over SSL) flag! */
apr_table_setn(env, "HTTPS", "on");
#ifdef HAVE_TLSEXT /* add content of SNI TLS extension (if supplied with ClientHello) */ if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
apr_table_set(env, "SSL_TLS_SNI", servername);
} #endif
/* standard SSL environment variables */ if (dc->nOptions & SSL_OPT_STDENVVARS) {
modssl_var_extract_dns(env, ssl, r->pool);
modssl_var_extract_san_entries(env, ssl, r->pool);
for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
var = (char *)ssl_hook_Fixup_vars[i];
val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); if (!strIsEmpty(val)) {
apr_table_setn(env, var, val);
}
}
}
/* *On-demandbloatuptheSSI/CGIenvironmentwithcertificatedata
*/ if (dc->nOptions & SSL_OPT_EXPORTCERTDATA) {
val = ssl_var_lookup(r->pool, r->server, r->connection,
r, "SSL_SERVER_CERT");
apr_table_setn(env, "SSL_SERVER_CERT", val);
val = ssl_var_lookup(r->pool, r->server, r->connection,
r, "SSL_CLIENT_CERT");
apr_table_setn(env, "SSL_CLIENT_CERT", val);
if ((peer_certs = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl))) { for (i = 0; i < sk_X509_num(peer_certs); i++) {
var = apr_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i);
val = ssl_var_lookup(r->pool, r->server, r->connection,
r, var); if (val) {
apr_table_setn(env, var, val);
}
}
}
}
staticconstchar *ssl_authz_require_ssl_parse(cmd_parms *cmd, constchar *require_line, constvoid **parsed)
{ if (require_line && require_line[0]) return"'Require ssl' does not take arguments";
staticconstchar *ssl_authz_verify_client_parse(cmd_parms *cmd, constchar *require_line, constvoid **parsed)
{ if (require_line && require_line[0]) return"'Require ssl-verify-client' does not take arguments";
/* Get verify ingredients */ int errnum = X509_STORE_CTX_get_error(ctx); int errdepth = X509_STORE_CTX_get_error_depth(ctx); int depth = UNSET; int verify = SSL_CVERIFY_UNSET;
if (errdepth > depth) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, APLOGNO(02040) "Certificate Verification: Certificate Chain too long " "(chain has %d certificates, but maximum allowed are " "only %d)",
errdepth, depth);
/* *GetApachecontextbackthroughOpenSSLcontext
*/ if (!(s = (server_rec *)SSL_CTX_get_app_data(ctx))) { return; /* on server shutdown Apache is already gone */
}
sc = mySrvConfig(s);
/* *RemovetheSSL_SESSIONfromtheinter-processcache
*/ #ifdef OPENSSL_NO_SSL_INTERN
id = (unsignedchar *)SSL_SESSION_get_id(session, &idlen); #else
id = session->session_id;
idlen = session->session_id_length; #endif
/* TODO: Do we need a temp pool here, or are we always shutting down? */
ssl_scache_remove(s, id, idlen, sc->mc->pPool);
/* *ThiscallbackfunctionisexecutedwhileOpenSSLprocessestheSSL *handshakeanddoesSSLrecordlayerstuff.It'susedtotrap *client-initiatedrenegotiations(whereSSL_OP_NO_RENEGOTIATIONis *notavailable),andfordumpingeverythingtothelog.
*/ void ssl_callback_Info(const SSL *ssl, int where, int rc)
{
conn_rec *c;
server_rec *s;
/* Retrieve the conn_rec and the associated SSLConnRec. */ if ((c = (conn_rec *)SSL_get_app_data((SSL *)ssl)) == NULL) { return;
}
#ifndef SSL_OP_NO_RENEGOTIATION /* With OpenSSL < 1.1.1 (implying TLS v1.2 or earlier), this *callbackisusedtoblockclient-initiatedrenegotiation.With *TLSv1.3itisunnecessarysincerenegotiationisforbiddenat *protocollevel.Otherwise(TLSv1.2withOpenSSL>=1.1.1),
* SSL_OP_NO_RENEGOTIATION is used to block renegotiation. */
{
SSLConnRec *sslconn;
if ((sslconn = myConnConfig(c)) == NULL) { return;
}
/* If the reneg state is to reject renegotiations, check the SSL *statemachineandmovetoABORTifaClientHelloisbeing
* read. */ if (!c->outgoing &&
(where & SSL_CB_HANDSHAKE_START) &&
sslconn->reneg_state == RENEG_REJECT) {
sslconn->reneg_state = RENEG_ABORT;
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02042) "rejecting client initiated renegotiation");
} /* If the first handshake is complete, change state to reject any
* subsequent client-initiated renegotiation. */ elseif ((where & SSL_CB_HANDSHAKE_DONE)
&& sslconn->reneg_state == RENEG_INIT) {
sslconn->reneg_state = RENEG_REJECT;
}
} #endif
s = mySrvFromConn(c); if (s && APLOGdebug(s)) {
log_tracing_state(ssl, c, s, where, rc);
}
}
/* We can't use SSL_get_servername() at this earliest OpenSSL connection *stage,andthereisnoSSL_client_hello_get0_servername()providedas *ofOpenSSL1.1.1.Sothecodebelow,thatextractstheSNIfromthe *ClientHello'sTLSextensions,istakenfromsometestcodeinOpenSSL, *i.e.client_hello_select_server_ctx()in"test/handshake_helper.c".
*/
/* Extract the length of the supplied list of names. */
len = (*(pos++) << 8);
len += *(pos++); if (len + 2 != remaining) goto give_up;
remaining = len;
/* Now we can finally pull out the byte array with the actual hostname. */
len = (*(pos++) << 8);
len += *(pos++); if (len + 2 != remaining) goto give_up;
/* Use the SNI to switch to the relevant vhost, should it differ from *c->base_server.
*/
servername = apr_pstrmemdup(c->pool, (constchar *)pos, len);
/* If the connection object is not available,
* then there's nothing for us to do. */ if (c == NULL) { return SSL_TLSEXT_ERR_OK;
}
sslconn = myConnConfig(c);
if (inlen == 0) { /* someone tries to trick us? */
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02837) "ALPN client protocol list empty"); return SSL_TLSEXT_ERR_ALERT_FATAL;
}
client_protos = apr_array_make(c->pool, 0, sizeof(char *)); for (i = 0; i < inlen; /**/) { unsignedint plen = in[i++]; if (plen + i > inlen) { /* someone tries to trick us? */
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02838) "ALPN protocol identifier too long"); return SSL_TLSEXT_ERR_ALERT_FATAL;
}
APR_ARRAY_PUSH(client_protos, char *) =
apr_pstrndup(c->pool, (constchar *)in+i, plen);
i += plen;
}
/* The order the callbacks are invoked from TLS extensions is, unfortunately *notdefinedandolderopensslversionsdocallALPNselectionbefore *theycallbacktheSNI.Weneedtomakesurethatweknowwhichvhost *wearedealingwithsowerespectthecorrectprotocols.
*/
init_vhost(c, ssl, NULL);
len = strlen(proposed); if (len > 255) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02840) "ALPN negotiated protocol name too long"); return SSL_TLSEXT_ERR_ALERT_FATAL;
}
*out = (constunsignedchar *)proposed;
*outlen = (unsignedchar)len;
if (strcmp(proposed, ap_get_protocol(c))) {
apr_status_t status;
status = ap_switch_protocol(c, NULL, sslconn->server, proposed); if (status != APR_SUCCESS) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c,
APLOGNO(02908) "protocol switch to '%s' failed",
proposed); return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* protocol was switched, this could be a challenge protocol such as "acme-tls/1". *Forthattowork,weneedtoallowoverridestooursslcertificate. *However,excludechallengechecksonourbestknowntrafficprotocol. *(http/1.1isthedefault,weneverswitchtoitanyway.)
*/ if (strcmp("h2", proposed)) { constchar *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
X509 *cert;
EVP_PKEY *key; constchar *cert_pem, *key_pem;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.