#include "config.h"
#ifdef WITH_TLS
#include <logging_mosq.h>
#include <mosquitto_internal.h>
#include <net_mosq.h>
#include <openssl/safestack.h>
#include <openssl/tls1.h>
#include <openssl/ssl.h>
#include <openssl/ocsp.h>
int mosquitto__verify_ocsp_status_cb(SSL * ssl, void *arg)
{
struct mosquitto *mosq = (struct mosquitto *)arg;
int ocsp_status, result2, i;
unsigned char *p;
const unsigned char *cp;
OCSP_RESPONSE *rsp = NULL;
OCSP_BASICRESP *br = NULL;
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
long len = SSL_get_tlsext_status_ocsp_resp(mosq->ssl, &p);
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL_get_tlsext_status_ocsp_resp returned %ld bytes", len);
cp = (const unsigned char *)p;
if (!cp || len <= 0) {
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: no response");
goto end;
}
rsp = d2i_OCSP_RESPONSE(NULL, &cp, len);
if (rsp==NULL) {
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: invalid response");
goto end;
}
ocsp_status = OCSP_response_status(rsp);
if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: invalid status: %s (%d)",
OCSP_response_status_str(ocsp_status), ocsp_status);
goto end;
}
br = OCSP_response_get1_basic(rsp);
if (!br) {
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: invalid response");
goto end;
}
ch = SSL_get_peer_cert_chain(mosq->ssl);
if (sk_X509_num(ch) <= 0) {
log__printf(mosq, MOSQ_LOG_ERR, "OCSP: we did not receive certificates of the server (num: %d)", sk_X509_num(ch));
goto end;
}
st = SSL_CTX_get_cert_store(mosq->ssl_ctx);
if ((result2=OCSP_basic_verify(br, ch, st, 0)) <= 0) {
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: response verification failed (error: %d)", result2);
goto end;
}
for(i = 0; i < OCSP_resp_count(br); i++) {
int cert_status, crl_reason;
OCSP_SINGLERESP *single = NULL;
ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
single = OCSP_resp_get0(br, i);
if(!single)
continue;
cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, &thisupd, &nextupd);
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL certificate status: %s (%d)",
OCSP_cert_status_str(cert_status), cert_status);
switch(cert_status) {
case V_OCSP_CERTSTATUS_GOOD:
if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: OCSP response has expired");
goto end;
}
break;
case V_OCSP_CERTSTATUS_REVOKED:
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL certificate revocation reason: %s (%d)",
OCSP_crl_reason_str(crl_reason), crl_reason);
goto end;
case V_OCSP_CERTSTATUS_UNKNOWN:
goto end;
default:
log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL certificate revocation status unknown");
goto end;
}
}
if (br!=NULL) OCSP_BASICRESP_free(br);
if (rsp!=NULL) OCSP_RESPONSE_free(rsp);
return 1;
end:
if (br!=NULL) OCSP_BASICRESP_free(br);
if (rsp!=NULL) OCSP_RESPONSE_free(rsp);
return 0;
}
#endif