client: Initial support for TLS in the client

Use GNUtls because it is GPL compatible and instead of mbedTLS seems
to have a working non-blocking I/O integration. GNUtls has various
issues that could not be resolved easily:

* Pick spdy as sub protocol
* gmt_time not randomized
* private key loaded to RAM (but not verified)

This is the beginning and not the end. Client support might need more
work with actual tls verification. Maybe more manual x509 cert
verification is needed and maybe client certs don't work at all. I try
to ignore renegotiation as I threw away the key.

Reload x509 creds and keys as they might have changed from one
connection to another.

Change-Id: I9128e14084da1fc2705f858393f98b8133996172
diff --git a/src/osmo_client_vty.c b/src/osmo_client_vty.c
index a8739b1..a409cf4 100644
--- a/src/osmo_client_vty.c
+++ b/src/osmo_client_vty.c
@@ -1,7 +1,7 @@
 /*
  * osmo-pcap-client code
  *
- * (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
  * (C) 2011 by On-Waves
  * All Rights Reserved
  *
@@ -62,6 +62,26 @@
 	if (pcap_client->gprs_filtering)
 		vty_out(vty, " pcap add-filter gprs%s", VTY_NEWLINE);
 
+	if (pcap_client->tls_on) {
+		vty_out(vty, " enable tls%s", VTY_NEWLINE);
+		vty_out(vty, " tls hostname %s%s", pcap_client->tls_hostname, VTY_NEWLINE);
+		vty_out(vty, " %stls verify-cert%s",
+				pcap_client->tls_verify ? "" : "no ", VTY_NEWLINE);
+		if (pcap_client->tls_capath)
+			vty_out(vty, " tls capath %s%s", pcap_client->tls_capath, VTY_NEWLINE);
+		if (pcap_client->tls_client_cert)
+			vty_out(vty, " tls client-cert %s%s",
+					pcap_client->tls_client_cert, VTY_NEWLINE);
+		if (pcap_client->tls_client_key)
+			vty_out(vty, " tls client-key %s%s",
+					pcap_client->tls_client_key, VTY_NEWLINE);
+		if (pcap_client->tls_priority)
+			vty_out(vty, " tls priority %s%s",
+					pcap_client->tls_priority, VTY_NEWLINE);
+		vty_out(vty, " tls log-level %d%s",
+			pcap_client->tls_log_level, VTY_NEWLINE);
+	}
+
 	if (pcap_client->srv_ip)
 		vty_out(vty, " server ip %s%s",
 			pcap_client->srv_ip, VTY_NEWLINE);
@@ -131,6 +151,162 @@
 	return CMD_SUCCESS;
 }
 
+
+#define TLS_STR "Transport Layer Security\n"
+
+DEFUN(cfg_enable_tls,
+      cfg_enable_tls_cmd,
+      "enable tls",
+      "Enable\n" "Transport Layer Security\n")
+{
+	if (!pcap_client->tls_on) {
+		if (pcap_client->wqueue.bfd.fd >= 0)
+			osmo_client_reconnect(pcap_client);
+	}
+
+	pcap_client->tls_on = true;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_disable_tls,
+      cfg_disable_tls_cmd,
+      "disable tls",
+      "Disable\n" "Transport Layer Security\n")
+{
+	if (pcap_client->tls_on)
+		osmo_client_reconnect(pcap_client);
+
+	pcap_client->tls_on = false;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_hostname,
+      cfg_tls_hostname_cmd,
+      "tls hostname NAME",
+      TLS_STR "hostname for certificate validation\n" "name\n")
+{
+	talloc_free(pcap_client->tls_hostname);
+	pcap_client->tls_hostname = talloc_strdup(pcap_client, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_tls_hostname,
+      cfg_no_tls_hostname_cmd,
+      "no tls hostname",
+      NO_STR TLS_STR "hostname for certificate validation\n")
+{
+	talloc_free(pcap_client->tls_hostname);
+	pcap_client->tls_hostname = NULL;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_verify,
+      cfg_tls_verify_cmd,
+      "tls verify-cert",
+      TLS_STR "Verify certificates\n")
+{
+	pcap_client->tls_verify = true;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_tls_verify,
+      cfg_no_tls_verify_cmd,
+      "no tls verify-cert",
+      NO_STR TLS_STR "Verify certificates\n")
+{
+	pcap_client->tls_verify = false;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_capath,
+      cfg_tls_capath_cmd,
+      "tls capath .PATH",
+      TLS_STR "Trusted root certificates\n" "Filename\n")
+{
+	talloc_free(pcap_client->tls_capath);
+	pcap_client->tls_capath = talloc_strdup(pcap_client, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_tls_capath,
+      cfg_no_tls_capath_cmd,
+      "no tls capath",
+      NO_STR TLS_STR "Trusted root certificates\n")
+{
+	talloc_free(pcap_client->tls_capath);
+	pcap_client->tls_capath = NULL;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_client_cert,
+      cfg_tls_client_cert_cmd,
+      "tls client-cert .PATH",
+      TLS_STR "Client certificate for authentication\n" "Filename\n")
+{
+	talloc_free(pcap_client->tls_client_cert);
+	pcap_client->tls_client_cert = talloc_strdup(pcap_client, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_tls_client_cert,
+      cfg_no_tls_client_cert_cmd,
+      "no tls client-cert",
+      NO_STR TLS_STR "Client certificate for authentication\n")
+{
+	talloc_free(pcap_client->tls_client_cert);
+	pcap_client->tls_client_cert = NULL;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_client_key,
+      cfg_tls_client_key_cmd,
+      "tls client-key .PATH",
+      TLS_STR "Client private key\n" "Filename\n")
+{
+	talloc_free(pcap_client->tls_client_key);
+	pcap_client->tls_client_key = talloc_strdup(pcap_client, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_tls_client_key,
+      cfg_no_tls_client_key_cmd,
+      "no tls client-key",
+      NO_STR TLS_STR "Client private key\n")
+{
+	talloc_free(pcap_client->tls_client_key);
+	pcap_client->tls_client_key = NULL;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_priority,
+      cfg_tls_priority_cmd,
+      "tls priority STR",
+      TLS_STR "Priority string for GNUtls\n" "Priority string\n")
+{
+	talloc_free(pcap_client->tls_priority);
+	pcap_client->tls_priority = talloc_strdup(pcap_client, argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_tls_priority,
+      cfg_no_tls_priority_cmd,
+      "no tls priority",
+      NO_STR TLS_STR "Priority string for GNUtls\n")
+{
+	talloc_free(pcap_client->tls_priority);
+	pcap_client->tls_priority = NULL;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_tls_log_level,
+      cfg_tls_log_level_cmd,
+      "tls log-level <0-255>",
+      TLS_STR "Log-level\n" "GNUtls debug level\n")
+{
+	pcap_client->tls_log_level = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_server_ip,
       cfg_server_ip_cmd,
       "server ip A.B.C.D",
@@ -164,6 +340,22 @@
 	install_element(CLIENT_NODE, &cfg_server_ip_cmd);
 	install_element(CLIENT_NODE, &cfg_server_port_cmd);
 
+	install_element(CLIENT_NODE, &cfg_enable_tls_cmd);
+	install_element(CLIENT_NODE, &cfg_disable_tls_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_hostname_cmd);
+	install_element(CLIENT_NODE, &cfg_no_tls_hostname_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_verify_cmd);
+	install_element(CLIENT_NODE, &cfg_no_tls_verify_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_capath_cmd);
+	install_element(CLIENT_NODE, &cfg_no_tls_capath_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_client_cert_cmd);
+	install_element(CLIENT_NODE, &cfg_no_tls_client_cert_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_client_key_cmd);
+	install_element(CLIENT_NODE, &cfg_no_tls_client_key_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_priority_cmd);
+	install_element(CLIENT_NODE, &cfg_no_tls_priority_cmd);
+	install_element(CLIENT_NODE, &cfg_tls_log_level_cmd);
+
 	install_element(CLIENT_NODE, &cfg_client_add_gprs_cmd);
 	install_element(CLIENT_NODE, &cfg_client_del_gprs_cmd);