Skip to content

Commit 8d3aa32

Browse files
committed
CDRIVER 3408 query OCSP responder
1 parent b9577cb commit 8d3aa32

File tree

2 files changed

+151
-63
lines changed

2 files changed

+151
-63
lines changed

.evergreen/run-ocsp-test.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ if [ -z "$TEST_COLUMN" -o -z "$CERT_TYPE" ]; then
4242
fi
4343
echo "TEST_COLUMN=$TEST_COLUMN"
4444
echo "CERT_TYPE=$CERT_TYPE"
45-
echo "USE_DELEGATE=$USE_DELEGATE"
4645
echo "CDRIVER_ROOT=$CDRIVER_ROOT"
4746
echo "CDRIVER_BUILD=$CDRIVER_BUILD"
4847
echo "MONGODB_PORT=$MONGODB_PORT"

src/libmongoc/src/mongoc/mongoc-openssl.c

Lines changed: 151 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -470,22 +470,100 @@ _get_issuer (X509 *cert, STACK_OF (X509) * chain)
470470
issuer = candidate;
471471
}
472472
}
473-
return issuer;
473+
RETURN (issuer);
474474
}
475475

476476
#define ERR_STR (ERR_error_string (ERR_get_error (), NULL))
477477

478+
OCSP_RESPONSE *
479+
_contact_ocsp_responder (OCSP_CERTID *id, X509 *peer)
480+
{
481+
STACK_OF (OPENSSL_STRING) *url_stack = NULL;
482+
OPENSSL_STRING url = NULL, host = NULL, path = NULL, port = NULL;
483+
OCSP_REQUEST *req = NULL;
484+
OCSP_RESPONSE *resp = NULL;
485+
BIO *bio = NULL;
486+
int i, ssl;
487+
488+
url_stack = X509_get1_ocsp (peer);
489+
for (i = 0; i < sk_OPENSSL_STRING_num (url_stack) && !resp; i++) {
490+
url = sk_OPENSSL_STRING_value (url_stack, i);
491+
MONGOC_DEBUG ("Contacting OCSP responder '%s'", url);
492+
493+
/* splits the given url into its host, port and path components */
494+
if (!OCSP_parse_url (url, &host, &port, &path, &ssl)) {
495+
MONGOC_DEBUG ("Could not parse URL");
496+
GOTO (retry);
497+
}
498+
499+
if (!(req = OCSP_REQUEST_new ())) {
500+
MONGOC_DEBUG ("Could not create new OCSP request");
501+
GOTO (retry);
502+
}
503+
504+
/* add the cert ID to the OCSP request object */
505+
if (!id || !OCSP_request_add0_id (req, OCSP_CERTID_dup (id))) {
506+
MONGOC_DEBUG ("Could not add cert ID to the OCSP request object");
507+
GOTO (retry);
508+
}
509+
510+
/* add nonce to OCSP request object */
511+
if (!OCSP_request_add1_nonce (req, 0 /* use random nonce */, -1)) {
512+
MONGOC_DEBUG ("Could not add nonce to OCSP request object");
513+
GOTO (retry);
514+
}
515+
516+
if (!(bio = BIO_new_connect (host))) {
517+
MONGOC_DEBUG ("Could not create new BIO object");
518+
GOTO (retry);
519+
}
520+
521+
BIO_set_conn_port (bio, port);
522+
if (BIO_do_connect (bio) <= 0) {
523+
MONGOC_DEBUG ("Could not connect to url '%s'", url);
524+
GOTO (retry);
525+
}
526+
527+
if (!(resp = OCSP_sendreq_bio (bio, path, req))) {
528+
MONGOC_DEBUG (
529+
"Could not perform an OCSP request for url '%s'. Error: %s",
530+
url,
531+
ERR_STR);
532+
}
533+
retry:
534+
if (bio)
535+
BIO_free_all (bio);
536+
if (host)
537+
OPENSSL_free (host);
538+
if (port)
539+
OPENSSL_free (port);
540+
if (path)
541+
OPENSSL_free (path);
542+
if (req)
543+
OCSP_REQUEST_free (req);
544+
}
545+
546+
if (url_stack)
547+
X509_email_free (url_stack);
548+
RETURN (resp);
549+
}
550+
551+
#define SOFT_FAIL(...) \
552+
((stapled_response) ? MONGOC_ERROR (__VA_ARGS__) \
553+
: MONGOC_DEBUG (__VA_ARGS__))
554+
478555
int
479556
_mongoc_ocsp_tlsext_status_cb (SSL *ssl, void *arg)
480557
{
481-
const int ERROR = -1, FAILURE = 0, SUCCESS = 1;
558+
enum { ERROR = -1, REVOKED, SUCCESS } ret;
559+
bool stapled_response = true;
482560
OCSP_RESPONSE *resp = NULL;
483561
OCSP_BASICRESP *basic = NULL;
484562
X509_STORE *store = NULL;
485563
X509 *peer = NULL, *issuer = NULL;
486564
STACK_OF (X509) *cert_chain = NULL;
487565
const unsigned char *r = NULL;
488-
int cert_status, reason, len, status, ret;
566+
int cert_status, reason, len, status;
489567
OCSP_CERTID *id = NULL;
490568
mongoc_openssl_ocsp_opt_t *opts = (mongoc_openssl_ocsp_opt_t *) arg;
491569
ASN1_GENERALIZEDTIME *produced_at = NULL, *this_update = NULL,
@@ -496,60 +574,81 @@ _mongoc_ocsp_tlsext_status_cb (SSL *ssl, void *arg)
496574
}
497575

498576
if (!(peer = SSL_get_peer_certificate (ssl))) {
499-
MONGOC_ERROR ("No certificate was presented by the peer: %s", ERR_STR);
577+
MONGOC_ERROR ("No certificate was presented by the peer");
578+
ret = ERROR;
579+
GOTO (done);
580+
}
581+
582+
/* Get a STACK_OF(X509) certs forming the cert chain of the peer, including
583+
* the peer's cert */
584+
if (!(cert_chain = SSL_get0_verified_chain (ssl))) {
585+
MONGOC_ERROR ("No certificate was presented by the peer");
586+
ret = REVOKED;
587+
GOTO (done);
588+
}
589+
590+
if (!(issuer = _get_issuer (peer, cert_chain))) {
591+
MONGOC_ERROR ("Could not get issuer from peer cert");
500592
ret = ERROR;
501-
goto done;
593+
GOTO (done);
594+
}
595+
596+
if (!(id = OCSP_cert_to_id (NULL /* SHA1 */, peer, issuer))) {
597+
MONGOC_ERROR ("Could not obtain a valid OCSP_CERTID for peer");
598+
ret = ERROR;
599+
GOTO (done);
502600
}
503601

504602
/* Get the stapled OCSP response returned by the server */
505603
len = SSL_get_tlsext_status_ocsp_resp (ssl, &r);
506-
if (!r) {
604+
stapled_response = !!r;
605+
if (stapled_response) {
606+
/* obtain an OCSP_RESPONSE object from the OCSP response */
607+
if (!d2i_OCSP_RESPONSE (&resp, &r, len)) {
608+
MONGOC_ERROR ("Failed to parse OCSP response");
609+
ret = ERROR;
610+
GOTO (done);
611+
}
612+
} else {
613+
MONGOC_DEBUG ("Server does not contain a stapled response");
507614
bool must_staple = X509_get_ext_d2i (peer, NID_tlsfeature, 0, 0) != NULL;
508615
if (must_staple) {
509-
MONGOC_ERROR ("Server must contain a stapled response: %s", ERR_STR);
510-
ret = FAILURE;
511-
goto done;
616+
MONGOC_ERROR ("Server must contain a stapled response");
617+
ret = REVOKED;
618+
GOTO (done);
512619
}
513-
ret = SUCCESS; // TODO: contact OCSP responder
514-
goto done;
515-
}
516620

517-
/* obtain an OCSP_RESPONSE object from the OCSP response */
518-
if (!d2i_OCSP_RESPONSE (&resp, &r, len)) {
519-
MONGOC_ERROR ("Failed to parse OCSP response: %s", ERR_STR);
520-
ret = ERROR;
521-
goto done;
621+
if (!(resp = _contact_ocsp_responder (id, peer))) {
622+
MONGOC_DEBUG ("Soft-fail: No OCSP responder could be reached");
623+
ret = SUCCESS;
624+
GOTO (done);
625+
}
522626
}
523627

628+
MONGOC_DEBUG ("Validating OCSP response");
524629
/* Validate the OCSP response status of the OCSP_RESPONSE object */
525630
status = OCSP_response_status (resp);
526631
if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
527-
MONGOC_ERROR ("OCSP response error %d %s",
528-
status,
529-
OCSP_response_status_str (status));
632+
SOFT_FAIL ("OCSP response error %d %s",
633+
status,
634+
OCSP_response_status_str (status));
530635
ret = ERROR;
531-
goto done;
636+
GOTO (done);
532637
}
533638

639+
MONGOC_DEBUG ("OCSP response status successful");
640+
534641
/* Get the OCSP_BASICRESP structure contained in OCSP_RESPONSE object for the
535642
* peer cert */
536643
basic = OCSP_response_get1_basic (resp);
537644
if (!basic) {
538-
MONGOC_ERROR ("Could not find BasicOCSPResponse: %s", ERR_STR);
645+
SOFT_FAIL ("Could not find BasicOCSPResponse: %s", ERR_STR);
539646
ret = ERROR;
540-
goto done;
647+
GOTO (done);
541648
}
542649

543650
store = SSL_CTX_get_cert_store (SSL_get_SSL_CTX (ssl));
544651

545-
/* Get a STACK_OF(X509) certs forming the cert chain of the peer, including
546-
* the peer's cert */
547-
if (!(cert_chain = SSL_get0_verified_chain (ssl))) {
548-
MONGOC_ERROR ("No certificate was presented by the peer: %s", ERR_STR);
549-
ret = ERROR;
550-
goto done;
551-
}
552-
553652
/*
554653
* checks that the basic response message is correctly signed and that the
555654
* signer certificate can be validated.
@@ -560,22 +659,9 @@ _mongoc_ocsp_tlsext_status_cb (SSL *ssl, void *arg)
560659
* validation path via the untrusted cert chain.
561660
*/
562661
if (SUCCESS != OCSP_basic_verify (basic, cert_chain, store, 0)) {
563-
MONGOC_ERROR ("OCSP response failed verification: %s", ERR_STR);
564-
ret = ERROR;
565-
goto done;
566-
}
567-
568-
if (!(issuer = _get_issuer (peer, cert_chain))) {
569-
MONGOC_ERROR ("Could not get issuer from peer cert");
662+
SOFT_FAIL ("OCSP response failed verification: %s", ERR_STR);
570663
ret = ERROR;
571-
goto done;
572-
}
573-
574-
if (!(id = OCSP_cert_to_id (NULL /* SHA1 */, peer, issuer))) {
575-
MONGOC_ERROR ("Could not obtain a valid OCSP_CERTID for peer: %s",
576-
ERR_STR);
577-
ret = ERROR;
578-
goto done;
664+
GOTO (done);
579665
}
580666

581667
/* searches the basic response for an OCSP response for the given cert ID */
@@ -586,54 +672,57 @@ _mongoc_ocsp_tlsext_status_cb (SSL *ssl, void *arg)
586672
&produced_at,
587673
&this_update,
588674
&next_update)) {
589-
MONGOC_ERROR ("No OCSP response found for the peer certificate: %s",
590-
ERR_STR);
675+
SOFT_FAIL ("No OCSP response found for the peer certificate");
591676
ret = ERROR;
592-
goto done;
677+
GOTO (done);
593678
}
594679

595680
/* checks the validity of this_update and next_update values */
596681
if (!OCSP_check_validity (this_update, next_update, 0L, -1L)) {
597-
MONGOC_ERROR ("OCSP response has expired: %s", ERR_STR);
682+
SOFT_FAIL ("OCSP response has expired: %s", ERR_STR);
598683
ret = ERROR;
599-
goto done;
684+
GOTO (done);
600685
}
601686

602687
switch (cert_status) {
603688
case V_OCSP_CERTSTATUS_GOOD:
689+
MONGOC_DEBUG ("OCSP Certificate Status: Good");
604690
/* TODO: cache response */
605691
break;
606692

607693
case V_OCSP_CERTSTATUS_REVOKED:
608-
MONGOC_ERROR ("OCSP Certificate Status: Revoked. Reason %d", reason);
609-
ret = FAILURE;
610-
goto done;
694+
MONGOC_ERROR ("OCSP Certificate Status: Revoked. Reason: %s",
695+
OCSP_crl_reason_str (reason));
696+
ret = REVOKED;
697+
GOTO (done);
611698

612-
default: /* V_OCSP_CERTSTATUS_UNKNOWN */
699+
default:
700+
MONGOC_DEBUG ("OCSP Certificate Status: Unknown");
613701
break;
614702
}
615703

616704
/* Validate hostname matches cert */
617705
if (!opts->allow_invalid_hostname &&
618706
X509_check_host (peer, opts->host, 0, 0, NULL) != SUCCESS &&
619707
X509_check_ip_asc (peer, opts->host, 0) != SUCCESS) {
620-
ret = FAILURE;
621-
goto done;
708+
ret = REVOKED;
709+
GOTO (done);
622710
}
623711

624712
ret = SUCCESS;
625713
done:
714+
if (ret == ERROR && !stapled_response) {
715+
ret = SUCCESS;
716+
}
626717
if (basic)
627718
OCSP_BASICRESP_free (basic);
628719
if (resp)
629720
OCSP_RESPONSE_free (resp);
630721
if (id)
631-
OCSP_CERTID_free (id);
722+
OCSP_CERTID_free (id);
632723
if (peer)
633-
X509_free (peer);
634-
if (issuer)
635-
X509_free (issuer);
636-
return ret;
724+
X509_free (peer);
725+
RETURN (ret);
637726
}
638727
#endif
639728

0 commit comments

Comments
 (0)