Created
July 15, 2019 15:22
-
-
Save alfredh/d353de9645b4e78c24ed90e765406413 to your computer and use it in GitHub Desktop.
libre SIP/TLS verify
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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