Browse code

tls: add support for urlencoded cert PVs and select

- new PVs: $tls_peer_raw_cert, $tls_peer_urlencoded_cert, $tls_my_raw_cert, $tls_my_urlencoded_cert
- new selects: @tls.peer.raw_cert, @tls.peer.urlencoded_cert, @tls.my.raw_cert, @tls.my.urlencoded_cert

Armen Babikyan authored on 31/03/2020 01:19:53
Showing 1 changed files
... ...
@@ -41,6 +41,7 @@
41 41
 #include "../../core/ut.h"
42 42
 #include "../../core/cfg/cfg.h"
43 43
 #include "../../core/dprint.h"
44
+#include "../../core/strutils.h"
44 45
 #include "tls_server.h"
45 46
 #include "tls_select.h"
46 47
 #include "tls_mod.h"
... ...
@@ -58,6 +59,8 @@ enum {
58 59
 	CERT_SELFSIGNED,  /* self-signed certificate test */
59 60
 	CERT_NOTBEFORE,   /* Select validity end from certificate */
60 61
 	CERT_NOTAFTER,    /* Select validity start from certificate */
62
+	CERT_RAW,         /* Select raw PEM-encoded certificate */
63
+	CERT_URLENCODED,  /* Select urlencoded PEM-encoded certificate */
61 64
 	COMP_CN,          /* Common name */
62 65
 	COMP_O,           /* Organization name */
63 66
 	COMP_OU,          /* Organization unit */
... ...
@@ -85,21 +88,23 @@ enum {
85 88
 	PV_CERT_SELFSIGNED = 1<<7,   /* self-signed certificate test */
86 89
 	PV_CERT_NOTBEFORE  = 1<<8,   /* Select validity end from certificate */
87 90
 	PV_CERT_NOTAFTER   = 1<<9,   /* Select validity start from certificate */
88
-
89
-	PV_COMP_CN = 1<<10,          /* Common name */
90
-	PV_COMP_O  = 1<<11,          /* Organization name */
91
-	PV_COMP_OU = 1<<12,          /* Organization unit */
92
-	PV_COMP_C  = 1<<13,          /* Country name */
93
-	PV_COMP_ST = 1<<14,          /* State */
94
-	PV_COMP_L  = 1<<15,          /* Locality/town */
95
-
96
-	PV_COMP_HOST = 1<<16,        /* hostname from subject/alternative */
97
-	PV_COMP_URI  = 1<<17,        /* URI from subject/alternative */
98
-	PV_COMP_E    = 1<<18,        /* Email address */
99
-	PV_COMP_IP   = 1<<19,        /* IP from subject/alternative */
100
-	PV_COMP_UID  = 1<<20,        /* UserID*/
101
-
102
-	PV_TLSEXT_SNI = 1<<21,       /* Peer's server name (TLS extension) */
91
+	PV_CERT_RAW        = 1<<10,  /* Select raw PEM-encoded certificate */
92
+	PV_CERT_URLENCODED = 1<<11,  /* Select urlencoded PEM-encoded certificate */
93
+
94
+	PV_COMP_CN = 1<<12,          /* Common name */
95
+	PV_COMP_O  = 1<<13,          /* Organization name */
96
+	PV_COMP_OU = 1<<14,          /* Organization unit */
97
+	PV_COMP_C  = 1<<15,          /* Country name */
98
+	PV_COMP_ST = 1<<16,          /* State */
99
+	PV_COMP_L  = 1<<17,          /* Locality/town */
100
+
101
+	PV_COMP_HOST = 1<<18,        /* hostname from subject/alternative */
102
+	PV_COMP_URI  = 1<<19,        /* URI from subject/alternative */
103
+	PV_COMP_E    = 1<<20,        /* Email address */
104
+	PV_COMP_IP   = 1<<21,        /* IP from subject/alternative */
105
+	PV_COMP_UID  = 1<<22,        /* UserID*/
106
+
107
+	PV_TLSEXT_SNI = 1<<23,       /* Peer's server name (TLS extension) */
103 108
 };
104 109
 
105 110
 
... ...
@@ -682,6 +687,120 @@ static int pv_sn(sip_msg_t* msg, pv_param_t* param, pv_value_t* res)
682 687
 }
683 688
 
684 689
 
690
+static int get_ssl_cert(str* res, int local, int urlencoded, sip_msg_t* msg)
691
+{
692
+#define MAX_CERT_SIZE 16384
693
+	/* buf2 holds the urlencoded version of buf, which can be up to 3 times its size */
694
+	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;
703
+
704
+	mem = BIO_new(BIO_s_mem());
705
+	if (!mem) {
706
+		ERR("Error while creating memory BIO\n");
707
+		goto err;
708
+	}
709
+
710
+	/* Write a certificate to a BIO */
711
+	if (!PEM_write_bio_X509(mem, cert)) {
712
+		goto err;
713
+	}
714
+
715
+	len = BIO_pending(mem);
716
+	if (len > MAX_CERT_SIZE) {
717
+		ERR("certificate is too long\n");
718
+		goto err;
719
+	}
720
+
721
+	if (BIO_read(mem, buf, len) <= 0) {
722
+		ERR("problem reading data out of BIO");
723
+		goto err;
724
+	}
725
+
726
+	if (urlencoded)
727
+	{
728
+		temp_str.len = len;
729
+		temp_str.s = buf;
730
+		res->s = buf2;
731
+		res->len = MAX_CERT_SIZE*3+1;
732
+
733
+		if (urlencode(&temp_str, res) < 0) {
734
+			ERR("Problem with urlencode()\n");
735
+			goto err;
736
+		}
737
+	}
738
+	else
739
+	{
740
+		res->s = buf;
741
+		res->len = len;
742
+	}
743
+
744
+	BIO_free(mem);
745
+	if (!local) X509_free(cert);
746
+	tcpconn_put(c);
747
+	return 0;
748
+
749
+ err:
750
+	if (mem) BIO_free(mem);
751
+	if (!local) X509_free(cert);
752
+	tcpconn_put(c);
753
+	return -1;
754
+}
755
+
756
+
757
+static int sel_ssl_cert(str* res, select_t* s, sip_msg_t* msg)
758
+{
759
+	int local, urlencoded;
760
+
761
+	switch(s->params[s->n - 2].v.i) {
762
+	case CERT_PEER: local = 0; break;
763
+	case CERT_LOCAL: local = 1; break;
764
+	case CERT_RAW: urlencoded = 0; break;
765
+	case CERT_URLENCODED: urlencoded = 1; break;
766
+	default:
767
+		BUG("Bug in call to sel_ssl_cert\n");
768
+		return -1;
769
+	}
770
+
771
+	return get_ssl_cert(res, local, urlencoded, msg);
772
+}
773
+
774
+
775
+static int pv_ssl_cert(sip_msg_t* msg, pv_param_t* param, pv_value_t* res)
776
+{
777
+	int local, urlencoded;
778
+
779
+	if (param->pvn.u.isname.name.n & PV_CERT_PEER) {
780
+		local = 0;
781
+	} else if (param->pvn.u.isname.name.n & PV_CERT_LOCAL) {
782
+		local = 1;
783
+	} else {
784
+		BUG("bug in call to pv_ssl_cert\n");
785
+		return pv_get_null(msg, param, res);
786
+	}
787
+
788
+	if (param->pvn.u.isname.name.n & PV_CERT_RAW) {
789
+		urlencoded = 0;
790
+	} else if (param->pvn.u.isname.name.n & PV_CERT_URLENCODED) {
791
+		urlencoded = 1;
792
+	} else {
793
+		BUG("bug in call to pv_ssl_cert\n");
794
+		return pv_get_null(msg, param, res);
795
+	}
796
+
797
+	if (get_ssl_cert(&res->rs, local, urlencoded, msg) < 0) {
798
+		return pv_get_null(msg, param, res);
799
+	}
800
+	res->flags = PV_VAL_STR;
801
+	return 0;
802
+}
803
+
685 804
 
686 805
 static int get_comp(str* res, int local, int issuer, int nid, sip_msg_t* msg)
687 806
 {
... ...
@@ -1082,6 +1201,11 @@ select_row_t tls_sel[] = {
1082 1201
 
1083 1202
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("version"), sel_cert_version, 0},
1084 1203
 
1204
+	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("rawCert"), sel_ssl_cert, CERT_RAW},
1205
+	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("raw_cert"), sel_ssl_cert, CERT_RAW},
1206
+	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("URLEncodedCert"), sel_ssl_cert, CERT_URLENCODED},
1207
+	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("urlencoded_cert"), sel_ssl_cert, CERT_URLENCODED},
1208
+
1085 1209
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("sn"),            sel_sn, 0},
1086 1210
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("serialNumber"),  sel_sn, 0},
1087 1211
 	{ sel_cert, SEL_PARAM_STR, STR_STATIC_INIT("serial_number"), sel_sn, 0},
... ...
@@ -1162,6 +1286,19 @@ pv_export_t tls_pv[] = {
1162 1286
 	{{"tls_cipher_bits", sizeof("tls_cipher_bits")-1},
1163 1287
 		PVT_OTHER,  pv_bits, 0,
1164 1288
 		0, 0, 0, 0 },
1289
+	/* raw and urlencoded versions of peer and local certificates */
1290
+	{{"tls_peer_raw_cert", sizeof("tls_peer_raw_cert")-1},
1291
+		PVT_OTHER, pv_ssl_cert, 0,
1292
+		0, 0, pv_init_iname, PV_CERT_PEER | PV_CERT_RAW},
1293
+	{{"tls_my_raw_cert", sizeof("tls_my_raw_cert")-1},
1294
+		PVT_OTHER, pv_ssl_cert, 0,
1295
+		0, 0, pv_init_iname, PV_CERT_LOCAL | PV_CERT_RAW},
1296
+	{{"tls_peer_urlencoded_cert", sizeof("tls_peer_urlencoded_cert")-1},
1297
+		PVT_OTHER, pv_ssl_cert, 0,
1298
+		0, 0, pv_init_iname, PV_CERT_PEER | PV_CERT_URLENCODED},
1299
+	{{"tls_my_urlencoded_cert", sizeof("tls_my_urlencoded_cert")-1},
1300
+		PVT_OTHER, pv_ssl_cert, 0,
1301
+		0, 0, pv_init_iname, PV_CERT_LOCAL | PV_CERT_URLENCODED},
1165 1302
 	/* general certificate parameters for peer and local */
1166 1303
 	{{"tls_peer_version", sizeof("tls_peer_version")-1},
1167 1304
 		PVT_OTHER, pv_cert_version, 0,