@@ -82,6 +82,9 @@ apr_status_t serf_ssl_set_certificates_directory(serf_ssl_context_t *ssl_ctx,
8282 const char * path);
8383apr_status_t serf_ssl_set_certificates_file (serf_ssl_context_t *ssl_ctx,
8484 const char * file);
85+ int serf_ssl_check_host (const serf_ssl_certificate_t *cert,
86+ const char * hostname);
87+
8588} // extern "C"
8689
8790namespace net_instaweb {
@@ -237,18 +240,19 @@ int64 SerfFetch::TimeDuration() const {
237240
238241#if SERF_HTTPS_FETCHING
239242// static
240- apr_status_t SerfFetch::SSLCertError (void *data, int failures,
243+ apr_status_t SerfFetch::SSLCertValidate (void *data, int failures,
241244 const serf_ssl_certificate_t *cert) {
242- return static_cast <SerfFetch*>(data)->HandleSSLCertErrors (failures, 0 );
245+ return static_cast <SerfFetch*>(data)->HandleSSLCertValidation (
246+ failures, 0 , cert);
243247}
244248
245249// static
246- apr_status_t SerfFetch::SSLCertChainError (
250+ apr_status_t SerfFetch::SSLCertChainValidate (
247251 void *data, int failures, int error_depth,
248252 const serf_ssl_certificate_t * const *certs,
249253 apr_size_t certs_count) {
250- return static_cast <SerfFetch*>(data)->HandleSSLCertErrors (failures,
251- error_depth);
254+ return static_cast <SerfFetch*>(data)->HandleSSLCertValidation (
255+ failures, error_depth, NULL );
252256}
253257#endif
254258
@@ -293,12 +297,11 @@ apr_status_t SerfFetch::ConnectionSetup(
293297 }
294298 }
295299
296- serf_ssl_server_cert_callback_set (fetch-> ssl_context_ , SSLCertError,
297- fetch);
300+ serf_ssl_server_cert_callback_set (
301+ fetch-> ssl_context_ , SSLCertValidate, fetch);
298302
299- serf_ssl_server_cert_chain_callback_set (fetch->ssl_context_ ,
300- SSLCertError, SSLCertChainError,
301- fetch);
303+ serf_ssl_server_cert_chain_callback_set (
304+ fetch->ssl_context_ , SSLCertValidate, SSLCertChainValidate, fetch);
302305
303306 status = serf_ssl_set_hostname (fetch->ssl_context_ , fetch->sni_host_ );
304307 if (status != APR_SUCCESS) {
@@ -382,14 +385,15 @@ bool SerfFetch::IsStatusOk(apr_status_t status) {
382385}
383386
384387#if SERF_HTTPS_FETCHING
385- apr_status_t SerfFetch::HandleSSLCertErrors (int errors, int failure_depth) {
388+ apr_status_t SerfFetch::HandleSSLCertValidation (
389+ int errors, int failure_depth, const serf_ssl_certificate_t *cert) {
386390 // TODO(jmarantz): is there value in logging the errors and failure_depth
387391 // formals here?
388392
389- // Note that HandleSSLCertErrors can be called multiple times for
390- // a single request. As far as I can tell, there is value in
391- // recording only one of these. For now, I have set up the logic
392- // so only the last error will be printed lazilly, in ReadHeaders.
393+ // Note that HandleSSLCertValidation can be called multiple times for a single
394+ // request. As far as I can tell, there is value in recording only one of
395+ // these. For now, I have set up the logic so only the last error will be
396+ // printed lazilly, in ReadHeaders.
393397 if (((errors & SERF_SSL_CERT_SELF_SIGNED) != 0 ) &&
394398 !fetcher_->allow_self_signed ()) {
395399 ssl_error_message_ = " SSL certificate is self-signed" ;
@@ -406,9 +410,35 @@ apr_status_t SerfFetch::HandleSSLCertErrors(int errors, int failure_depth) {
406410 ssl_error_message_ = " SSL certificate has an unknown error" ;
407411 }
408412
413+ if (ssl_error_message_ == NULL && async_fetch_ != NULL ) {
414+ if (// If cert is null that means we're being called via SSLCertChainError.
415+ // We only need to check the host name matches when being called via
416+ // SSLCertError, in which case cert won't be null.
417+ cert != NULL &&
418+ // No point in checking the host if we're allowing self-signed or a made
419+ // up CA, since people can forge whatever they want and often don't
420+ // bother to make the name match.
421+ !fetcher_->allow_self_signed () &&
422+ !fetcher_->allow_unknown_certificate_authority ()) {
423+
424+ DCHECK (serf_ssl_cert_depth (cert) == 0 ) <<
425+ " Serf should be filtering out intermediate certs before hitting us." ;
426+
427+ // You would think we could do whatever serf_get.c does, but it turns
428+ // out that does no checking at all. There's x509_check_host, added in
429+ // 1.0.2, but when svn uses serf it rolls its own check because it wants
430+ // to support older versions. We generally build with boringssl, which
431+ // forked from 1.0.2 and has always had this function, but when we build
432+ // with openssl we now require 1.0.2.
433+ if (serf_ssl_check_host (cert, sni_host_) != 1 ) {
434+ ssl_error_message_ = " Failed to match host." ;
435+ }
436+ }
437+ }
438+
409439 // Immediately call the fetch callback on a cert error. Note that
410- // HandleSSLCertErrors is called multiple times when there is an error,
411- // so check async_fetch before CallCallback.
440+ // HandleSSLCertValidation is called multiple times when there is an error, so
441+ // check async_fetch before CallCallback.
412442 if ((ssl_error_message_ != NULL ) && (async_fetch_ != NULL )) {
413443 fetcher_->cert_errors_ ->Add (1 );
414444 CallCallback (false ); // sets async_fetch_ to null.
0 commit comments