From bacf82195314709e8fe1b737f35d438911d61068 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 8 Feb 2013 17:46:16 +0100 Subject: [PATCH] cleaned up TLS code which was moved to tlslib --- src/main.c | 135 +++--------------------------------- src/main.h | 3 + src/ocserv-args.def | 1 + src/sample.config | 1 + src/tlslib.c | 163 +++++++++++++++++++++++++++++++++++++++++++- src/tlslib.h | 8 +++ src/vpn.h | 4 ++ src/worker.h | 7 -- 8 files changed, 189 insertions(+), 133 deletions(-) diff --git a/src/main.c b/src/main.c index d9efbe45..c2d714ef 100644 --- a/src/main.c +++ b/src/main.c @@ -48,11 +48,6 @@ static unsigned int terminate = 0; static unsigned int need_maintainance = 0; static unsigned int need_children_cleanup = 0; -static void tls_log_func(int level, const char *str) -{ - syslog(LOG_DEBUG, "TLS[<%d>]: %s", level, str); -} - static int _listen_ports(struct cfg_st* config, struct addrinfo *res, struct listen_list_st *list) { @@ -301,65 +296,6 @@ static void handle_alarm(int signo) } -static void tls_audit_log_func(gnutls_session_t session, const char *str) -{ -worker_st * ws; - - if (session == NULL) - syslog(LOG_AUTH, "Warning: %s", str); - else { - ws = gnutls_session_get_ptr(session); - - oclog(ws, LOG_ERR, "Warning: %s", str); - } -} - -static int verify_certificate_cb(gnutls_session_t session) -{ - unsigned int status; - int ret; - worker_st * ws; - - ws = gnutls_session_get_ptr(session); - if (ws == NULL) { - syslog(LOG_ERR, "%s:%d: Could not obtain worker state.", __func__, __LINE__); - return -1; - } - - /* This verification function uses the trusted CAs in the credentials - * structure. So you must have installed one or more CA certificates. - */ - ret = gnutls_certificate_verify_peers2(session, &status); - if (ret < 0) { - oclog(ws, LOG_ERR, "Error verifying client certificate"); - return GNUTLS_E_CERTIFICATE_ERROR; - } - - if (status != 0) { -#if GNUTLS_VERSION_NUMBER > 0x030106 - type = gnutls_certificate_type_get(session); - - ret = - gnutls_certificate_verification_status_print(status, type, - &out, 0); - if (ret < 0) - return GNUTLS_E_CERTIFICATE_ERROR; - - oclog(ws, LOG_INFO, "Client certificate verification failed: %s", out.data); - - gnutls_free(out.data); -#else - oclog(ws, LOG_INFO, "Client certificate verification failed."); -#endif - - return GNUTLS_E_CERTIFICATE_ERROR; - } else { - oclog(ws, LOG_INFO, "Client certificate verification succeeded"); - } - - /* notify gnutls to continue handshake normally */ - return 0; -} static void drop_privileges(main_server_st* s) { @@ -521,13 +457,11 @@ fail: int main(int argc, char** argv) { int fd, pid, e; - struct tls_st creds; struct listen_list_st llist; struct proc_list_st clist; struct listener_st *ltmp; struct proc_st *ctmp, *cpos; struct tun_st tun; - const char* perr; fd_set rd; int val, n = 0, ret; struct timeval tv; @@ -579,59 +513,7 @@ int main(int argc, char** argv) } /* Initialize GnuTLS */ - gnutls_global_set_audit_log_function(tls_audit_log_func); - if (config.tls_debug) { - gnutls_global_set_log_function(tls_log_func); - gnutls_global_set_log_level(9); - } - - ret = gnutls_global_init(); - GNUTLS_FATAL_ERR(ret); - - ret = gnutls_certificate_allocate_credentials(&creds.xcred); - GNUTLS_FATAL_ERR(ret); - - ret = - gnutls_certificate_set_x509_key_file(creds.xcred, config.cert, - config.key, - GNUTLS_X509_FMT_PEM); - if (ret < 0) { - fprintf(stderr, "Error setting the certificate (%s) or key (%s) files.\n", - config.cert, config.key); - exit(1); - } - - if (config.cert_req != GNUTLS_CERT_IGNORE) { - if (config.ca != NULL) { - ret = - gnutls_certificate_set_x509_trust_file(creds.xcred, - config.ca, - GNUTLS_X509_FMT_PEM); - if (ret < 0) { - fprintf(stderr, "Error setting the CA (%s) file.\n", - config.ca); - exit(1); - } - - printf("Processed %d CA certificate(s).\n", ret); - } - - if (config.crl != NULL) { - ret = - gnutls_certificate_set_x509_crl_file(creds.xcred, - config.crl, - GNUTLS_X509_FMT_PEM); - GNUTLS_FATAL_ERR(ret); - } - - gnutls_certificate_set_verify_function(creds.xcred, - verify_certificate_cb); - } - - ret = gnutls_priority_init(&creds.cprio, config.priorities, &perr); - if (ret == GNUTLS_E_PARSING_ERROR) - fprintf(stderr, "Error in TLS priority string: %s\n", perr); - GNUTLS_FATAL_ERR(ret); + tls_global_init(&s); memset(&ws, 0, sizeof(ws)); @@ -717,22 +599,25 @@ int main(int argc, char** argv) pid = fork(); if (pid == 0) { /* child */ - - /* Drop privileges after this point */ - drop_privileges(&s); - /* close any open descriptors before * running the server */ close(cmd_fd[0]); clear_lists(&s); - + ws.config = &config; ws.cmd_fd = cmd_fd[1]; ws.tun_fd = -1; ws.udp_fd = -1; ws.conn_fd = fd; - ws.creds = &creds; + ws.creds = &s.creds; + + ret = tls_global_init_client(&ws); + if (ret < 0) + exit(1); + + /* Drop privileges after this point */ + drop_privileges(&s); vpn_server(&ws); exit(0); diff --git a/src/main.h b/src/main.h index 4be763f5..f6ca1539 100644 --- a/src/main.h +++ b/src/main.h @@ -56,6 +56,9 @@ typedef struct main_server_st { hash_db_st *tls_db; hash_db_st *cookie_db; + /* tls credentials */ + struct tls_st creds; + struct listen_list_st* llist; struct proc_list_st* clist; } main_server_st; diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 258267d0..f4b17a47 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -79,6 +79,7 @@ tcp-port = 3333 udp-port = 3333 # The key and the certificates of the server +# The key may be a file, or any URL supported by GnuTLS (i.e., tpmkey or pkcs11) server-cert = /path/to/cert.pem server-key = /path/to/key.pem diff --git a/src/sample.config b/src/sample.config index 98a32cb1..8bec37ef 100644 --- a/src/sample.config +++ b/src/sample.config @@ -26,6 +26,7 @@ udp-port = 3333 keepalive = 90 # The key and the certificates of the server +# The key may be a file, or any URL supported by GnuTLS (i.e., tpmkey or pkcs11) server-cert = ./test-cert.pem server-key = ./test-key.pem diff --git a/src/tlslib.c b/src/tlslib.c index 45230fc9..a79ef5e3 100644 --- a/src/tlslib.c +++ b/src/tlslib.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -29,10 +30,11 @@ #include #include #include - #include #include #include +#include +#include ssize_t tls_send(gnutls_session_t session, const void *data, @@ -159,3 +161,162 @@ struct htable_iter iter; return; } + +static void tls_log_func(int level, const char *str) +{ + syslog(LOG_DEBUG, "TLS[<%d>]: %s", level, str); +} + +static void tls_audit_log_func(gnutls_session_t session, const char *str) +{ +worker_st * ws; + + if (session == NULL) + syslog(LOG_AUTH, "Warning: %s", str); + else { + ws = gnutls_session_get_ptr(session); + + oclog(ws, LOG_ERR, "Warning: %s", str); + } +} + +static int verify_certificate_cb(gnutls_session_t session) +{ + unsigned int status; + int ret; + worker_st * ws; + + ws = gnutls_session_get_ptr(session); + if (ws == NULL) { + syslog(LOG_ERR, "%s:%d: Could not obtain worker state.", __func__, __LINE__); + return -1; + } + + /* This verification function uses the trusted CAs in the credentials + * structure. So you must have installed one or more CA certificates. + */ + ret = gnutls_certificate_verify_peers2(session, &status); + if (ret < 0) { + oclog(ws, LOG_ERR, "Error verifying client certificate"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + if (status != 0) { +#if GNUTLS_VERSION_NUMBER > 0x030106 + type = gnutls_certificate_type_get(session); + + ret = + gnutls_certificate_verification_status_print(status, type, + &out, 0); + if (ret < 0) + return GNUTLS_E_CERTIFICATE_ERROR; + + oclog(ws, LOG_INFO, "Client certificate verification failed: %s", out.data); + + gnutls_free(out.data); +#else + oclog(ws, LOG_INFO, "Client certificate verification failed."); +#endif + + return GNUTLS_E_CERTIFICATE_ERROR; + } else { + oclog(ws, LOG_INFO, "Client certificate verification succeeded"); + } + + /* notify gnutls to continue handshake normally */ + return 0; +} + +void tls_global_init(main_server_st* s) +{ +int ret; +const char* perr; + + gnutls_global_set_audit_log_function(tls_audit_log_func); + if (s->config->tls_debug) { + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(9); + } + + ret = gnutls_global_init(); + GNUTLS_FATAL_ERR(ret); + + ret = gnutls_certificate_allocate_credentials(&s->creds.xcred); + GNUTLS_FATAL_ERR(ret); + + if (s->config->key != NULL && strncmp(s->config->key, "pkcs11:", 7) != 0) { + ret = + gnutls_certificate_set_x509_key_file(s->creds.xcred, s->config->cert, + s->config->key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "Error setting the certificate (%s) or key (%s) files: %s\n", + s->config->cert, s->config->key, gnutls_strerror(ret)); + exit(1); + } + } + + if (s->config->cert_req != GNUTLS_CERT_IGNORE) { + if (s->config->ca != NULL) { + ret = + gnutls_certificate_set_x509_trust_file(s->creds.xcred, + s->config->ca, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "Error setting the CA (%s) file.\n", + s->config->ca); + exit(1); + } + + fprintf(stderr, "Processed %d CA certificate(s).\n", ret); + } + + if (s->config->crl != NULL) { + ret = + gnutls_certificate_set_x509_crl_file(s->creds.xcred, + s->config->crl, + GNUTLS_X509_FMT_PEM); + GNUTLS_FATAL_ERR(ret); + } + + gnutls_certificate_set_verify_function(s->creds.xcred, + verify_certificate_cb); + } + + ret = gnutls_priority_init(&s->creds.cprio, s->config->priorities, &perr); + if (ret == GNUTLS_E_PARSING_ERROR) + fprintf(stderr, "Error in TLS priority string: %s\n", perr); + GNUTLS_FATAL_ERR(ret); + + + return; +} + +int tls_global_init_client(worker_st* ws) +{ +int ret; + + /* when we have PKCS #11 keys we cannot open them and then fork(), we need + * to open them at the process they are going to be used. */ + if (ws->config->key != NULL && strncmp(ws->config->key, "pkcs11:", 7) == 0) { + ret = gnutls_pkcs11_reinit(); + if (ret < 0) { + oclog(ws, LOG_ERR, "Could not reinitialize PKCS #11 subsystem: %s\n", + gnutls_strerror(ret)); + return -1; + + } + + ret = + gnutls_certificate_set_x509_key_file(ws->creds->xcred, ws->config->cert, + ws->config->key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + oclog(ws, LOG_ERR, "Error setting the certificate (%s) or key (%s) files: %s\n", + ws->config->cert, ws->config->key, gnutls_strerror(ret)); + return -1; + } + } + + return 0; +} diff --git a/src/tlslib.h b/src/tlslib.h index f8add59e..539059af 100644 --- a/src/tlslib.h +++ b/src/tlslib.h @@ -14,6 +14,9 @@ ssize_t tls_recv(gnutls_session_t session, void *data, size_t data_size); ssize_t tls_send(gnutls_session_t session, const void *data, size_t data_size); +void tls_global_init(struct main_server_st* s); +int tls_global_init_client(struct worker_st* ws); + ssize_t tls_send_file(gnutls_session_t session, const char *file); #define GNUTLS_FATAL_ERR(x) \ @@ -30,6 +33,11 @@ void tls_close(gnutls_session_t session); void tls_fatal_close(gnutls_session_t session, gnutls_alert_description_t a); +struct tls_st { + gnutls_certificate_credentials_t xcred; + gnutls_priority_t cprio; +}; + typedef struct { /* does not allow resumption from different address diff --git a/src/vpn.h b/src/vpn.h index 51661a59..8afbd5d2 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -86,6 +86,10 @@ struct cfg_st { struct vpn_st network; }; +/* generic thing to stop complaints */ +struct worker_st; +struct main_server_st; + #include #define MAX_USERNAME_SIZE 64 diff --git a/src/worker.h b/src/worker.h index d92c8ab6..ccec4f71 100644 --- a/src/worker.h +++ b/src/worker.h @@ -11,13 +11,6 @@ #include #include - -struct tls_st { - gnutls_certificate_credentials_t xcred; - gnutls_priority_t cprio; -}; - - typedef enum { UP_DISABLED, UP_SETUP,