Skip to content

Instantly share code, notes, and snippets.

@alfredh
Created July 15, 2019 15:22
Show Gist options
  • Save alfredh/d353de9645b4e78c24ed90e765406413 to your computer and use it in GitHub Desktop.
Save alfredh/d353de9645b4e78c24ed90e765406413 to your computer and use it in GitHub Desktop.
libre SIP/TLS verify
diff --git a/include/re_tls.h b/include/re_tls.h
index 319d601c..d4f6d041 100644
--- a/include/re_tls.h
+++ b/include/re_tls.h
@@ -56,6 +56,7 @@ const char *tls_cipher_name(const struct tls_conn *tc);
int tls_set_ciphers(struct tls *tls, const char *cipherv[], size_t count);
int tls_set_servername(struct tls_conn *tc, const char *servername);
int tls_set_verify_server(struct tls_conn *tc, const char *host);
+bool tls_verify_peer_san(const struct tls_conn *tc, const char *host);
/* TCP */
diff --git a/src/sip/ctrans.c b/src/sip/ctrans.c
index 0ff32660..c4467b8f 100644
--- a/src/sip/ctrans.c
+++ b/src/sip/ctrans.c
@@ -205,7 +205,7 @@ static void retransmit_handler(void *arg)
tmr_start(&ct->tmre, timeout, retransmit_handler, ct);
err = sip_transp_send(&ct->qent, ct->sip, NULL, ct->tp, &ct->dst,
- ct->mb, transport_handler, ct);
+ ct->mb, transport_handler, ct, NULL);
if (err) {
terminate(ct, err);
mem_deref(ct);
@@ -310,7 +310,7 @@ static bool response_handler(const struct sip_msg *msg, void *arg)
int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip,
enum sip_transp tp, const struct sa *dst, char *met,
char *branch, struct mbuf *mb,
- sip_resp_h *resph, void *arg)
+ sip_resp_h *resph, void *arg, const char *host)
{
struct sip_ctrans *ct;
int err;
@@ -336,7 +336,7 @@ int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip,
ct->arg = arg;
err = sip_transp_send(&ct->qent, sip, NULL, tp, dst, mb,
- transport_handler, ct);
+ transport_handler, ct, host);
if (err)
goto out;
@@ -386,7 +386,7 @@ int sip_ctrans_cancel(struct sip_ctrans *ct)
goto out;
err = sip_ctrans_request(NULL, ct->sip, ct->tp, &ct->dst, cancel,
- ct->branch, mb, NULL, NULL);
+ ct->branch, mb, NULL, NULL, NULL);
if (err)
goto out;
diff --git a/src/sip/request.c b/src/sip/request.c
index aca2935e..f60d358e 100644
--- a/src/sip/request.c
+++ b/src/sip/request.c
@@ -194,7 +194,8 @@ static int request(struct sip_request *req, enum sip_transp tp,
err = sip_send(req->sip, NULL, tp, dst, mb);
else
err = sip_ctrans_request(&req->ct, req->sip, tp, dst, req->met,
- branch, mb, response_handler, req);
+ branch, mb, response_handler, req,
+ req->host);
if (err)
goto out;
diff --git a/src/sip/sip.c b/src/sip/sip.c
index 651628cd..a2617703 100644
--- a/src/sip/sip.c
+++ b/src/sip/sip.c
@@ -173,7 +173,7 @@ void sip_close(struct sip *sip, bool force)
int sip_send(struct sip *sip, void *sock, enum sip_transp tp,
const struct sa *dst, struct mbuf *mb)
{
- return sip_transp_send(NULL, sip, sock, tp, dst, mb, NULL, NULL);
+ return sip_transp_send(NULL, sip, sock, tp, dst, mb, NULL, NULL, NULL);
}
diff --git a/src/sip/sip.h b/src/sip/sip.h
index 912c69bb..32ec3f13 100644
--- a/src/sip/sip.h
+++ b/src/sip/sip.h
@@ -50,7 +50,7 @@ struct sip_ctrans;
int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip,
enum sip_transp tp, const struct sa *dst, char *met,
char *branch, struct mbuf *mb, sip_resp_h *resph,
- void *arg);
+ void *arg, const char *host);
int sip_ctrans_cancel(struct sip_ctrans *ct);
int sip_ctrans_init(struct sip *sip, uint32_t sz);
int sip_ctrans_debug(struct re_printf *pf, const struct sip *sip);
@@ -69,7 +69,8 @@ typedef void(sip_transp_h)(int err, void *arg);
int sip_transp_init(struct sip *sip, uint32_t sz);
int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock,
enum sip_transp tp, const struct sa *dst, struct mbuf *mb,
- sip_transp_h *transph, void *arg);
+ sip_transp_h *transph, void *arg,
+ const char *host);
bool sip_transp_supported(struct sip *sip, enum sip_transp tp, int af);
const char *sip_transp_srvid(enum sip_transp tp);
bool sip_transp_reliable(enum sip_transp tp);
diff --git a/src/sip/transp.c b/src/sip/transp.c
index aed33bb0..eb391a7c 100644
--- a/src/sip/transp.c
+++ b/src/sip/transp.c
@@ -57,6 +57,8 @@ struct sip_conn {
struct sip *sip;
uint32_t ka_interval;
bool established;
+ char *host;
+ bool client;
};
@@ -104,6 +106,7 @@ static void conn_destructor(void *arg)
mem_deref(conn->sc);
mem_deref(conn->tc);
mem_deref(conn->mb);
+ mem_deref(conn->host);
}
@@ -463,6 +466,29 @@ static void tcp_estab_handler(void *arg)
tcp_conn_local_get(conn->tc, &conn->laddr);
#endif
+#ifdef USE_TLS
+ if (conn->client && conn->sc) {
+
+ err = tls_peer_verify(conn->sc);
+
+ re_printf(".... tls server cert: (%m)\n", err);
+
+ if (err) {
+ conn_close(conn, err);
+ mem_deref(conn);
+ return;
+ }
+
+ if (!tls_verify_peer_san(conn->sc, conn->host)) {
+ re_printf("sip: could not verify server SAN (%s)\n",
+ conn->host);
+ conn_close(conn, EAUTH);
+ mem_deref(conn);
+ return;
+ }
+ }
+#endif
+
conn->established = true;
le = list_head(&conn->ql);
@@ -544,7 +570,7 @@ static void tcp_connect_handler(const struct sa *paddr, void *arg)
static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure,
const struct sa *dst, struct mbuf *mb,
- sip_transp_h *transph, void *arg)
+ sip_transp_h *transph, void *arg, const char *host)
{
struct sip_conn *conn, *new_conn = NULL;
struct sip_connqent *qent;
@@ -565,6 +591,7 @@ static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure,
hash_append(sip->ht_conn, sa_hash(dst, SA_ALL), &conn->he, conn);
conn->paddr = *dst;
conn->sip = sip;
+ conn->client = true;
err = tcp_connect(&conn->tc, dst, tcp_estab_handler, tcp_recv_handler,
tcp_close_handler, conn);
@@ -588,6 +615,12 @@ static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure,
err = tls_start_tcp(&conn->sc, transp->tls, conn->tc, 0);
if (err)
goto out;
+
+ err = str_dup(&conn->host, host);
+ if (err) {
+ re_printf("sip: missing host param for tls\n");
+ goto out;
+ }
}
#endif
@@ -716,15 +749,18 @@ void sip_transp_flush(struct sip *sip)
}
+/* TODO: find a better way to transfer host from ctrans to transp */
int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock,
enum sip_transp tp, const struct sa *dst, struct mbuf *mb,
- sip_transp_h *transph, void *arg)
+ sip_transp_h *transph, void *arg, const char *host)
{
const struct sip_transport *transp;
struct sip_conn *conn;
bool secure = false;
int err;
+ re_printf(".... send: host=%s\n", host);
+
if (!sip || !dst || !mb)
return EINVAL;
@@ -753,7 +789,7 @@ int sip_transp_send(struct sip_connqent **qentp, struct sip *sip, void *sock,
err = tcp_send(conn->tc, mb);
else
err = conn_send(qentp, sip, secure, dst, mb,
- transph, arg);
+ transph, arg, host);
break;
default:
diff --git a/src/tls/openssl/tls.c b/src/tls/openssl/tls.c
index 85e2fd41..79d42127 100644
--- a/src/tls/openssl/tls.c
+++ b/src/tls/openssl/tls.c
@@ -683,11 +683,19 @@ int tls_peer_common_name(const struct tls_conn *tc, char *cn, size_t size)
*/
int tls_peer_verify(const struct tls_conn *tc)
{
+ long result;
+
if (!tc)
return EINVAL;
- if (SSL_get_verify_result(tc->ssl) != X509_V_OK)
+ result = SSL_get_verify_result(tc->ssl);
+ if (result != X509_V_OK) {
+
+ re_printf("tls: verify failed, result = %ld (%s)\n",
+ result, X509_verify_cert_error_string(result));
+
return EAUTH;
+ }
return 0;
}
@@ -937,3 +945,80 @@ struct ssl_ctx_st *tls_openssl_context(const struct tls *tls)
{
return tls ? tls->ctx : NULL;
}
+
+
+/*
+ * RFC 5922
+ *
+ * Subject Alternative Names (SANs)
+ */
+bool tls_verify_peer_san(const struct tls_conn *tc, const char *host)
+{
+ STACK_OF(GENERAL_NAME) *san_names;
+ X509 *cert;
+ bool match = false;
+ int i;
+ int err;
+
+ re_printf("---- tls: verify SAN: '%s'\n", host);
+
+ if (!tc || !host)
+ return false;
+
+ cert = SSL_get_peer_certificate(tc->ssl);
+ if (!cert)
+ return false;
+
+ san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+ if (san_names) {
+ for (i=0; i<sk_GENERAL_NAME_num(san_names); i++) {
+
+ const GENERAL_NAME *name;
+ struct pl pl;
+ unsigned char *p = 0;
+ unsigned len;
+ bool lmatch;
+
+ name = sk_GENERAL_NAME_value(san_names, i);
+
+ switch (name->type) {
+
+ case GEN_DNS:
+ len = ASN1_STRING_to_UTF8(&p, name->d.ia5);
+
+ pl.p = (char *)p;
+ pl.l = len;
+
+ lmatch = (0 == pl_strcasecmp(&pl, host));
+ if (lmatch)
+ match = true;
+
+ re_printf("tls: %5s [%u] type DNS: '%r'\n",
+ lmatch ? "Match" : "", i, &pl);
+ break;
+
+ default:
+ re_printf("cert: unknown type %d\n",
+ name->type);
+ break;
+ }
+ }
+ }
+ else {
+ char cn[256];
+
+ err = tls_peer_common_name(tc, cn, sizeof(cn));
+ if (err)
+ goto out;
+
+ match = (0==str_casecmp(host, cn));
+ }
+
+ out:
+ if (san_names)
+ sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+ if (cert)
+ X509_free(cert);
+
+ return match;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment