Attached is an updated patch for CVS HEAD, plus a patch for the 1.0.2
branch.
Are you still accepting patches for 1.0.1?
Any chance of reviewing these patches soon?
Thanks.
On 19/06/12 21:15, Rob Stradling via RT wrote:
> The OCSP Stapling Callback function (s->ctx->tlsext_status_cb) is called
> during the parsing of the ClientHello message, before the server has
> decided which cipher to use. However, since the choice of cipher can
> influence which server certificate is sent, this means that the wrong
> OCSP Response may be sent in cases where multiple server certificates
> are configured.
>
> The attached patch against CVS HEAD makes the following changes:
> - Moves the s->ctx->tlsext_status_cb() call to just after the cipher
> has been chosen. This involves splitting ssl_check_clienthello_tlsext()
> into two functions: "early" and "late".
> - Updates SSL_get_certificate() so that it returns the server
> certificate that actually gets sent. (This is the function that Apache
> httpd's OCSP Stapling code calls in order to determine which OCSP
> Response to send).
>
> I've tested this patch successfully with an installation of httpd 2.4.2
> that has both an RSA cert and an ECC cert configured.
>
> If this patch is OK, I'd like to backport it to the OpenSSL 1.0.x branch
> as well.
>
--
Rob Stradling
Senior Research & Development Scientist
COMODO - Creating Trust Online
Index: ssl/s3_srvr.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_srvr.c,v
retrieving revision 1.239
diff -u -r1.239 s3_srvr.c
--- ssl/s3_srvr.c 15 Aug 2012 15:15:05 -0000 1.239
+++ ssl/s3_srvr.c 7 Sep 2012 10:00:12 -0000
@@ -1432,6 +1432,16 @@
* s->tmp.new_cipher - the new cipher to use.
*/
+ /* Handles TLS extensions that we couldn't check earlier */
+ if (s->version >= SSL3_VERSION)
+ {
+ if (ssl_check_clienthello_tlsext_late(s) <= 0)
+ {
+
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+ }
+
if (ret < 0) ret=1;
if (0)
{
Index: ssl/ssl_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_lib.c,v
retrieving revision 1.242
diff -u -r1.242 ssl_lib.c
--- ssl/ssl_lib.c 31 Aug 2012 11:18:54 -0000 1.242
+++ ssl/ssl_lib.c 7 Sep 2012 10:00:12 -0000
@@ -2336,7 +2336,7 @@
#endif
-static int ssl_get_server_cert_index(SSL *s)
+static int ssl_get_server_cert_index(const SSL *s)
{
int idx;
idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
@@ -2347,7 +2347,7 @@
return idx;
}
-CERT_PKEY *ssl_get_server_send_pkey(SSL *s)
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
{
CERT *c;
int i;
@@ -2833,6 +2833,14 @@
/* Fix this function so that it takes an optional type parameter */
X509 *SSL_get_certificate(const SSL *s)
{
+ if (s->server)
+ {
+ CERT_PKEY *certpkey;
+ certpkey = ssl_get_server_send_pkey(s);
+ if (certpkey && certpkey->x509)
+ return certpkey->x509;
+ }
+
if (s->cert != NULL)
return(s->cert->key->x509);
else
Index: ssl/ssl_locl.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_locl.h,v
retrieving revision 1.155
diff -u -r1.155 ssl_locl.h
--- ssl/ssl_locl.h 31 Aug 2012 11:18:54 -0000 1.155
+++ ssl/ssl_locl.h 7 Sep 2012 10:00:12 -0000
@@ -934,7 +934,7 @@
int ssl_undefined_function(SSL *s);
int ssl_undefined_void_function(void);
int ssl_undefined_const_function(const SSL *s);
-CERT_PKEY *ssl_get_server_send_pkey(SSL *);
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s);
unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length);
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
@@ -1201,6 +1201,7 @@
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned
char *limit);
unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned
char *limit);
int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char
*d, int n);
+int ssl_check_clienthello_tlsext_late(SSL *s);
int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char
*d, int n);
int ssl_prepare_clienthello_tlsext(SSL *s);
int ssl_prepare_serverhello_tlsext(SSL *s);
Index: ssl/t1_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/t1_lib.c,v
retrieving revision 1.139
diff -u -r1.139 t1_lib.c
--- ssl/t1_lib.c 29 Aug 2012 13:18:34 -0000 1.139
+++ ssl/t1_lib.c 7 Sep 2012 10:00:12 -0000
@@ -123,7 +123,7 @@
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
SSL_SESSION **psess);
-static int ssl_check_clienthello_tlsext(SSL *s);
+static int ssl_check_clienthello_tlsext_early(SSL *s);
int ssl_check_serverhello_tlsext(SSL *s);
#endif
@@ -2241,7 +2241,7 @@
return 0;
}
- if (ssl_check_clienthello_tlsext(s) <= 0)
+ if (ssl_check_clienthello_tlsext_early(s) <= 0)
{
SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT);
return 0;
@@ -2642,7 +2642,7 @@
return 1;
}
-static int ssl_check_clienthello_tlsext(SSL *s)
+static int ssl_check_clienthello_tlsext_early(SSL *s)
{
int ret=SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
@@ -2661,42 +2661,11 @@
else if (s->initial_ctx != NULL &&
s->initial_ctx->tlsext_servername_callback != 0)
ret = s->initial_ctx->tlsext_servername_callback(s, &al,
s->initial_ctx->tlsext_servername_arg);
- /* If status request then ask callback what to do.
- * Note: this must be called after servername callbacks in case
- * the certificate has changed.
- */
- if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
- {
- int r;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- switch (r)
- {
- /* We don't want to send a status request response */
- case SSL_TLSEXT_ERR_NOACK:
- s->tlsext_status_expected = 0;
- break;
- /* status request response should be sent */
- case SSL_TLSEXT_ERR_OK:
- if (s->tlsext_ocsp_resp)
- s->tlsext_status_expected = 1;
- else
- s->tlsext_status_expected = 0;
- break;
- /* something bad happened */
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
- }
- }
- else
- s->tlsext_status_expected = 0;
-
#ifdef TLSEXT_TYPE_opaque_prf_input
{
/* This sort of belongs into ssl_prepare_serverhello_tlsext(),
* but we might be sending an alert in response to the client
hello,
- * so this has to happen here in
ssl_check_clienthello_tlsext(). */
+ * so this has to happen here in
ssl_check_clienthello_tlsext_early(). */
int r = 1;
@@ -2748,8 +2717,8 @@
}
}
-#endif
err:
+#endif
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:
@@ -2767,6 +2736,59 @@
}
}
+int ssl_check_clienthello_tlsext_late(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_OK;
+ int al;
+
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed, and must be called after the cipher
+ * has been chosen because this may influence which certificate is sent
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
+
+ err:
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ default:
+ return 1;
+ }
+ }
+
int ssl_check_serverhello_tlsext(SSL *s)
{
int ret=SSL_TLSEXT_ERR_NOACK;
Index: ssl/s3_srvr.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/s3_srvr.c,v
retrieving revision 1.171.2.21.2.24.2.11
diff -u -r1.171.2.21.2.24.2.11 s3_srvr.c
--- ssl/s3_srvr.c 6 Jun 2012 12:45:14 -0000 1.171.2.21.2.24.2.11
+++ ssl/s3_srvr.c 19 Jul 2012 15:08:41 -0000
@@ -1418,6 +1418,16 @@
* s->tmp.new_cipher - the new cipher to use.
*/
+ /* Handles TLS extensions that we couldn't check earlier */
+ if (s->version >= SSL3_VERSION)
+ {
+ if (ssl_check_clienthello_tlsext_late(s) <= 0)
+ {
+
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+ }
+
if (ret < 0) ret=1;
if (0)
{
Index: ssl/ssl_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_lib.c,v
retrieving revision 1.176.2.19.2.24.2.7
diff -u -r1.176.2.19.2.24.2.7 ssl_lib.c
--- ssl/ssl_lib.c 3 Jun 2012 22:03:31 -0000 1.176.2.19.2.24.2.7
+++ ssl/ssl_lib.c 19 Jul 2012 15:08:41 -0000
@@ -2320,7 +2320,7 @@
#endif
/* THIS NEEDS CLEANING UP */
-static int ssl_get_server_cert_index(SSL *s)
+static int ssl_get_server_cert_index(const SSL *s)
{
unsigned long alg_k, alg_a;
@@ -2371,7 +2371,7 @@
}
}
-CERT_PKEY *ssl_get_server_send_pkey(SSL *s)
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
{
CERT *c;
int i;
@@ -2840,6 +2840,14 @@
/* Fix this function so that it takes an optional type parameter */
X509 *SSL_get_certificate(const SSL *s)
{
+ if (s->server)
+ {
+ CERT_PKEY *certpkey;
+ certpkey = ssl_get_server_send_pkey(s);
+ if (certpkey && certpkey->x509)
+ return certpkey->x509;
+ }
+
if (s->cert != NULL)
return(s->cert->key->x509);
else
Index: ssl/ssl_locl.h
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/ssl_locl.h,v
retrieving revision 1.100.2.10.2.17.2.11
diff -u -r1.100.2.10.2.17.2.11 ssl_locl.h
--- ssl/ssl_locl.h 29 May 2012 17:27:48 -0000 1.100.2.10.2.17.2.11
+++ ssl/ssl_locl.h 19 Jul 2012 15:08:41 -0000
@@ -866,7 +866,7 @@
int ssl_undefined_function(SSL *s);
int ssl_undefined_void_function(void);
int ssl_undefined_const_function(const SSL *s);
-CERT_PKEY *ssl_get_server_send_pkey(SSL *);
+CERT_PKEY *ssl_get_server_send_pkey(const SSL *s);
unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length);
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
@@ -1133,6 +1133,7 @@
unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned
char *limit);
unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned
char *limit);
int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char
*d, int n);
+int ssl_check_clienthello_tlsext_late(SSL *s);
int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char
*d, int n);
int ssl_prepare_clienthello_tlsext(SSL *s);
int ssl_prepare_serverhello_tlsext(SSL *s);
Index: ssl/t1_lib.c
===================================================================
RCS file: /v/openssl/cvs/openssl/ssl/t1_lib.c,v
retrieving revision 1.64.2.14.2.32.2.13
diff -u -r1.64.2.14.2.32.2.13 t1_lib.c
--- ssl/t1_lib.c 3 Jul 2012 20:21:35 -0000 1.64.2.14.2.32.2.13
+++ ssl/t1_lib.c 19 Jul 2012 15:08:41 -0000
@@ -123,7 +123,7 @@
static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
const unsigned char *sess_id, int sesslen,
SSL_SESSION **psess);
-static int ssl_check_clienthello_tlsext(SSL *s);
+static int ssl_check_clienthello_tlsext_early(SSL *s);
int ssl_check_serverhello_tlsext(SSL *s);
#endif
@@ -1846,7 +1846,7 @@
return 0;
}
- if (ssl_check_clienthello_tlsext(s) <= 0)
+ if (ssl_check_clienthello_tlsext_early(s) <= 0)
{
SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT);
return 0;
@@ -2247,7 +2247,7 @@
return 1;
}
-static int ssl_check_clienthello_tlsext(SSL *s)
+static int ssl_check_clienthello_tlsext_early(SSL *s)
{
int ret=SSL_TLSEXT_ERR_NOACK;
int al = SSL_AD_UNRECOGNIZED_NAME;
@@ -2266,42 +2266,11 @@
else if (s->initial_ctx != NULL &&
s->initial_ctx->tlsext_servername_callback != 0)
ret = s->initial_ctx->tlsext_servername_callback(s, &al,
s->initial_ctx->tlsext_servername_arg);
- /* If status request then ask callback what to do.
- * Note: this must be called after servername callbacks in case
- * the certificate has changed.
- */
- if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
- {
- int r;
- r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- switch (r)
- {
- /* We don't want to send a status request response */
- case SSL_TLSEXT_ERR_NOACK:
- s->tlsext_status_expected = 0;
- break;
- /* status request response should be sent */
- case SSL_TLSEXT_ERR_OK:
- if (s->tlsext_ocsp_resp)
- s->tlsext_status_expected = 1;
- else
- s->tlsext_status_expected = 0;
- break;
- /* something bad happened */
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- ret = SSL_TLSEXT_ERR_ALERT_FATAL;
- al = SSL_AD_INTERNAL_ERROR;
- goto err;
- }
- }
- else
- s->tlsext_status_expected = 0;
-
#ifdef TLSEXT_TYPE_opaque_prf_input
{
/* This sort of belongs into ssl_prepare_serverhello_tlsext(),
* but we might be sending an alert in response to the client
hello,
- * so this has to happen here in
ssl_check_clienthello_tlsext(). */
+ * so this has to happen here in
ssl_check_clienthello_tlsext_early(). */
int r = 1;
@@ -2353,8 +2322,8 @@
}
}
-#endif
err:
+#endif
switch (ret)
{
case SSL_TLSEXT_ERR_ALERT_FATAL:
@@ -2372,6 +2341,59 @@
}
}
+int ssl_check_clienthello_tlsext_late(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_OK;
+ int al;
+
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed, and must be called after the cipher
+ * has been chosen because this may influence which certificate is sent
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
+
+ err:
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ default:
+ return 1;
+ }
+ }
+
int ssl_check_serverhello_tlsext(SSL *s)
{
int ret=SSL_TLSEXT_ERR_NOACK;