Browse code

tls: add sel for tls verified cert chain (requires OpenSSL 1.1+) (#2289)

* tls: add sel for tls verified cert chain (requires OpenSSL 1.1+)

* remove extra tcpconn_put() call

Co-authored-by: Armen Babikyan <armen@firespotter.com>

Armen Babikyan authored on 20/04/2020 07:51:26 • GitHub committed on 20/04/2020 07:51:26
Showing 1 changed files
... ...
@@ -687,19 +687,11 @@ static int pv_sn(sip_msg_t* msg, pv_param_t* param, pv_value_t* res)
687 687
 }
688 688
 
689 689
 
690
-static int get_ssl_cert(str* res, int local, int urlencoded, sip_msg_t* msg)
690
+static int cert_to_buf(X509 *cert, char **bufptr, size_t *len)
691 691
 {
692 692
 #define MAX_CERT_SIZE 16384
693
-	/* buf2 holds the urlencoded version of buf, which can be up to 3 times its size */
694 693
 	static char buf[MAX_CERT_SIZE];
695
-	static char buf2[MAX_CERT_SIZE*3+1];
696
-	X509* cert;
697
-	struct tcp_connection* c;
698
-	size_t   len;
699
-	BIO     *mem;
700
-	str     temp_str;
701
-
702
-	if (get_cert(&cert, &c, msg, local) < 0) return -1;
694
+	BIO     *mem = NULL;
703 695
 
704 696
 	mem = BIO_new(BIO_s_mem());
705 697
 	if (!mem) {
... ...
@@ -712,17 +704,45 @@ static int get_ssl_cert(str* res, int local, int urlencoded, sip_msg_t* msg)
712 704
 		goto err;
713 705
 	}
714 706
 
715
-	len = BIO_pending(mem);
716
-	if (len > MAX_CERT_SIZE) {
707
+	*len = BIO_pending(mem);
708
+	if (*len > MAX_CERT_SIZE) {
717 709
 		ERR("certificate is too long\n");
718 710
 		goto err;
719 711
 	}
720 712
 
721
-	if (BIO_read(mem, buf, len) <= 0) {
713
+	if (BIO_read(mem, buf, *len) <= 0) {
722 714
 		ERR("problem reading data out of BIO");
723 715
 		goto err;
724 716
 	}
725 717
 
718
+	*bufptr = buf;
719
+
720
+	BIO_free(mem);
721
+	return 0;
722
+err:
723
+
724
+	if (mem) BIO_free(mem);
725
+	return -1;
726
+}
727
+
728
+
729
+static int get_ssl_cert(str* res, int local, int urlencoded, sip_msg_t* msg)
730
+{
731
+	char *buf = NULL;
732
+	/* buf2 holds the urlencoded version of buf, which can be up to 3 times its size */
733
+	static char buf2[MAX_CERT_SIZE*3+1];
734
+	X509* cert;
735
+	struct tcp_connection* c;
736
+	size_t   len;
737
+	str     temp_str;
738
+
739
+	if (get_cert(&cert, &c, msg, local) < 0) return -1;
740
+
741
+	if (cert_to_buf(cert, &buf, &len) < 0) {
742
+		ERR("cert to buf failed\n");
743
+		goto err;
744
+	}
745
+
726 746
 	if (urlencoded)
727 747
 	{
728 748
 		temp_str.len = len;
... ...
@@ -741,13 +761,11 @@ static int get_ssl_cert(str* res, int local, int urlencoded, sip_msg_t* msg)
741 761
 		res->len = len;
742 762
 	}
743 763
 
744
-	BIO_free(mem);
745 764
 	if (!local) X509_free(cert);
746 765
 	tcpconn_put(c);
747 766
 	return 0;
748 767
 
749 768
  err:
750
-	if (mem) BIO_free(mem);
751 769
 	if (!local) X509_free(cert);
752 770
 	tcpconn_put(c);
753 771
 	return -1;
... ...
@@ -804,6 +822,74 @@ static int pv_ssl_cert(sip_msg_t* msg, pv_param_t* param, pv_value_t* res)
804 822
 }
805 823
 
806 824
 
825
+#if (OPENSSL_VERSION_NUMBER >= 0x10100001L)
826
+/* NB: SSL_get0_verified_chain() was introduced in OpenSSL 1.1.0 */
827
+static int get_verified_cert_chain(STACK_OF(X509)** chain, struct tcp_connection** c, struct sip_msg* msg)
828
+{
829
+	SSL* ssl;
830
+
831
+	*chain = 0;
832
+	*c = get_cur_connection(msg);
833
+	if (!(*c)) {
834
+		INFO("TLS connection not found\n");
835
+		return -1;
836
+	}
837
+	ssl = get_ssl(*c);
838
+	if (!ssl) goto err;
839
+	*chain = SSL_get0_verified_chain(ssl);
840
+	if (!*chain) {
841
+		ERR("Unable to retrieve peer TLS verified chain from SSL structure\n");
842
+		goto err;
843
+	}
844
+
845
+	return 0;
846
+err:
847
+	tcpconn_put(*c);
848
+	return -1;
849
+}
850
+
851
+
852
+static int sel_ssl_verified_cert_chain(str* res, select_t* s, sip_msg_t* msg)
853
+{
854
+	char *buf = NULL;
855
+	struct tcp_connection* c;
856
+	size_t   len;
857
+	STACK_OF(X509)* chain;
858
+	X509* cert;
859
+	int i;
860
+
861
+	if (get_verified_cert_chain(&chain, &c, msg) < 0) return -1;
862
+
863
+	if (s->params[s->n-1].type == SEL_PARAM_INT) {
864
+		i = s->params[s->n-1].v.i;
865
+	} else
866
+		return -1;
867
+
868
+	if (i < 0 || i >= sk_X509_num(chain))
869
+		return -1;
870
+
871
+	cert = sk_X509_value(chain, i);
872
+	if (!cert)
873
+		return -1;
874
+
875
+	if (cert_to_buf(cert, &buf, &len) < 0) {
876
+		ERR("cert to buf failed\n");
877
+		goto err;
878
+	}
879
+
880
+	res->s = buf;
881
+	res->len = len;
882
+
883
+	tcpconn_put(c);
884
+	return 0;
885
+
886
+err:
887
+	tcpconn_put(c);
888
+	return -1;
889
+}
890
+#endif /* (OPENSSL_VERSION_NUMBER >= 0x10100001L) */
891
+
892
+
807 893
 static int get_comp(str* res, int local, int issuer, int nid, sip_msg_t* msg)
808 894
 {
809 895
 	static char buf[1024];
... ...
@@ -1208,6 +1294,10 @@ select_row_t tls_sel[] = {
1208 1294
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("URLEncodedCert"), sel_ssl_cert, DIVERSION | CERT_URLENCODED},
1209 1295
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("urlencoded_cert"), sel_ssl_cert, DIVERSION | CERT_URLENCODED},
1210 1296
 
1297
+#if (OPENSSL_VERSION_NUMBER >= 0x10100001L)
1298
+	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("verified_cert_chain"), sel_ssl_verified_cert_chain, CONSUME_NEXT_INT},
1299
+#endif
1300
+
1211 1301
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("sn"),            sel_sn, 0},
1212 1302
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("serialNumber"),  sel_sn, 0},
1213 1303
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("serial_number"), sel_sn, 0},