Browse code

tls: add verify_client support (#2166)

* tls: add verify_client support

* tls: fix error in forward-port

* tls: docbook update

Armen Babikyan authored on 09/12/2019 20:02:53 • Daniel-Constantin Mierla committed on 09/12/2019 20:02:53
Showing 11 changed files
... ...
@@ -1043,6 +1043,7 @@ modparam("tls", "renegotiation", 1)
1043 1043
 			<listitem><para>tls_method - (str) - TLS methods</para></listitem>
1044 1044
 			<listitem><para>verify_certificate - (bool) - see modparam</para></listitem>
1045 1045
 			<listitem><para>require_certificate - (bool) - see modparam</para></listitem>
1046
+			<listitem><para>verify_client - (str) - see modparam</para></listitem>
1046 1047
 			<listitem><para>private_key - (str) - see modparam</para></listitem>
1047 1048
 			<listitem><para>certificate - (str) - see modparam</para></listitem>
1048 1049
 			<listitem><para>verify_depth - (int) - see modparam</para></listitem>
... ...
@@ -1339,4 +1340,65 @@ modparam("tls", "engine_algorithms", "ALL")
1339 1340
 	        The default is not to set any methods as default. This global param is not supported in the tls config file.
1340 1341
 	</para>
1341 1342
         </section>
1343
+
1344
+	<section id="tls.p.verify_client">
1345
+	<title><varname>verify_client</varname> (string)</title>
1346
+	<para>
1347
+		Provides an alternative to verify_certificate and require_certificate modparam and tls.cfg
1348
+		parameters, and creates an additional opportunistic connection establishment option for connections with
1349
+		with unverifiable certificates (optional_no_ca).
1350
+	</para>
1351
+	<para>
1352
+		This is useful for allowing connections from SIP phones with self-signed
1353
+		certificates, signed by unrecognized root CAs, expired certificates, etc.
1354
+	</para>
1355
+	<para>
1356
+		The following values have respective behaviors:
1357
+	</para>
1358
+	<itemizedlist>
1359
+		<listitem><para>off - no client certificate request performed.</para></listitem>
1360
+		<listitem><para>on - require a verified certificate from the client.</para></listitem>
1361
+		<listitem><para>optional - ask client for certificate. If one is provided, it must
1362
+				be verified. Allowing missing certificate.</para></listitem>
1363
+		<listitem><para>optional_no_ca - ask client for certificate. Opportunistically try to
1364
+				verify certificate. Allow connection regardless of whether there is
1365
+				no certificate or whether certificate is present (verified or not).
1366
+				Note that verification status can be retrieved via $tls_peer_verified.</para></listitem>
1367
+	</itemizedlist>
1368
+	<para>
1369
+		Default value is 'off' (no client certificate request performed).
1370
+	</para>
1371
+	<para>
1372
+		Recommendation: when using this parameter, do not use verify_certificate or
1373
+		require_certificate parameters. Conversion table is as follows:
1374
+	</para>
1375
+	<itemizedlist>
1376
+		<listitem><para>verify_certificate=0, require_certificate=0 => verify_client="off"</listitem></para>
1377
+		<listitem><para>verify_certificate=1, require_certificate=0 => verify_client="optional"</listitem></para>
1378
+		<listitem><para>verify_certificate=1, require_certificate=1 => verify_client="on"</listitem></para>
1379
+	</itemizedlist>
1380
+	<example>
1381
+		<title>Set <varname>verify_client</varname> modparam parameter</title>
1382
+		<programlisting>
1383
+...
1384
+modparam("tls", "verify_client", "on")
1385
+...
1386
+		</programlisting>
1387
+	</example>
1388
+	<example>
1389
+		<title>Set <varname>verify_client</varname> tls.cfg parameter</title>
1390
+		<programlisting>
1391
+...
1392
+[server:1.2.3.4:5061]
1393
+method = TLSv1
1394
+verify_client = on
1395
+...
1396
+
1397
+[server:5.6.7.8:5061]
1398
+method = TLSv1.2
1399
+verify_client = optional_no_ca
1400
+...
1401
+		</programlisting>
1402
+	</example>
1403
+	</section>
1342 1404
  </section>
... ...
@@ -41,6 +41,7 @@ struct cfg_group_tls default_tls_cfg = {
41 41
 	0, /* verify_certificate */
42 42
 	9, /* verify_depth */
43 43
 	0, /* require_certificate */
44
+	STR_STATIC_INIT("off"), /* verify_client */
44 45
 	STR_NULL, /* private_key (default value set in fix_tls_cfg) */
45 46
 	STR_NULL, /* ca_list (default value set in fix_tls_cfg) */
46 47
 	STR_NULL, /* crl (default value set in fix_tls_cfg) */
... ...
@@ -155,6 +156,8 @@ cfg_def_t	tls_cfg_def[] = {
155 156
 		" verification go in the search for a trusted CA" },
156 157
 	{"require_certificate", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
157 158
 		"if enabled a certificate will be required from clients" },
159
+	{"verify_client", CFG_VAR_STR | CFG_READONLY, 0, 0, 0, 0,
160
+		"set to off (default), on, optional, or optional_no_ca" },
158 161
 	{"private_key", CFG_VAR_STR | CFG_READONLY, 0, 0, 0, 0,
159 162
 		"name of the file containing the private key (pem format), if not"
160 163
 		" contained in the certificate file" },
... ...
@@ -46,6 +46,7 @@ struct cfg_group_tls {
46 46
 	int verify_cert;
47 47
 	int verify_depth;
48 48
 	int require_cert;
49
+	str verify_client;
49 50
 	str private_key;
50 51
 	str ca_list;
51 52
 	str crl;
... ...
@@ -154,6 +154,15 @@ static cfg_option_t ksr_tls_token_any[] = {
154 154
 };
155 155
 
156 156
 
157
+static cfg_option_t verify_client_params[] = {
158
+	{"off",            .val = TLS_VERIFY_CLIENT_OFF},
159
+	{"on",             .val = TLS_VERIFY_CLIENT_ON},
160
+	{"optional",       .val = TLS_VERIFY_CLIENT_OPTIONAL},
161
+	{"optional_no_ca", .val = TLS_VERIFY_CLIENT_OPTIONAL_NO_CA},
162
+	{0}
163
+};
164
+
165
+
157 166
 static cfg_option_t options[] = {
158 167
 	{"method",              .param = methods, .f = cfg_parse_enum_opt},
159 168
 	{"tls_method",          .param = methods, .f = cfg_parse_enum_opt},
... ...
@@ -173,6 +182,7 @@ static cfg_option_t options[] = {
173 182
 	{"server_name",         .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
174 183
 	{"server_name_mode",    .f = cfg_parse_int_opt},
175 184
 	{"server_id",           .f = cfg_parse_str_opt, .flags = CFG_STR_SHMMEM},
185
+	{"verify_client",       .param = verify_client_params, .f = cfg_parse_enum_opt},
176 186
 	{0}
177 187
 };
178 188
 
... ...
@@ -199,6 +209,9 @@ static void update_opt_variables(void)
199 209
 	options[15].param = &_ksr_tls_domain->server_name;
200 210
 	options[16].param = &_ksr_tls_domain->server_name_mode;
201 211
 	options[17].param = &_ksr_tls_domain->server_id;
212
+	for(i = 0; verify_client_params[i].name; i++) {
213
+		verify_client_params[i].param = &_ksr_tls_domain->verify_client;
214
+	}
202 215
 }
203 216
 
204 217
 
... ...
@@ -516,3 +529,21 @@ int tls_parse_method(str* method)
516 529
 
517 530
 	return opt->val;
518 531
 }
532
+
533
+/*
534
+ * Convert TLS verify_client string to integer
535
+ */
536
+int tls_parse_verify_client(str* verify_client)
537
+{
538
+	cfg_option_t* opt;
539
+
540
+	if (!verify_client) {
541
+		LM_BUG("Invalid parameter value\n");
542
+		return -1;
543
+	}
544
+
545
+	opt = cfg_lookup_token(verify_client_params, verify_client);
546
+	if (!opt) return -1;
547
+
548
+	return opt->val;
549
+}
... ...
@@ -44,5 +44,9 @@ tls_domains_cfg_t* tls_load_config(str* filename);
44 44
  */
45 45
 int tls_parse_method(str* method);
46 46
 
47
+/*
48
+ * Convert TLS verify_client string to integer
49
+ */
50
+int tls_parse_verify_client(str* verify_client);
47 51
 
48 52
 #endif /* _TLS_CONFIG_H */
... ...
@@ -49,6 +49,7 @@ extern EVP_PKEY * tls_engine_private_key(const char* key_id);
49 49
 #include "tls_init.h"
50 50
 #include "tls_domain.h"
51 51
 #include "tls_cfg.h"
52
+#include "tls_verify.h"
52 53
 
53 54
 /*
54 55
  * ECDHE is enabled only on OpenSSL 1.0.0e and later.
... ...
@@ -174,6 +175,7 @@ tls_domain_t* tls_new_domain(int type, struct ip_addr *ip, unsigned short port)
174 175
 	d->verify_cert = -1;
175 176
 	d->verify_depth = -1;
176 177
 	d->require_cert = -1;
178
+	d->verify_client = -1;
177 179
 	return d;
178 180
 }
179 181
 
... ...
@@ -353,6 +355,9 @@ static int ksr_tls_fill_missing(tls_domain_t* d, tls_domain_t* parent)
353 355
 	if (d->verify_depth == -1) d->verify_depth = parent->verify_depth;
354 356
 	LOG(L_INFO, "%s: verify_depth=%d\n", tls_domain_str(d), d->verify_depth);
355 357
 
358
+	if (d->verify_client == -1) d->verify_client = parent->verify_client;
359
+	LOG(L_INFO, "%s: verify_client=%d\n", tls_domain_str(d), d->verify_client);
360
+
356 361
 	return 0;
357 362
 }
358 363
 
... ...
@@ -686,12 +691,12 @@ static int set_verification(tls_domain_t* d)
686 691
 	int verify_mode, i;
687 692
 	int procs_no;
688 693
 
689
-	if (d->require_cert) {
694
+	if (d->require_cert || d->verify_client == TLS_VERIFY_CLIENT_ON) {
690 695
 		verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
691 696
 		LOG(L_INFO, "%s: %s MUST present valid certificate\n", 
692 697
 			tls_domain_str(d), d->type & TLS_DOMAIN_SRV ? "Client" : "Server");
693 698
 	} else {
694
-		if (d->verify_cert) {
699
+		if (d->verify_cert || d->verify_client >= TLS_VERIFY_CLIENT_OPTIONAL) {
695 700
 			verify_mode = SSL_VERIFY_PEER;
696 701
 			if (d->type & TLS_DOMAIN_SRV) {
697 702
 				LOG(L_INFO, "%s: IF client provides certificate then it"
... ...
@@ -711,12 +716,17 @@ static int set_verification(tls_domain_t* d)
711 716
 			}
712 717
 		}
713 718
 	}
714
-	
719
+
715 720
 	procs_no=get_max_procs();
716 721
 	for(i = 0; i < procs_no; i++) {
717
-		SSL_CTX_set_verify(d->ctx[i], verify_mode, 0);
722
+		if (d->verify_client >= TLS_VERIFY_CLIENT_OPTIONAL_NO_CA) {
723
+			/* Note that actual verification result is available in $tls_peer_verified */
724
+			SSL_CTX_set_verify(d->ctx[i], verify_mode, verify_callback_unconditional_success);
725
+		} else {
726
+			SSL_CTX_set_verify(d->ctx[i], verify_mode, 0);
727
+		}
718 728
 		SSL_CTX_set_verify_depth(d->ctx[i], d->verify_depth);
719
-		
729
+
720 730
 	}
721 731
 	return 0;
722 732
 }
... ...
@@ -91,6 +91,19 @@ enum tls_domain_type {
91 91
 #define KSR_TLS_SNM_STRICT 0 /**< Match server_name only */
92 92
 #define KSR_TLS_SNM_INCDOM 1 /**< Match server_name and subdomains */
93 93
 #define KSR_TLS_SNM_SUBDOM 2 /**< Match subdomains only */
94
+
95
+
96
+/**
97
+ * TLS "verify_client" options
98
+ */
99
+enum tls_verify_client_options {
100
+	TLS_VERIFY_CLIENT_OFF = 0,
101
+	TLS_VERIFY_CLIENT_ON = 1,
102
+	TLS_VERIFY_CLIENT_OPTIONAL = 2,
103
+	TLS_VERIFY_CLIENT_OPTIONAL_NO_CA = 3
104
+};
105
+
106
+
94 107
 /**
95 108
  * separate configuration per ip:port
96 109
  */
... ...
@@ -111,6 +124,7 @@ typedef struct tls_domain {
111 124
 	str server_name;
112 125
 	int server_name_mode;
113 126
 	str server_id;
127
+	int verify_client;
114 128
 	struct tls_domain* next;
115 129
 } tls_domain_t;
116 130
 
... ...
@@ -108,6 +108,7 @@ static tls_domain_t mod_params = {
108 108
 	{0, 0},           /* Server name (SNI) */
109 109
 	0,                /* Server name (SNI) mode */
110 110
 	{0, 0},           /* Server id */
111
+	TLS_VERIFY_CLIENT_OFF,             /* Verify client */
111 112
 	0                 /* next */
112 113
 };
113 114
 
... ...
@@ -132,6 +133,7 @@ tls_domain_t srv_defaults = {
132 133
 	{0, 0},           /* Server name (SNI) */
133 134
 	0,                /* Server name (SNI) mode */
134 135
 	{0, 0},           /* Server id */
136
+	TLS_VERIFY_CLIENT_OFF,             /* Verify client */
135 137
 	0                 /* next */
136 138
 };
137 139
 
... ...
@@ -173,6 +175,7 @@ tls_domain_t cli_defaults = {
173 175
 	{0, 0},           /* Server name (SNI) */
174 176
 	0,                /* Server name (SNI) mode */
175 177
 	{0, 0},           /* Server id */
178
+	TLS_VERIFY_CLIENT_OFF,             /* Verify client */
176 179
 	0                 /* next */
177 180
 };
178 181
 
... ...
@@ -206,6 +209,7 @@ static param_export_t params[] = {
206 209
 	{"verify_certificate",  PARAM_INT,    &default_tls_cfg.verify_cert  },
207 210
 	{"verify_depth",        PARAM_INT,    &default_tls_cfg.verify_depth },
208 211
 	{"require_certificate", PARAM_INT,    &default_tls_cfg.require_cert },
212
+	{"verify_client",       PARAM_STR,    &default_tls_cfg.verify_client},
209 213
 	{"private_key",         PARAM_STR,    &default_tls_cfg.private_key  },
210 214
 	{"ca_list",             PARAM_STR,    &default_tls_cfg.ca_list      },
211 215
 	{"certificate",         PARAM_STR,    &default_tls_cfg.certificate  },
... ...
@@ -296,6 +300,7 @@ static tls_domains_cfg_t* tls_use_modparams(void)
296 300
 static int mod_init(void)
297 301
 {
298 302
 	int method;
303
+	int verify_client;
299 304
 
300 305
 	if (tls_disable){
301 306
 		LM_WARN("tls support is disabled "
... ...
@@ -329,6 +334,13 @@ static int mod_init(void)
329 334
 	mod_params.cert_file = cfg_get(tls, tls_cfg, certificate);
330 335
 	mod_params.cipher_list = cfg_get(tls, tls_cfg, cipher_list);
331 336
 	mod_params.server_name = cfg_get(tls, tls_cfg, server_name);
337
+	/* Convert verify_client parameter to integer */
338
+	verify_client = tls_parse_verify_client(&cfg_get(tls, tls_cfg, verify_client));
339
+	if (verify_client < 0) {
340
+		LM_ERR("Invalid tls_method parameter value\n");
341
+		return -1;
342
+	}
343
+	mod_params.verify_client = verify_client;
332 344
 
333 345
 	tls_domains_cfg =
334 346
 			(tls_domains_cfg_t**)shm_malloc(sizeof(tls_domains_cfg_t*));
... ...
@@ -219,13 +219,14 @@ static void tls_options(rpc_t* rpc, void* c)
219 219
 {
220 220
 	void* handle;
221 221
 	rpc->add(c, "{", &handle);
222
-	rpc->struct_add(handle, "dSdddSSSSdSSdddddddddddddd",
222
+	rpc->struct_add(handle, "dSdddSSSSSdSSdddddddddddddd",
223 223
 		"force_run",	cfg_get(tls, tls_cfg, force_run),
224 224
 		"method",		&cfg_get(tls, tls_cfg, method),
225 225
 		"verify_certificate", cfg_get(tls, tls_cfg, verify_cert),
226 226
 
227 227
 		"verify_depth",		cfg_get(tls, tls_cfg, verify_depth),
228 228
 		"require_certificate",	cfg_get(tls, tls_cfg, require_cert),
229
+		"verify_client",	&cfg_get(tls, tls_cfg, verify_client),
229 230
 		"private_key",		&cfg_get(tls, tls_cfg, private_key),
230 231
 		"ca_list",			&cfg_get(tls, tls_cfg, ca_list),
231 232
 		"certificate",		&cfg_get(tls, tls_cfg, certificate),
... ...
@@ -127,3 +127,9 @@ int verify_callback(int pre_verify_ok, X509_STORE_CTX *ctx) {
127 127
 	LM_NOTICE("tls init - verify return: %d\n", pre_verify_ok);
128 128
 	return(pre_verify_ok);
129 129
 }
130
+
131
+
132
+int verify_callback_unconditional_success(int pre_verify_ok, X509_STORE_CTX *ctx) {
133
+	LM_NOTICE("Post-verification callback: unconditional success\n");
134
+	return 1;
135
+}
... ...
@@ -33,4 +33,9 @@ at each step during the chain of certificates (this function
33 33
 is not the certificate_verification one!). */
34 34
 int verify_callback(int pre_verify_ok, X509_STORE_CTX *ctx);
35 35
 
36
+/* Post-verification callback handler which unconditionally returns 1 (success)
37
+   Note that actual verification result can be retrieved through TLS PVs after-the-fact
38
+ */
39
+int verify_callback_unconditional_success(int pre_verify_ok, X509_STORE_CTX *ctx);
40
+
36 41
 #endif /* _TLS_VERIFY_H */