static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
		      fr_tls_server_conf_t *conf)
{
	OCSP_CERTID	*certid;
	OCSP_REQUEST	*req;
	OCSP_RESPONSE	*resp = NULL;
	OCSP_BASICRESP	*bresp = NULL;
	char		*host = NULL;
	char		*port = NULL;
	char		*path = NULL;
	char		hostheader[1024];
	int		use_ssl = -1;
	long		nsec = MAX_VALIDITY_PERIOD, maxage = -1;
	BIO		*cbio, *bio_out;
	int		ocsp_ok = 0;
	int		status;
	ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
	int		reason;
#if OPENSSL_VERSION_NUMBER >= 0x1000003f
	OCSP_REQ_CTX	*ctx;
	int		rc;
	struct timeval	now;
	struct timeval	when;
#endif

	/*
	 * Create OCSP Request
	 */
	certid = OCSP_cert_to_id(NULL, client_cert, issuer_cert);
	req = OCSP_REQUEST_new();
	OCSP_request_add0_id(req, certid);
	if (conf->ocsp_use_nonce) OCSP_request_add1_nonce(req, NULL, 8);

	/*
	 * Send OCSP Request and get OCSP Response
	 */

	/* Get OCSP responder URL */
	if (conf->ocsp_override_url) {
		char *url;

		memcpy(&url, &conf->ocsp_url, sizeof(url));
		/* Reading the libssl src, they do a strdup on the URL, so it could of been const *sigh* */
		OCSP_parse_url(url, &host, &port, &path, &use_ssl);
	} else {
		ocsp_parse_cert_url(client_cert, &host, &port, &path, &use_ssl);
	}

	if (!host || !port || !path) {
		RWDEBUG("ocsp: Host / port / path missing.  Not doing OCSP");
		ocsp_ok = 2;
		goto ocsp_skip;
	}

	RDEBUG2("ocsp: Using responder URL \"http://%s:%s%s\"", host, port, path);

	/* Check host and port length are sane, then create Host: HTTP header */
	if ((strlen(host) + strlen(port) + 2) > sizeof(hostheader)) {
		RWDEBUG("ocsp: Host and port too long");
		goto ocsp_skip;
	}
	snprintf(hostheader, sizeof(hostheader), "%s:%s", host, port);

	/* Setup BIO socket to OCSP responder */
	cbio = BIO_new_connect(host);

	bio_out = NULL;
	if (rad_debug_lvl) {
		if (default_log.dst == L_DST_STDOUT) {
			bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
		} else if (default_log.dst == L_DST_STDERR) {
			bio_out = BIO_new_fp(stderr, BIO_NOCLOSE);
		}
	}

	BIO_set_conn_port(cbio, port);
#if OPENSSL_VERSION_NUMBER < 0x1000003f
	BIO_do_connect(cbio);

	/* Send OCSP request and wait for response */
	resp = OCSP_sendreq_bio(cbio, path, req);
	if (!resp) {
		REDEBUG("ocsp: Couldn't get OCSP response");
		ocsp_ok = 2;
		goto ocsp_end;
	}
#else
	if (conf->ocsp_timeout)
		BIO_set_nbio(cbio, 1);

	rc = BIO_do_connect(cbio);
	if ((rc <= 0) && ((!conf->ocsp_timeout) || !BIO_should_retry(cbio))) {
		REDEBUG("ocsp: Couldn't connect to OCSP responder");
		ocsp_ok = 2;
		goto ocsp_end;
	}

	ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
	if (!ctx) {
		REDEBUG("ocsp: Couldn't create OCSP request");
		ocsp_ok = 2;
		goto ocsp_end;
	}

	if (!OCSP_REQ_CTX_add1_header(ctx, "Host", hostheader)) {
		REDEBUG("ocsp: Couldn't set Host header");
		ocsp_ok = 2;
		goto ocsp_end;
	}

	if (!OCSP_REQ_CTX_set1_req(ctx, req)) {
		REDEBUG("ocsp: Couldn't add data to OCSP request");
		ocsp_ok = 2;
		goto ocsp_end;
	}

	gettimeofday(&when, NULL);
	when.tv_sec += conf->ocsp_timeout;

	do {
		rc = OCSP_sendreq_nbio(&resp, ctx);
		if (conf->ocsp_timeout) {
			gettimeofday(&now, NULL);
			if (!timercmp(&now, &when, <))
				break;
		}
	} while ((rc == -1) && BIO_should_retry(cbio));

	if (conf->ocsp_timeout && (rc == -1) && BIO_should_retry(cbio)) {
		REDEBUG("ocsp: Response timed out");
		ocsp_ok = 2;
		goto ocsp_end;
	}

	OCSP_REQ_CTX_free(ctx);

	if (rc == 0) {
		REDEBUG("ocsp: Couldn't get OCSP response");
		ocsp_ok = 2;
		goto ocsp_end;
	}
#endif

	/* Verify OCSP response status */
	status = OCSP_response_status(resp);
	if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
		REDEBUG("ocsp: Response status: %s", OCSP_response_status_str(status));
		goto ocsp_end;
	}
	bresp = OCSP_response_get1_basic(resp);
	if (conf->ocsp_use_nonce && OCSP_check_nonce(req, bresp)!=1) {
		REDEBUG("ocsp: Response has wrong nonce value");
		goto ocsp_end;
	}
	if (OCSP_basic_verify(bresp, NULL, store, 0)!=1){
		REDEBUG("ocsp: Couldn't verify OCSP basic response");
		goto ocsp_end;
	}

	/*	Verify OCSP cert status */
	if (!OCSP_resp_find_status(bresp, certid, &status, &reason, &rev, &thisupd, &nextupd)) {
		REDEBUG("ocsp: No Status found");
		goto ocsp_end;
	}

	if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
		if (bio_out) {
			BIO_puts(bio_out, "WARNING: Status times invalid.\n");
			ERR_print_errors(bio_out);
		}
		goto ocsp_end;
	}

	if (bio_out) {
		BIO_puts(bio_out, "\tThis Update: ");
		ASN1_GENERALIZEDTIME_print(bio_out, thisupd);
		BIO_puts(bio_out, "\n");
		if (nextupd) {
			BIO_puts(bio_out, "\tNext Update: ");
			ASN1_GENERALIZEDTIME_print(bio_out, nextupd);
			BIO_puts(bio_out, "\n");
		}
	}

	switch (status) {
	case V_OCSP_CERTSTATUS_GOOD:
		RDEBUG2("ocsp: Cert status: good");
		ocsp_ok = 1;
		break;

	default:
		/* REVOKED / UNKNOWN */
		REDEBUG("ocsp: Cert status: %s", OCSP_cert_status_str(status));
		if (reason != -1) REDEBUG("ocsp: Reason: %s", OCSP_crl_reason_str(reason));

		if (bio_out) {
			BIO_puts(bio_out, "\tRevocation Time: ");
			ASN1_GENERALIZEDTIME_print(bio_out, rev);
			BIO_puts(bio_out, "\n");
		}
		break;
	}

ocsp_end:
	/* Free OCSP Stuff */
	OCSP_REQUEST_free(req);
	OCSP_RESPONSE_free(resp);
	free(host);
	free(port);
	free(path);
	BIO_free_all(cbio);
	if (bio_out) BIO_free(bio_out);
	OCSP_BASICRESP_free(bresp);

 ocsp_skip:
	switch (ocsp_ok) {
	case 1:
		RDEBUG2("ocsp: Certificate is valid");
		break;

	case 2:
		if (conf->ocsp_softfail) {
			RWDEBUG("ocsp: Unable to check certificate, assuming it's valid");
			RWDEBUG("ocsp: This may be insecure");
			ocsp_ok = 1;
		} else {
			REDEBUG("ocsp: Unable to check certificate, failing");
			ocsp_ok = 0;
		}
		break;

	default:
		REDEBUG("ocsp: Certificate has been expired/revoked");
		break;
	}

	return ocsp_ok;
}