Skip to content

Commit

Permalink
tls/openssl: Add OCSP stapling
Browse files Browse the repository at this point in the history
  • Loading branch information
maximilianfridrich committed Feb 17, 2025
1 parent 6370f55 commit 2b25d30
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ if(USE_OPENSSL)
src/tls/openssl/tls_udp.c
src/tls/openssl/tls.c
src/tls/openssl/sni.c
src/tls/openssl/ocsp.c
src/hmac/openssl/hmac.c
)
elseif(APPLE)
Expand Down
8 changes: 8 additions & 0 deletions include/re_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ enum tls_resume_mode {
TLS_RESUMPTION_ALL = TLS_RESUMPTION_IDS | TLS_RESUMPTION_TICKETS,
};

enum tls_ocsp_stapling {
TLS_OCSP_STAPLE_DISABLED = 0,
TLS_OCSP_STAPLE_ENABLED,
TLS_OCSP_STAPLE_REQUIRED,
};

struct tls_conn_d {
int (*verifyh) (int ok, void *arg);
void *arg;
Expand Down Expand Up @@ -86,6 +92,8 @@ int tls_get_subject(struct tls *tls, struct mbuf *mb);
void tls_disable_verify_server(struct tls *tls);
void tls_enable_verify_client(struct tls *tls, bool enable);
int tls_set_resumption(struct tls *tls, const enum tls_resume_mode mode);
int tls_set_ocsp_stapling(struct tls *tls, const enum tls_ocsp_stapling mode);
enum tls_ocsp_stapling tls_get_ocsp_stapling(const struct tls *tls);

int tls_set_min_proto_version(struct tls *tls, int version);
int tls_set_max_proto_version(struct tls *tls, int version);
Expand Down
169 changes: 169 additions & 0 deletions src/tls/openssl/ocsp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* @file openssl/ocsp.c Online Certificate Status Protocol API
*
* Copyright (C) 2025 Commend.com - [email protected]
*/
#if defined(WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif
#include <openssl/ocsp.h>
#include <openssl/ssl.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_sa.h>
#include <re_srtp.h>
#include <re_tls.h>
#include "tls.h"

#define DEBUG_MODULE "tls/ocsp"
#define DEBUG_LEVEL 5
#include <re_dbg.h>


static OCSP_RESPONSE *get_ocsp_response(SSL *ssl, long *resp_len)
{
int rsp_status;
OCSP_RESPONSE *rsp;
const unsigned char *ocsp_resp;
*resp_len = SSL_get_tlsext_status_ocsp_resp(ssl, &ocsp_resp);

if (*resp_len <= 0 || !ocsp_resp)
return NULL;

rsp = d2i_OCSP_RESPONSE(NULL, &ocsp_resp, *resp_len);
if (!rsp)
return NULL;

rsp_status = OCSP_response_status(rsp);
if (rsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
OCSP_RESPONSE_free(rsp);
return NULL;
}

return rsp;
}


static int get_certificates(SSL *ssl, X509 **cert, X509 **issuer)
{
X509_NAME *iname;
STACK_OF(X509) *peer_chain;

#if OPENSSL_VERSION_MAJOR >= 3
*cert = SSL_get1_peer_certificate(ssl);
#else
*cert = SSL_get_peer_certificate(ssl);
#endif
if (!*cert)
return EINVAL;

peer_chain = SSL_get_peer_cert_chain(ssl);
if (!peer_chain) {
X509_free(*cert);
*cert = NULL;
return EINVAL;
}

iname = X509_get_issuer_name(*cert);
for (int i = 0; i < sk_X509_num(peer_chain); i++) {
X509 *c = sk_X509_value(peer_chain, i);
if (X509_NAME_cmp(X509_get_subject_name(c), iname) == 0) {
*issuer = X509_dup(c);
return 0;
}
}

X509_free(*cert);
*cert = NULL;
return EINVAL;
}


/* Verifies that the CERTSTATUS is GOOD and that the validity period is ok. */
static int verify_cert_status(OCSP_BASICRESP *br, X509 *cert, X509 *issuer)
{
int reason;
int cert_status;
int ret = EPROTO;
ASN1_GENERALIZEDTIME *revtime = NULL;
ASN1_GENERALIZEDTIME *thisupd = NULL;
ASN1_GENERALIZEDTIME *nextupd = NULL;

OCSP_CERTID *certid = OCSP_cert_to_id(NULL, cert, issuer);
if (!certid)
return EINVAL;

if (!OCSP_resp_find_status(br, certid, &cert_status, &reason, &revtime,
&thisupd, &nextupd))
goto cleanup;

if (cert_status != V_OCSP_CERTSTATUS_GOOD)
goto cleanup;

/* Check validity period with 5-minute allowance */
if (!OCSP_check_validity(thisupd, nextupd, 300, -1))
goto cleanup;

ret = 0;

cleanup:
OCSP_CERTID_free(certid);
return ret;
}


/* Returns 0 if OSCP status is okay. Non-zero otherwise. */
int verify_ocsp_status(SSL *ssl, enum tls_ocsp_stapling stapling_mode)
{
long resp_len;
int basic_verify;
X509_STORE *store;
STACK_OF(X509) *peer_chain;
int err = EPROTO;
X509 *cert = NULL;
X509 *issuer = NULL;
OCSP_RESPONSE *rsp = NULL;
OCSP_BASICRESP *br = NULL;
SSL_CTX *ctx = ssl ? SSL_get_SSL_CTX(ssl) : NULL;

if (!stapling_mode)
return 0;

if (!ssl || !ctx)
return EINVAL;

rsp = get_ocsp_response(ssl, &resp_len);
if (!rsp)
return stapling_mode == TLS_OCSP_STAPLE_REQUIRED ? EPROTO : 0;

br = OCSP_response_get1_basic(rsp);
if (!br)
goto cleanup;

if (get_certificates(ssl, &cert, &issuer) != 0)
goto cleanup;

if (verify_cert_status(br, cert, issuer) != 0)
goto cleanup;

store = SSL_CTX_get_cert_store(ctx);
peer_chain = SSL_get_peer_cert_chain(ssl);
if (!peer_chain || !store)
goto cleanup;

basic_verify = OCSP_basic_verify(br, peer_chain, store, 0);
if (!basic_verify)
goto cleanup;

err = 0;

cleanup:
X509_free(cert);
X509_free(issuer);
OCSP_BASICRESP_free(br);
OCSP_RESPONSE_free(rsp);

return err;
}
33 changes: 33 additions & 0 deletions src/tls/openssl/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct tls {
char *pass; /**< password for private key */
bool verify_server; /**< Enable SIP TLS server verification */
bool verify_client; /**< Enable SIP TLS client verification */
enum tls_ocsp_stapling ocsp_stapling; /**< OCSP stapling mode */
struct session_reuse reuse;
struct list certs; /**< Certificates for SNI selection */
};
Expand Down Expand Up @@ -2153,6 +2154,38 @@ int tls_set_resumption(struct tls *tls, const enum tls_resume_mode mode)
}


/**
* Set TLS OCSP stapling mode
*
* @param tls TLS Object
* @param mode TLS OCSP stapling mode
*
* @return 0 if success, otherwise errorcode
*/
int tls_set_ocsp_stapling(struct tls *tls, const enum tls_ocsp_stapling mode)
{
if (!tls)
return EINVAL;

tls->ocsp_stapling = mode;

return 0;
}


/**
* Get TLS OCSP stapling mode
*
* @param tls TLS Object
*
* @return TLS OCSP stapling mode
*/
enum tls_ocsp_stapling tls_get_ocsp_stapling(const struct tls *tls)
{
return tls ? tls->ocsp_stapling : TLS_OCSP_STAPLE_DISABLED;
}


/**
* Change used certificate+key of an existing SSL object
*
Expand Down
1 change: 1 addition & 0 deletions src/tls/openssl/tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ const struct list *tls_certs(const struct tls *tls);

struct tls_cert *tls_cert_for_sni(const struct tls *tls, const char *sni);
void tls_enable_sni(struct tls *tls);
int verify_ocsp_status(SSL *ssl, enum tls_ocsp_stapling stapling_mode);
19 changes: 19 additions & 0 deletions src/tls/openssl/tls_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ static bool recv_handler(int *err, struct mbuf *mb, bool *estab, void *arg)
tc->up = true;
}

r = verify_ocsp_status(tc->ssl, tls_get_ocsp_stapling(tc->tls));
if (r) {
*err = r;
return true;
}

mbuf_set_pos(mb, 0);

for (;;) {
Expand Down Expand Up @@ -365,7 +371,10 @@ int tls_conn_change_cert(struct tls_conn *tc, const char *file)
int tls_start_tcp(struct tls_conn **ptc, struct tls *tls, struct tcp_conn *tcp,
int layer)
{
enum tls_ocsp_stapling stapling_mode;
long ocsp_status_type;
struct tls_conn *tc;
long ok;
int err;

if (!ptc || !tls || !tcp)
Expand Down Expand Up @@ -420,6 +429,16 @@ int tls_start_tcp(struct tls_conn **ptc, struct tls *tls, struct tcp_conn *tcp,

SSL_set_bio(tc->ssl, tc->sbio_in, tc->sbio_out);

stapling_mode = tls_get_ocsp_stapling(tc->tls);
ocsp_status_type = stapling_mode ? TLSEXT_STATUSTYPE_ocsp : 0;
ok = SSL_set_tlsext_status_type(tc->ssl, ocsp_status_type);
if (!ok) {
DEBUG_WARNING("SSL: failed to set tlsext STATUSTYPE_ocsp\n");
ERR_clear_error();
err = EFAULT;
goto out;
}

err = 0;

out:
Expand Down
19 changes: 19 additions & 0 deletions src/tls/openssl/tls_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,12 @@ static void conn_recv(struct tls_conn *tc, struct mbuf *mb)
}
}

err = verify_ocsp_status(tc->ssl, tls_get_ocsp_stapling(tc->tls));
if (err) {
conn_close(tc, err);
return;
}

mbuf_set_pos(mb, 0);

for (;;) {
Expand Down Expand Up @@ -450,7 +456,10 @@ static int conn_alloc(struct tls_conn **ptc, struct tls *tls,
dtls_estab_h *estabh, dtls_recv_h *recvh,
dtls_close_h *closeh, void *arg)
{
enum tls_ocsp_stapling stapling_mode;
long ocsp_status_type;
struct tls_conn *tc;
long ok;
int err = 0;

if (sock->single_conn) {
Expand Down Expand Up @@ -511,6 +520,16 @@ static int conn_alloc(struct tls_conn **ptc, struct tls *tls,

SSL_set_read_ahead(tc->ssl, 1);

stapling_mode = tls_get_ocsp_stapling(tc->tls);
ocsp_status_type = stapling_mode ? TLSEXT_STATUSTYPE_ocsp : 0;
ok = SSL_set_tlsext_status_type(tc->ssl, ocsp_status_type);
if (!ok) {
DEBUG_WARNING("SSL: failed to set tlsext STATUSTYPE_ocsp\n");
ERR_clear_error();
err = EFAULT;
goto out;
}

out:
if (err)
mem_deref(tc);
Expand Down

0 comments on commit 2b25d30

Please sign in to comment.