Lines 29-34
Link Here
|
29 |
-- Unknown */ |
29 |
-- Unknown */ |
30 |
#include "mod_ssl.h" |
30 |
#include "mod_ssl.h" |
31 |
|
31 |
|
|
|
32 |
static int reneg_and_check(request_rec *r, int quick); |
33 |
|
32 |
/* |
34 |
/* |
33 |
* Post Read Request Handler |
35 |
* Post Read Request Handler |
34 |
*/ |
36 |
*/ |
Lines 159-164
Link Here
|
159 |
return DECLINED; |
161 |
return DECLINED; |
160 |
} |
162 |
} |
161 |
|
163 |
|
|
|
164 |
static ap_filter_rec_t *reneg_filter_rec; |
165 |
|
166 |
/* The renegotiation input filter is inserted into the input filter |
167 |
* stack to perform an SSL renegotatiation after the request body has |
168 |
* been read. It runs before the HTTP input filter and waits for it to return |
169 |
* an EOS; at which point it is safe to perform the SSL handshake. */ |
170 |
static apr_status_t reneg_in_filter(ap_filter_t *f, |
171 |
apr_bucket_brigade *bb, |
172 |
ap_input_mode_t mode, |
173 |
apr_read_type_e block, |
174 |
apr_off_t bytes) |
175 |
{ |
176 |
apr_bucket *bkt; |
177 |
apr_status_t rv; |
178 |
|
179 |
/* This filter needs to buffer each brigade into memory to ensure |
180 |
* that when an EOS is found, all data really has been read from |
181 |
* the socket. So, ensure that not too much is buffered: */ |
182 |
if (bytes > HUGE_STRING_LEN) { |
183 |
bytes = HUGE_STRING_LEN; |
184 |
} |
185 |
|
186 |
rv = ap_get_brigade(f->next, bb, mode, block, bytes); |
187 |
if (rv != APR_SUCCESS) { |
188 |
return rv; |
189 |
} |
190 |
|
191 |
for (bkt = APR_BRIGADE_FIRST(bb); |
192 |
bkt != APR_BRIGADE_SENTINEL(bb); |
193 |
bkt = APR_BUCKET_NEXT(bkt)) |
194 |
{ |
195 |
if (APR_BUCKET_IS_EOS(bkt)) { |
196 |
/* No more work for this filter. */ |
197 |
ap_remove_input_filter(f); |
198 |
|
199 |
/* Now really do the negotiation and access control checks. */ |
200 |
if (reneg_and_check(f->r, 0)) { |
201 |
|
202 |
/* Access control checks failed: send a 403. */ |
203 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, |
204 |
"renegotiation failed; sending 403 error"); |
205 |
bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); |
206 |
bkt = ap_bucket_error_create(HTTP_FORBIDDEN, NULL, |
207 |
f->r->pool, f->c->bucket_alloc); |
208 |
APR_BRIGADE_INSERT_TAIL(bb, bkt); |
209 |
bkt = apr_bucket_eos_create(f->c->bucket_alloc); |
210 |
APR_BRIGADE_INSERT_TAIL(bb, bkt); |
211 |
|
212 |
rv = ap_pass_brigade(f->r->output_filters, bb); |
213 |
if (rv) { |
214 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, |
215 |
"could not send 403 after renegotiation" |
216 |
" failure"); |
217 |
} |
218 |
|
219 |
/* Don't give anything back to the caller, just return |
220 |
* an error. */ |
221 |
apr_brigade_cleanup(bb); |
222 |
return APR_EACCES; |
223 |
} |
224 |
|
225 |
/* ignore the rest of the brigade */ |
226 |
break; |
227 |
} |
228 |
|
229 |
/* For any non-metadata buckets, read from the bucket to |
230 |
* ensure that it is morphed into a heap bucket if it's a |
231 |
* morphing bucket type. */ |
232 |
if (!APR_BUCKET_IS_METADATA(bkt)) { |
233 |
const char *buf; |
234 |
apr_size_t len; |
235 |
|
236 |
rv = apr_bucket_read(bkt, &buf, &len, block); |
237 |
if (rv) { |
238 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, |
239 |
"bucket read failed"); |
240 |
apr_brigade_cleanup(bb); |
241 |
return rv; |
242 |
} |
243 |
} |
244 |
} |
245 |
|
246 |
return APR_SUCCESS; |
247 |
} |
248 |
|
249 |
void ssl_reneg_filter_register(apr_pool_t *p) |
250 |
{ |
251 |
/* only requirement is that this input filter comes before the |
252 |
* ap_http_filter. */ |
253 |
reneg_filter_rec = |
254 |
ap_register_input_filter("SSL_RENEG", reneg_in_filter, NULL, |
255 |
AP_FTYPE_PROTOCOL - 1); |
256 |
} |
257 |
|
162 |
/* |
258 |
/* |
163 |
* Access Handler |
259 |
* Access Handler |
164 |
*/ |
260 |
*/ |
Lines 169-186
Link Here
|
169 |
SSLConnRec *sslconn = myConnConfig(r->connection); |
265 |
SSLConnRec *sslconn = myConnConfig(r->connection); |
170 |
SSL *ssl = sslconn ? sslconn->ssl : NULL; |
266 |
SSL *ssl = sslconn ? sslconn->ssl : NULL; |
171 |
SSL_CTX *ctx = NULL; |
267 |
SSL_CTX *ctx = NULL; |
172 |
apr_array_header_t *requires; |
|
|
173 |
ssl_require_t *ssl_requires; |
174 |
char *cp; |
268 |
char *cp; |
175 |
int ok, i; |
|
|
176 |
BOOL renegotiate = FALSE, renegotiate_quick = FALSE; |
269 |
BOOL renegotiate = FALSE, renegotiate_quick = FALSE; |
177 |
X509 *cert; |
|
|
178 |
X509 *peercert; |
270 |
X509 *peercert; |
179 |
X509_STORE *cert_store = NULL; |
|
|
180 |
X509_STORE_CTX cert_store_ctx; |
181 |
STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL; |
271 |
STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL; |
182 |
SSL_CIPHER *cipher = NULL; |
272 |
SSL_CIPHER *cipher = NULL; |
183 |
int depth, verify_old, verify, n; |
273 |
int verify_old, verify, n; |
184 |
|
274 |
|
185 |
if (ssl) { |
275 |
if (ssl) { |
186 |
ctx = SSL_get_SSL_CTX(ssl); |
276 |
ctx = SSL_get_SSL_CTX(ssl); |
Lines 489-723
Link Here
|
489 |
} |
579 |
} |
490 |
#endif /* HAVE_SSL_SET_CERT_STORE */ |
580 |
#endif /* HAVE_SSL_SET_CERT_STORE */ |
491 |
|
581 |
|
492 |
/* |
582 |
if (!renegotiate) { |
493 |
* SSL renegotiations in conjunction with HTTP |
583 |
/* Nothing more to do here. */ |
494 |
* requests using the POST method are not supported. |
584 |
return DECLINED; |
495 |
* |
|
|
496 |
* Background: |
497 |
* |
498 |
* 1. When the client sends a HTTP/HTTPS request, Apache's core code |
499 |
* reads only the request line ("METHOD /path HTTP/x.y") and the |
500 |
* attached MIME headers ("Foo: bar") up to the terminating line ("CR |
501 |
* LF"). An attached request body (for instance the data of a POST |
502 |
* method) is _NOT_ read. Instead it is read by mod_cgi's content |
503 |
* handler and directly passed to the CGI script. |
504 |
* |
505 |
* 2. mod_ssl supports per-directory re-configuration of SSL parameters. |
506 |
* This is implemented by performing an SSL renegotiation of the |
507 |
* re-configured parameters after the request is read, but before the |
508 |
* response is sent. In more detail: the renegotiation happens after the |
509 |
* request line and MIME headers were read, but _before_ the attached |
510 |
* request body is read. The reason simply is that in the HTTP protocol |
511 |
* usually there is no acknowledgment step between the headers and the |
512 |
* body (there is the 100-continue feature and the chunking facility |
513 |
* only), so Apache has no API hook for this step. |
514 |
* |
515 |
* 3. the problem now occurs when the client sends a POST request for |
516 |
* URL /foo via HTTPS the server and the server has SSL parameters |
517 |
* re-configured on a per-URL basis for /foo. Then mod_ssl has to |
518 |
* perform an SSL renegotiation after the request was read and before |
519 |
* the response is sent. But the problem is the pending POST body data |
520 |
* in the receive buffer of SSL (which Apache still has not read - it's |
521 |
* pending until mod_cgi sucks it in). When mod_ssl now tries to perform |
522 |
* the renegotiation the pending data leads to an I/O error. |
523 |
* |
524 |
* Solution Idea: |
525 |
* |
526 |
* There are only two solutions: Either to simply state that POST |
527 |
* requests to URLs with SSL re-configurations are not allowed, or to |
528 |
* renegotiate really after the _complete_ request (i.e. including |
529 |
* the POST body) was read. Obviously the latter would be preferred, |
530 |
* but it cannot be done easily inside Apache, because as already |
531 |
* mentioned, there is no API step between the body reading and the body |
532 |
* processing. And even when we mod_ssl would hook directly into the |
533 |
* loop of mod_cgi, we wouldn't solve the problem for other handlers, of |
534 |
* course. So the only general solution is to suck in the pending data |
535 |
* of the request body from the OpenSSL BIO into the Apache BUFF. Then |
536 |
* the renegotiation can be done and after this step Apache can proceed |
537 |
* processing the request as before. |
538 |
* |
539 |
* Solution Implementation: |
540 |
* |
541 |
* We cannot simply suck in the data via an SSL_read-based loop because of |
542 |
* HTTP chunking. Instead we _have_ to use the Apache API for this step which |
543 |
* is aware of HTTP chunking. So the trick is to suck in the pending request |
544 |
* data via the Apache API (which uses Apache's BUFF code and in the |
545 |
* background mod_ssl's I/O glue code) and re-inject it later into the Apache |
546 |
* BUFF code again. This way the data flows twice through the Apache BUFF, of |
547 |
* course. But this way the solution doesn't depend on any Apache specifics |
548 |
* and is fully transparent to Apache modules. |
549 |
* |
550 |
* !! BUT ALL THIS IS STILL NOT RE-IMPLEMENTED FOR APACHE 2.0 !! |
551 |
*/ |
552 |
if (renegotiate && !renegotiate_quick && (r->method_number == M_POST)) { |
553 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
554 |
"SSL Re-negotiation in conjunction " |
555 |
"with POST method not supported!\n" |
556 |
"hint: try SSLOptions +OptRenegotiate"); |
557 |
|
558 |
return HTTP_METHOD_NOT_ALLOWED; |
559 |
} |
585 |
} |
560 |
|
586 |
|
561 |
/* |
587 |
/* This function is called after reading the request-header. If |
562 |
* now do the renegotiation if anything was actually reconfigured |
588 |
* the HTTP request includes a message body, then the client may |
563 |
*/ |
589 |
* already have sent all the SSL records containing that body. |
564 |
if (renegotiate) { |
590 |
* It's not possible to do a renegotiation until all those SSL |
565 |
/* |
591 |
* records have been read and processed, so the renegotiation has |
566 |
* Now we force the SSL renegotation by sending the Hello Request |
592 |
* to be delayed until that point (when an EOS is returned by the |
567 |
* message to the client. Here we have to do a workaround: Actually |
593 |
* HTTP input filter). */ |
568 |
* OpenSSL returns immediately after sending the Hello Request (the |
594 |
|
569 |
* intent AFAIK is because the SSL/TLS protocol says it's not a must |
595 |
if (!renegotiate_quick && |
570 |
* that the client replies to a Hello Request). But because we insist |
596 |
(apr_table_get(r->headers_in, "Transfer-Encoding") || |
571 |
* on a reply (anything else is an error for us) we have to go to the |
597 |
((cp = (char *)apr_table_get(r->headers_in, "Content-Length")) != NULL |
572 |
* ACCEPT state manually. Using SSL_set_accept_state() doesn't work |
598 |
&& strcmp(cp, "0")))) { |
573 |
* here because it resets too much of the connection. So we set the |
|
|
574 |
* state explicitly and continue the handshake manually. |
575 |
*/ |
576 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
599 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
577 |
"Requesting connection re-negotiation"); |
600 |
"SSL re-negotiation needed for request with body: " |
578 |
|
601 |
"delaying until after body has been read"); |
579 |
if (renegotiate_quick) { |
602 |
ap_add_input_filter_handle(reneg_filter_rec, NULL, r, r->connection); |
580 |
STACK_OF(X509) *cert_stack; |
|
|
581 |
|
582 |
/* perform just a manual re-verification of the peer */ |
583 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
584 |
"Performing quick renegotiation: " |
585 |
"just re-verifying the peer"); |
586 |
|
587 |
cert_stack = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl); |
588 |
|
589 |
cert = SSL_get_peer_certificate(ssl); |
590 |
|
591 |
if (!cert_stack && cert) { |
592 |
/* client cert is in the session cache, but there is |
593 |
* no chain, since ssl3_get_client_certificate() |
594 |
* sk_X509_shift-ed the peer cert out of the chain. |
595 |
* we put it back here for the purpose of quick_renegotiation. |
596 |
*/ |
597 |
cert_stack = sk_new_null(); |
598 |
sk_X509_push(cert_stack, MODSSL_PCHAR_CAST cert); |
599 |
} |
600 |
|
601 |
if (!cert_stack || (sk_X509_num(cert_stack) == 0)) { |
602 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
603 |
"Cannot find peer certificate chain"); |
604 |
|
605 |
return HTTP_FORBIDDEN; |
606 |
} |
607 |
|
608 |
if (!(cert_store || |
609 |
(cert_store = SSL_CTX_get_cert_store(ctx)))) |
610 |
{ |
611 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
612 |
"Cannot find certificate storage"); |
613 |
|
614 |
return HTTP_FORBIDDEN; |
615 |
} |
616 |
|
617 |
if (!cert) { |
618 |
cert = sk_X509_value(cert_stack, 0); |
619 |
} |
620 |
|
621 |
X509_STORE_CTX_init(&cert_store_ctx, cert_store, cert, cert_stack); |
622 |
depth = SSL_get_verify_depth(ssl); |
623 |
|
603 |
|
624 |
if (depth >= 0) { |
604 |
return DECLINED; |
625 |
X509_STORE_CTX_set_depth(&cert_store_ctx, depth); |
605 |
} |
626 |
} |
|
|
627 |
|
628 |
X509_STORE_CTX_set_ex_data(&cert_store_ctx, |
629 |
SSL_get_ex_data_X509_STORE_CTX_idx(), |
630 |
(char *)ssl); |
631 |
|
606 |
|
632 |
if (!modssl_X509_verify_cert(&cert_store_ctx)) { |
607 |
/* Now actually perform the SSL renegotiation; return DECLINED on |
633 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
608 |
* success, to allow mod_auth and other modules to deny access. */ |
634 |
"Re-negotiation verification step failed"); |
609 |
return (reneg_and_check(r, renegotiate_quick) |
635 |
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); |
610 |
? HTTP_FORBIDDEN : DECLINED); |
636 |
} |
611 |
} |
637 |
|
612 |
|
638 |
SSL_set_verify_result(ssl, cert_store_ctx.error); |
613 |
/* Do an SSL renegotiation and perform access control checks; do a |
639 |
X509_STORE_CTX_cleanup(&cert_store_ctx); |
614 |
* "quick" renegotation (which doesn't actually perform an SSL |
|
|
615 |
* handshake), if 'quick' is non-zero. Returns non-zero if access |
616 |
* control checks failed. */ |
617 |
static int reneg_and_check(request_rec *r, int quick) |
618 |
{ |
619 |
SSLDirConfigRec *dc = myDirConfig(r); |
620 |
SSLConnRec *sslconn = myConnConfig(r->connection); |
621 |
SSL *ssl = sslconn ? sslconn->ssl : NULL; |
622 |
apr_array_header_t *requires; |
623 |
ssl_require_t *ssl_requires; |
624 |
X509_STORE *cert_store = NULL; |
625 |
X509_STORE_CTX cert_store_ctx; |
626 |
X509 *cert; |
627 |
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); |
628 |
int depth, i, ok; |
629 |
char *cp; |
640 |
|
630 |
|
641 |
if (cert_stack != SSL_get_peer_cert_chain(ssl)) { |
631 |
/* |
642 |
/* we created this ourselves, so free it */ |
632 |
* Now we force the SSL renegotation by sending the Hello Request |
643 |
sk_X509_pop_free(cert_stack, X509_free); |
633 |
* message to the client. Here we have to do a workaround: Actually |
644 |
} |
634 |
* OpenSSL returns immediately after sending the Hello Request (the |
|
|
635 |
* intent AFAIK is because the SSL/TLS protocol says it's not a must |
636 |
* that the client replies to a Hello Request). But because we insist |
637 |
* on a reply (anything else is an error for us) we have to go to the |
638 |
* ACCEPT state manually. Using SSL_set_accept_state() doesn't work |
639 |
* here because it resets too much of the connection. So we set the |
640 |
* state explicitly and continue the handshake manually. |
641 |
*/ |
642 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
643 |
"Requesting connection re-negotiation"); |
644 |
|
645 |
if (quick) { |
646 |
STACK_OF(X509) *cert_stack; |
647 |
|
648 |
/* perform just a manual re-verification of the peer */ |
649 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
650 |
"Performing quick renegotiation: " |
651 |
"just re-verifying the peer"); |
652 |
|
653 |
cert_stack = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl); |
654 |
|
655 |
cert = SSL_get_peer_certificate(ssl); |
656 |
|
657 |
if (!cert_stack && cert) { |
658 |
/* client cert is in the session cache, but there is |
659 |
* no chain, since ssl3_get_client_certificate() |
660 |
* sk_X509_shift-ed the peer cert out of the chain. |
661 |
* we put it back here for the purpose of quick_renegotiation. |
662 |
*/ |
663 |
cert_stack = sk_new_null(); |
664 |
sk_X509_push(cert_stack, MODSSL_PCHAR_CAST cert); |
645 |
} |
665 |
} |
646 |
else { |
666 |
|
647 |
request_rec *id = r->main ? r->main : r; |
667 |
if (!cert_stack || (sk_X509_num(cert_stack) == 0)) { |
648 |
|
668 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
649 |
/* do a full renegotiation */ |
669 |
"Cannot find peer certificate chain"); |
650 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
670 |
|
651 |
"Performing full renegotiation: " |
671 |
return 1; |
652 |
"complete handshake protocol"); |
|
|
653 |
|
654 |
SSL_set_session_id_context(ssl, |
655 |
(unsigned char *)&id, |
656 |
sizeof(id)); |
657 |
|
658 |
SSL_renegotiate(ssl); |
659 |
SSL_do_handshake(ssl); |
660 |
|
661 |
if (SSL_get_state(ssl) != SSL_ST_OK) { |
662 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
663 |
"Re-negotiation request failed"); |
664 |
|
665 |
r->connection->aborted = 1; |
666 |
return HTTP_FORBIDDEN; |
667 |
} |
668 |
|
669 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
670 |
"Awaiting re-negotiation handshake"); |
671 |
|
672 |
SSL_set_state(ssl, SSL_ST_ACCEPT); |
673 |
SSL_do_handshake(ssl); |
674 |
|
675 |
if (SSL_get_state(ssl) != SSL_ST_OK) { |
676 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
677 |
"Re-negotiation handshake failed: " |
678 |
"Not accepted by client!?"); |
679 |
|
680 |
r->connection->aborted = 1; |
681 |
return HTTP_FORBIDDEN; |
682 |
} |
683 |
} |
672 |
} |
684 |
|
673 |
|
685 |
/* |
674 |
if (!(cert_store || |
686 |
* Remember the peer certificate's DN |
675 |
(cert_store = SSL_CTX_get_cert_store(ctx)))) |
687 |
*/ |
676 |
{ |
688 |
if ((cert = SSL_get_peer_certificate(ssl))) { |
677 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
689 |
if (sslconn->client_cert) { |
678 |
"Cannot find certificate storage"); |
690 |
X509_free(sslconn->client_cert); |
679 |
|
691 |
} |
680 |
return 1; |
692 |
sslconn->client_cert = cert; |
|
|
693 |
sslconn->client_dn = NULL; |
694 |
} |
681 |
} |
695 |
|
682 |
|
696 |
/* |
683 |
if (!cert) { |
697 |
* Finally check for acceptable renegotiation results |
684 |
cert = sk_X509_value(cert_stack, 0); |
|
|
685 |
} |
686 |
|
687 |
X509_STORE_CTX_init(&cert_store_ctx, cert_store, cert, cert_stack); |
688 |
depth = SSL_get_verify_depth(ssl); |
689 |
|
690 |
if (depth >= 0) { |
691 |
X509_STORE_CTX_set_depth(&cert_store_ctx, depth); |
692 |
} |
693 |
|
694 |
X509_STORE_CTX_set_ex_data(&cert_store_ctx, |
695 |
SSL_get_ex_data_X509_STORE_CTX_idx(), |
696 |
(char *)ssl); |
697 |
|
698 |
if (!modssl_X509_verify_cert(&cert_store_ctx)) { |
699 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
700 |
"Re-negotiation verification step failed"); |
701 |
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); |
702 |
} |
703 |
|
704 |
SSL_set_verify_result(ssl, cert_store_ctx.error); |
705 |
X509_STORE_CTX_cleanup(&cert_store_ctx); |
706 |
|
707 |
if (cert_stack != SSL_get_peer_cert_chain(ssl)) { |
708 |
/* we created this ourselves, so free it */ |
709 |
sk_X509_pop_free(cert_stack, X509_free); |
710 |
} |
711 |
} |
712 |
else { |
713 |
request_rec *id = r->main ? r->main : r; |
714 |
|
715 |
/* do a full renegotiation */ |
716 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
717 |
"Performing full renegotiation: " |
718 |
"complete handshake protocol"); |
719 |
|
720 |
SSL_set_session_id_context(ssl, |
721 |
(unsigned char *)&id, |
722 |
sizeof(id)); |
723 |
|
724 |
SSL_renegotiate(ssl); |
725 |
SSL_do_handshake(ssl); |
726 |
|
727 |
if (SSL_get_state(ssl) != SSL_ST_OK) { |
728 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
729 |
"Re-negotiation request failed"); |
730 |
|
731 |
r->connection->aborted = 1; |
732 |
return 1; |
733 |
} |
734 |
|
735 |
ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, |
736 |
"Awaiting re-negotiation handshake"); |
737 |
|
738 |
/* XXX: Should replace SSL_set_state with SSL_renegotiate(ssl); |
739 |
* However, this causes failures in perl-framework currently, |
740 |
* perhaps pre-test if we have already negotiated? |
698 |
*/ |
741 |
*/ |
699 |
if (dc->nVerifyClient != SSL_CVERIFY_NONE) { |
742 |
SSL_set_state(ssl, SSL_ST_ACCEPT); |
700 |
BOOL do_verify = (dc->nVerifyClient == SSL_CVERIFY_REQUIRE); |
743 |
SSL_do_handshake(ssl); |
|
|
744 |
|
745 |
if (SSL_get_state(ssl) != SSL_ST_OK) { |
746 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
747 |
"Re-negotiation handshake failed: " |
748 |
"Not accepted by client!?"); |
749 |
|
750 |
r->connection->aborted = 1; |
751 |
return 1; |
752 |
} |
753 |
} |
754 |
|
755 |
/* |
756 |
* Remember the peer certificate's DN |
757 |
*/ |
758 |
if ((cert = SSL_get_peer_certificate(ssl))) { |
759 |
if (sslconn->client_cert) { |
760 |
X509_free(sslconn->client_cert); |
761 |
} |
762 |
sslconn->client_cert = cert; |
763 |
sslconn->client_dn = NULL; |
764 |
} |
765 |
|
766 |
/* |
767 |
* Finally check for acceptable renegotiation results |
768 |
*/ |
769 |
if (dc->nVerifyClient != SSL_CVERIFY_NONE) { |
770 |
BOOL do_verify = (dc->nVerifyClient == SSL_CVERIFY_REQUIRE); |
771 |
|
772 |
if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) { |
773 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
774 |
"Re-negotiation handshake failed: " |
775 |
"Client verification failed"); |
776 |
return 1; |
777 |
} |
778 |
|
779 |
if (do_verify) { |
780 |
X509 *peercert; |
701 |
|
781 |
|
702 |
if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) { |
782 |
if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) { |
703 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
783 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
704 |
"Re-negotiation handshake failed: " |
784 |
"Re-negotiation handshake failed: " |
705 |
"Client verification failed"); |
785 |
"Client certificate missing"); |
706 |
|
786 |
return 1; |
707 |
return HTTP_FORBIDDEN; |
|
|
708 |
} |
709 |
|
710 |
if (do_verify) { |
711 |
if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) { |
712 |
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, |
713 |
"Re-negotiation handshake failed: " |
714 |
"Client certificate missing"); |
715 |
|
716 |
return HTTP_FORBIDDEN; |
717 |
} |
718 |
|
719 |
X509_free(peercert); |
720 |
} |
787 |
} |
|
|
788 |
|
789 |
X509_free(peercert); |
721 |
} |
790 |
} |
722 |
} |
791 |
} |
723 |
|
792 |
|
Lines 744-750
Link Here
|
744 |
/* remember forbidden access for strict require option */ |
813 |
/* remember forbidden access for strict require option */ |
745 |
apr_table_setn(r->notes, "ssl-access-forbidden", "1"); |
814 |
apr_table_setn(r->notes, "ssl-access-forbidden", "1"); |
746 |
|
815 |
|
747 |
return HTTP_FORBIDDEN; |
816 |
return 1; |
748 |
} |
817 |
} |
749 |
|
818 |
|
750 |
if (ok != 1) { |
819 |
if (ok != 1) { |
Lines 765-782
Link Here
|
765 |
/* remember forbidden access for strict require option */ |
834 |
/* remember forbidden access for strict require option */ |
766 |
apr_table_setn(r->notes, "ssl-access-forbidden", "1"); |
835 |
apr_table_setn(r->notes, "ssl-access-forbidden", "1"); |
767 |
|
836 |
|
768 |
return HTTP_FORBIDDEN; |
837 |
return 1; |
769 |
} |
838 |
} |
770 |
} |
839 |
} |
771 |
|
840 |
|
772 |
/* |
841 |
return 0; |
773 |
* Else access is granted from our point of view (except vendor |
|
|
774 |
* handlers override). But we have to return DECLINED here instead |
775 |
* of OK, because mod_auth and other modules still might want to |
776 |
* deny access. |
777 |
*/ |
778 |
|
779 |
return DECLINED; |
780 |
} |
842 |
} |
781 |
|
843 |
|
782 |
/* |
844 |
/* |