Bug 55786 - SSLVerifyClient and OptRenegotiate result in a 403 Forbidden error
Summary: SSLVerifyClient and OptRenegotiate result in a 403 Forbidden error
Status: RESOLVED FIXED
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: mod_ssl (show other bugs)
Version: 2.4.6
Hardware: PC Linux
: P2 major (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords: FixedInTrunk
Depends on:
Blocks:
 
Reported: 2013-11-16 15:37 UTC by Reto Ischi
Modified: 2017-05-25 12:13 UTC (History)
3 users (show)



Attachments
Handle empty cert chain as no chain for quick renegotiation (1.36 KB, patch)
2016-08-11 12:27 UTC, Yann Ylavic
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Reto Ischi 2013-11-16 15:37:20 UTC
openssl version: 1.0.1e

1. simple httpd.conf:
======================================================================
User daemon
Listen 8000
ServerName test
DocumentRoot /tmp

LoadModule ssl_module bin/mod_ssl.so
SSLSessionCache shmcb:log/ssl_scache(512000)

PidFile  /tmp/httpd.pid
ErrorLog /tmp/httpd.log
LogLevel debug

SSLEngine on
SSLCertificateKeyFile /opt/airlock/ext-apache/conf/ssl.key/server.key
SSLCertificateFile  /opt/airlock/ext-apache/conf/ssl.crt/server.crt
SSLCACertificateFile /opt/airlock/ext-apache/conf/ssl.crt/client-ca.crt
SSLVerifyDepth 3

<Location /cert>
        SSLVerifyClient require
        SSLOptions +OptRenegotiate
</Location>

<Location /nocert>
        SSLVerifyClient none
        SSLOptions -OptRenegotiate
</Location>
======================================================================

2) Request to /cert/, full ssl handshake, client sends valid certificate without an intermediate CA certificate, request is accepted by httpd

3) Request to /nocert/ within TCP keep-alive timeout (same httpd process used), no client certificate requested, request accepted by httpd

4) Request again to /cert/ within TCP keep-alive, quick renegotiation initiated, no client cert requested, 403 forbidden send to client, apache error log shows: Cannot find peer certificate chain

ssl_engine_kernel.c:

 672         if (renegotiate_quick) {
 673             STACK_OF(X509) *cert_stack;
 674 
 675             /* perform just a manual re-verification of the peer */
 676             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02258)
 677                          "Performing quick renegotiation: "
 678                          "just re-verifying the peer");
 679 
 680             cert_stack = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl);
 681 
 682             cert = SSL_get_peer_certificate(ssl);
 683 
 684             if (!cert_stack && cert) {
 685                 /* client cert is in the session cache, but there is
 686                  * no chain, since ssl3_get_client_certificate()
 687                  * sk_X509_shift-ed the peer cert out of the chain.
 688                  * we put it back here for the purpose of quick_renegotiation.
 689                  */
 690                 cert_stack = sk_X509_new_null();
 691                 sk_X509_push(cert_stack, cert);
 692             }
 693 
 694             if (!cert_stack || (sk_X509_num(cert_stack) == 0)) {
 695                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02222)
 696                               "Cannot find peer certificate chain");
 697 
 698                 return HTTP_FORBIDDEN;
 699             }

In the second request to /cert/, "cert_stack" (line: 680) and "cert" (line: 682) is not NULL but sk_X509_num(cert_stack) is 0 (line: 694), therefore we get the error "Cannot find peer certificate chain” on line 695.

Configuration workarounds we can’t apply:

a) Removing “OptRenegotiate” on /cert/. We need this feature to prevent client certificate requests with every access to /cert

b) Setting SSLVerifyClient to require or optional on the whole virtual host: Not possible because requests to /nocert should not trigger a certificate request.

c) Disable keep-alive.

Our expectation:

In step 4) httpd performs a quick renegotiation without asking the client to send again his certificate. The cached client certificate is validated against the configured CA certificate and the request is accepted. SSL_get_peer_cert_chain() may return an empty chain because the client does not send an intermediate CA certificate. This should not result in an 403 access forbidden if the cached certificate and the configured CA cert forms a valid certificate chain.

Related bug report (but not the same issue): https://issues.apache.org/bugzilla/show_bug.cgi?id=47055
The patches there changes the behaviour but causes other problems (intermediate CAs not cached and cause another 403 access denies in a quick renegotiation).
Comment 1 Yann Ylavic 2016-08-11 12:27:08 UTC
Created attachment 34123 [details]
Handle empty cert chain as no chain for quick renegotiation

Does this patch fixes the issue ?
Comment 2 Petter A. Urkedal 2016-08-12 11:52:35 UTC
(In reply to Yann Ylavic from comment #1)
> Created attachment 34123 [details]
> Handle empty cert chain as no chain for quick renegotiation
> 
> Does this patch fixes the issue ?

Yes, thanks!  I rebuilt httpd-2.4.6-40.el7.centos.4.x86_64 with your patch, which applied cleanly.  With Chromium the page would consistently fail after the first reload of the page, after applying the patch, there are no failures.

(Well, we still have a lot of "AH02261: Re-negotiation handshake failed: Not accepted by client!?", but we had that on the EL 6 server as well, and seemingly does not cause any real issue.)

I'll try to get it into EL 7, unless you'd like to do it.
Comment 3 Reto Ischi 2016-08-16 11:53:01 UTC
(In reply to Yann Ylavic from comment #1)
> Created attachment 34123 [details]
> Handle empty cert chain as no chain for quick renegotiation
> 
> Does this patch fixes the issue ?

Works for me as well. Thanks!
Comment 4 Yann Ylavic 2016-08-16 22:05:29 UTC
Committed in r1756542 and proposed for backport to 2.4.x.
Comment 5 Christophe JAILLET 2017-05-25 12:13:58 UTC
This has been merged in 2.4.x in r1770838.

This is part of version 2.4.24