diff options
-rw-r--r-- | include/osmo-pcap/osmo_pcap_server.h | 7 | ||||
-rw-r--r-- | include/osmo-pcap/osmo_tls.h | 5 | ||||
-rw-r--r-- | src/osmo_server_main.c | 2 | ||||
-rw-r--r-- | src/osmo_server_network.c | 8 | ||||
-rw-r--r-- | src/osmo_server_vty.c | 251 | ||||
-rw-r--r-- | src/osmo_tls.c | 123 |
6 files changed, 381 insertions, 15 deletions
diff --git a/include/osmo-pcap/osmo_pcap_server.h b/include/osmo-pcap/osmo_pcap_server.h index 89c3df2..c1d318e 100644 --- a/include/osmo-pcap/osmo_pcap_server.h +++ b/include/osmo-pcap/osmo_pcap_server.h @@ -118,11 +118,18 @@ struct osmo_pcap_server { void *zmq_publ; /* tls base */ + bool tls_on; + bool tls_allow_anon; + bool tls_allow_x509; unsigned tls_log_level; char *tls_priority; char *tls_capath; + char *tls_crlfile; char *tls_server_cert; char *tls_server_key; + char *tls_dh_pkcs3; + gnutls_dh_params_t dh_params; + bool dh_params_allocated; char *base_path; off_t max_size; diff --git a/include/osmo-pcap/osmo_tls.h b/include/osmo-pcap/osmo_tls.h index 54fea4d..0637739 100644 --- a/include/osmo-pcap/osmo_tls.h +++ b/include/osmo-pcap/osmo_tls.h @@ -67,9 +67,14 @@ void osmo_tls_init(void); bool osmo_tls_init_client_session(struct osmo_pcap_client *client); + bool osmo_tls_init_server_session(struct osmo_pcap_conn *conn, struct osmo_pcap_server *server); void osmo_tls_release(struct osmo_tls_session *); int osmo_tls_client_bfd_cb(struct osmo_fd *fd, unsigned int what); size_t osmo_tls_pending(struct osmo_tls_session *session); +void osmo_tls_server_init(struct osmo_pcap_server *server); + +void osmo_tls_dh_load(struct osmo_pcap_server *server); +void osmo_tls_dh_generate(struct osmo_pcap_server *server); diff --git a/src/osmo_server_main.c b/src/osmo_server_main.c index 27fb519..37a9632 100644 --- a/src/osmo_server_main.c +++ b/src/osmo_server_main.c @@ -247,6 +247,8 @@ int main(int argc, char **argv) exit(1); } + osmo_tls_server_init(pcap_server); + /* attempt to connect to the remote */ if (osmo_pcap_server_listen(pcap_server) != 0) { LOGP(DSERVER, LOGL_ERROR, diff --git a/src/osmo_server_network.c b/src/osmo_server_network.c index 1b7addc..a854223 100644 --- a/src/osmo_server_network.c +++ b/src/osmo_server_network.c @@ -491,7 +491,13 @@ static void new_connection(struct osmo_pcap_server *server, client->state = STATE_INITIAL; client->pend = sizeof(*client->data); - if (client->tls_use) { + if (client->tls_use && !server->tls_on) { + LOGP(DSERVER, LOGL_NOTICE, + "Require TLS but not enabled on conn=%s\n", + client->name); + close_connection(client); + return; + } else if (client->tls_use) { if (!osmo_tls_init_server_session(client, server)) { close_connection(client); return; diff --git a/src/osmo_server_vty.c b/src/osmo_server_vty.c index 14cdb89..b2919ae 100644 --- a/src/osmo_server_vty.c +++ b/src/osmo_server_vty.c @@ -41,6 +41,45 @@ static struct cmd_node server_node = { 1, }; +static void write_tls(struct vty *vty, struct osmo_pcap_server *pcap_server) +{ + if (!pcap_server->tls_on) + return; + + vty_out(vty, " enable tls%s", VTY_NEWLINE); + vty_out(vty, " tls log-level %d%s", + pcap_server->tls_log_level, VTY_NEWLINE); + + if (pcap_server->tls_allow_anon) + vty_out(vty, " tls allow-auth anonymous%s", VTY_NEWLINE); + + if (pcap_server->tls_allow_x509) + vty_out(vty, " tls allow-auth x509%s", VTY_NEWLINE); + + if (pcap_server->tls_priority) + vty_out(vty, " tls priority %s%s", + pcap_server->tls_priority, VTY_NEWLINE); + if (pcap_server->tls_capath) + vty_out(vty, " tls capath %s%s", pcap_server->tls_capath, VTY_NEWLINE); + + if (pcap_server->tls_crlfile) + vty_out(vty, " tls crlfile %s%s", pcap_server->tls_crlfile, VTY_NEWLINE); + + if (pcap_server->tls_server_cert) + vty_out(vty, " tls server-cert %s%s", + pcap_server->tls_server_cert, VTY_NEWLINE); + + if (pcap_server->tls_server_key) + vty_out(vty, " tls server-key %s%s", + pcap_server->tls_server_key, VTY_NEWLINE); + + if (pcap_server->tls_dh_pkcs3) + vty_out(vty, " tls dh pkcs3 %s%s", + pcap_server->tls_dh_pkcs3, VTY_NEWLINE); + else + vty_out(vty, " tls dh generate%s", VTY_NEWLINE); +} + static int config_write_server(struct vty *vty) { struct osmo_pcap_conn *conn; @@ -59,6 +98,8 @@ static int config_write_server(struct vty *vty) vty_out(vty, " zeromq-publisher %s %d%s", pcap_server->zmq_ip, pcap_server->zmq_port, VTY_NEWLINE); + write_tls(vty, pcap_server); + llist_for_each_entry(conn, &pcap_server->conn, entry) { vty_out(vty, " client %s %s%s%s%s", conn->name, conn->remote_host, @@ -272,6 +313,195 @@ DEFUN(cfg_no_server_zmq_ip_port, 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") +{ + pcap_server->tls_on = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_disable_tls, + cfg_disable_tls_cmd, + "disable tls", + "Disable\n" "Transport Layer Security\n") +{ + pcap_server->tls_on = false; + 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_server->tls_log_level = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_allow_anon, + cfg_tls_allow_anon_cmd, + "tls allow-auth anonymous", + TLS_STR "allow authentication\n" "for anonymous\n") +{ + pcap_server->tls_allow_anon = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_no_tls_allow_anon, + cfg_no_tls_allow_anon_cmd, + "no tls allow-auth anonymous", + NO_STR TLS_STR "allow authentication\n" "for anonymous\n") +{ + pcap_server->tls_allow_anon = false; + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_allow_x509, + cfg_tls_allow_x509_cmd, + "tls allow-auth x509", + TLS_STR "allow authentication\n" "for certificates\n") +{ + pcap_server->tls_allow_x509 = true; + return CMD_SUCCESS; +} + +DEFUN(cfg_no_tls_allow_x509, + cfg_no_tls_allow_x509_cmd, + "no tls allow-auth x509", + NO_STR TLS_STR "allow authentication\n" "for certificates\n") +{ + pcap_server->tls_allow_x509 = false; + 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_server->tls_priority); + pcap_server->tls_priority = talloc_strdup(pcap_server, 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_server->tls_priority); + pcap_server->tls_priority = NULL; + 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_server->tls_capath); + pcap_server->tls_capath = talloc_strdup(pcap_server, 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_server->tls_capath); + pcap_server->tls_capath = NULL; + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_crlfile, + cfg_tls_crlfile_cmd, + "tls crlfile .PATH", + TLS_STR "CRL file\n" "Filename\n") +{ + talloc_free(pcap_server->tls_crlfile); + pcap_server->tls_crlfile = talloc_strdup(pcap_server, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_no_tls_crlfile, + cfg_no_tls_crlfile_cmd, + "no tls crlfile", + NO_STR TLS_STR "CRL file\n") +{ + talloc_free(pcap_server->tls_crlfile); + pcap_server->tls_crlfile = NULL; + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_server_cert, + cfg_tls_server_cert_cmd, + "tls server-cert .PATH", + TLS_STR "Server certificate\n" "Filename\n") +{ + talloc_free(pcap_server->tls_server_cert); + pcap_server->tls_server_cert = talloc_strdup(pcap_server, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_no_tls_server_cert, + cfg_no_tls_server_cert_cmd, + "no tls server-cert", + NO_STR TLS_STR "Server certificate\n") +{ + talloc_free(pcap_server->tls_server_cert); + pcap_server->tls_server_cert = NULL; + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_server_key, + cfg_tls_server_key_cmd, + "tls server-key .PATH", + TLS_STR "Server private key\n" "Filename\n") +{ + talloc_free(pcap_server->tls_server_key); + pcap_server->tls_server_key = talloc_strdup(pcap_server, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_no_tls_server_key, + cfg_no_tls_server_key_cmd, + "no tls server-key", + NO_STR TLS_STR "Server private key\n") +{ + talloc_free(pcap_server->tls_server_key); + pcap_server->tls_server_key = NULL; + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_dh_pkcs3, + cfg_tls_dh_pkcs3_cmd, + "tls dh pkcs .FILE", + TLS_STR "Diffie-Hellman Key Exchange\n" "PKCS3\n" "Filename\n") +{ + talloc_free(pcap_server->tls_dh_pkcs3); + pcap_server->tls_dh_pkcs3 = talloc_strdup(pcap_server, argv[0]); + + osmo_tls_dh_load(pcap_server); + return CMD_SUCCESS; +} + +DEFUN(cfg_tls_dh_generate, + cfg_tls_dh_generate_cmd, + "tls dh generate", + TLS_STR "Diffie-Hellman Key Exchange\n" "Generate prime\n") +{ + talloc_free(pcap_server->tls_dh_pkcs3); + pcap_server->tls_dh_pkcs3 = NULL; + + osmo_tls_dh_generate(pcap_server); + return CMD_SUCCESS; +} + void vty_server_init(struct osmo_pcap_server *server) { install_element(CONFIG_NODE, &cfg_server_cmd); @@ -285,6 +515,27 @@ void vty_server_init(struct osmo_pcap_server *server) install_element(SERVER_NODE, &cfg_server_zmq_ip_port_cmd); install_element(SERVER_NODE, &cfg_no_server_zmq_ip_port_cmd); + /* tls for the server */ + install_element(SERVER_NODE, &cfg_enable_tls_cmd); + install_element(SERVER_NODE, &cfg_disable_tls_cmd); + install_element(SERVER_NODE, &cfg_tls_log_level_cmd); + install_element(SERVER_NODE, &cfg_tls_allow_anon_cmd); + install_element(SERVER_NODE, &cfg_no_tls_allow_anon_cmd); + install_element(SERVER_NODE, &cfg_tls_allow_x509_cmd); + install_element(SERVER_NODE, &cfg_no_tls_allow_x509_cmd); + install_element(SERVER_NODE, &cfg_tls_priority_cmd); + install_element(SERVER_NODE, &cfg_no_tls_priority_cmd); + install_element(SERVER_NODE, &cfg_tls_capath_cmd); + install_element(SERVER_NODE, &cfg_no_tls_capath_cmd); + install_element(SERVER_NODE, &cfg_tls_crlfile_cmd); + install_element(SERVER_NODE, &cfg_no_tls_crlfile_cmd); + install_element(SERVER_NODE, &cfg_tls_server_cert_cmd); + install_element(SERVER_NODE, &cfg_no_tls_server_cert_cmd); + install_element(SERVER_NODE, &cfg_tls_server_key_cmd); + install_element(SERVER_NODE, &cfg_no_tls_server_key_cmd); + install_element(SERVER_NODE, &cfg_tls_dh_generate_cmd); + install_element(SERVER_NODE, &cfg_tls_dh_pkcs3_cmd); + install_element(SERVER_NODE, &cfg_server_client_cmd); install_element(SERVER_NODE, &cfg_server_client_store_tls_cmd); install_element(SERVER_NODE, &cfg_server_no_client_cmd); diff --git a/src/osmo_tls.c b/src/osmo_tls.c index c42d242..aeecf6d 100644 --- a/src/osmo_tls.c +++ b/src/osmo_tls.c @@ -35,15 +35,81 @@ exit(1); \ } -static gnutls_dh_params_t dh_params; -static int generate_dh_params (void) +static int generate_dh_params(struct osmo_pcap_server *server) { + int rc; unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH); LOGP(DTLS, LOGL_NOTICE, "Going to create DH params for %d bits\n", bits); - gnutls_dh_params_init (&dh_params); - return gnutls_dh_params_generate2 (dh_params, bits); + + /* allocate it */ + rc = gnutls_dh_params_init (&server->dh_params); + if (rc != GNUTLS_E_SUCCESS) { + LOGP(DTLS, LOGL_ERROR, "Failed to allocate DH params rc=%d\n", rc); + server->dh_params_allocated = false; + return rc; + } + + /* generate and check */ + rc = gnutls_dh_params_generate2 (server->dh_params, bits); + if (rc == GNUTLS_E_SUCCESS) + server->dh_params_allocated = true; + else { + LOGP(DTLS, LOGL_ERROR, "Failed to generate DH params rc=%d\n", rc); + server->dh_params_allocated = false; + gnutls_dh_params_deinit(server->dh_params); + } + return rc; +} + +void osmo_tls_dh_load(struct osmo_pcap_server *server) +{ + gnutls_datum_t data; + int rc; + + /* free it before we start */ + if (server->dh_params_allocated) { + gnutls_dh_params_deinit(server->dh_params); + server->dh_params_allocated = false; + } + /* check if we have all data */ + if (!server->tls_dh_pkcs3) { + LOGP(DTLS, LOGL_ERROR, "Can not generate missing pkcs3=%p\n", + server->tls_dh_pkcs3); + return; + } + /* initialize it again */ + rc = gnutls_dh_params_init (&server->dh_params); + if (rc != GNUTLS_E_SUCCESS) { + LOGP(DTLS, LOGL_ERROR, "Failed to allocate DH params rc=%d\n", rc); + server->dh_params_allocated = false; + return; + } + /* load prime and generator */ + rc = gnutls_load_file(server->tls_dh_pkcs3, &data); + if (rc != GNUTLS_E_SUCCESS) { + LOGP(DTLS, LOGL_ERROR, "Failed to load DH params from=%s rc=%d\n", + server->tls_dh_pkcs3, rc); + gnutls_dh_params_deinit(server->dh_params); + return; + } + rc = gnutls_dh_params_import_pkcs3(server->dh_params, &data, GNUTLS_X509_FMT_PEM); + gnutls_free(data.data); + if (rc != GNUTLS_E_SUCCESS) { + LOGP(DTLS, LOGL_ERROR, "Failed to import DH params rc=%d\n", rc); + gnutls_dh_params_deinit(server->dh_params); + return; + } + /* done */ + server->dh_params_allocated = true; +} + +void osmo_tls_dh_generate(struct osmo_pcap_server *server) +{ + if (server->dh_params_allocated) + gnutls_dh_params_deinit(server->dh_params); + generate_dh_params(server); } static int cert_callback(gnutls_session_t tls_session, @@ -105,7 +171,15 @@ void osmo_tls_init(void) rc = gnutls_global_init(); CHECK_RC(rc, "init failed"); gnutls_global_set_log_function(tls_log_func); - rc = generate_dh_params(); +} + +void osmo_tls_server_init(struct osmo_pcap_server *server) +{ + int rc; + + if (server->dh_params_allocated) + return; + rc = generate_dh_params(server); CHECK_RC(rc, "dh params failed"); } @@ -312,10 +386,15 @@ bool osmo_tls_init_server_session(struct osmo_pcap_conn *conn, sess->cert_alloc = true; /* set the credentials now */ -#warning "Anon?" - gnutls_anon_set_server_dh_params (sess->anon_serv_cred, dh_params); - gnutls_credentials_set(sess->session, GNUTLS_CRD_ANON, sess->anon_serv_cred); - gnutls_credentials_set(sess->session, GNUTLS_CRD_CERTIFICATE, sess->cert_cred); + if (server->dh_params_allocated) { + gnutls_anon_set_server_dh_params(sess->anon_serv_cred, server->dh_params); + gnutls_certificate_set_dh_params(sess->cert_cred, server->dh_params); + } + + if (server->tls_allow_anon) + gnutls_credentials_set(sess->session, GNUTLS_CRD_ANON, sess->anon_serv_cred); + if (server->tls_allow_x509) + gnutls_credentials_set(sess->session, GNUTLS_CRD_CERTIFICATE, sess->cert_cred); if (server->tls_capath) { rc = gnutls_certificate_set_x509_trust_file( @@ -328,12 +407,28 @@ bool osmo_tls_init_server_session(struct osmo_pcap_conn *conn, } } -#if 0 - if (load_keys(client) != 0) { - osmo_tls_release(sess); - return false; + if (server->tls_crlfile) { + rc = gnutls_certificate_set_x509_crl_file( + sess->cert_cred, server->tls_crlfile, GNUTLS_X509_FMT_PEM); + if (rc != GNUTLS_E_SUCCESS) { + LOGP(DTLS, LOGL_ERROR, "Failed to load crlfile from path=%s rc=%d\n", + server->tls_crlfile, rc); + osmo_tls_release(sess); + return false; + } + } + + if (server->tls_server_cert && server->tls_server_key) { + rc = gnutls_certificate_set_x509_key_file( + sess->cert_cred, server->tls_server_cert, server->tls_server_key, + GNUTLS_X509_FMT_PEM); + if (rc != GNUTLS_E_SUCCESS) { + LOGP(DTLS, LOGL_ERROR, "Failed to load crt/key from path=%s/%s rc=%d\n", + server->tls_server_cert, server->tls_server_key, rc); + osmo_tls_release(sess); + return false; + } } -#endif #warning "TODO client certificates" |