diff options
34 files changed, 2598 insertions, 610 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 22196e64..1ffa5bf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12.2...3.30.0) +cmake_minimum_required(VERSION 2.8.12.2...4.0.3.0) cmake_policy(VERSION ${CMAKE_VERSION}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") diff --git a/include/ouroboros/crypt.h b/include/ouroboros/crypt.h index 28fe63b2..b510a3b2 100644 --- a/include/ouroboros/crypt.h +++ b/include/ouroboros/crypt.h @@ -26,31 +26,84 @@ #include <ouroboros/shm_du_buff.h> #include <ouroboros/utils.h> +#define IVSZ 16 #define SYMMKEYSZ 32 +#define MSGBUFSZ 2048 -struct crypt_info { - uint16_t flags; - void * ctx; - uint8_t key[SYMMKEYSZ]; -}; +struct auth_ctx; +struct crypt_ctx; -int crypt_dh_pkp_create(void ** pkp, - uint8_t * pk); +struct crypt_ctx * crypt_create_ctx(uint16_t flags, + const uint8_t * key); -void crypt_dh_pkp_destroy(void * pkp); +void crypt_destroy_ctx(struct crypt_ctx * ctx); -int crypt_dh_derive(void * pkp, - buffer_t pk, - uint8_t * s); +int crypt_dh_pkp_create(void ** pkp, + uint8_t * pk); -int crypt_encrypt(struct crypt_info * info, - struct shm_du_buff * sdb); +void crypt_dh_pkp_destroy(void * pkp); -int crypt_decrypt(struct crypt_info * info, - struct shm_du_buff * sdb); +int crypt_dh_derive(void * pkp, + buffer_t pk, + uint8_t * s); -int crypt_init(struct crypt_info * info); +int crypt_encrypt(struct crypt_ctx * ctx, + buffer_t in, + buffer_t * out); -void crypt_fini(struct crypt_info * info); +int crypt_decrypt(struct crypt_ctx * ctx, + buffer_t in, + buffer_t * out); + +int crypt_load_crt_file(const char * path, + void ** crt); + +int crypt_load_crt_str(const char * str, + void ** crt); + +int crypt_get_pubkey_crt(void * crt, + void ** pk); + +void crypt_free_crt(void * crt); + +int crypt_load_privkey_file(const char * path, + void ** key); + +int crypt_load_privkey_str(const char * str, + void ** key); + +int crypt_load_pubkey_str(const char * str, + void ** key); + +int crypt_cmp_key(const void * key1, + const void * key2); + +void crypt_free_key(void * key); + +int crypt_crt_str(void * crt, + char * buf); + +int crypt_check_crt_name(void * crt, + const char * name); + +struct auth_ctx * auth_create_ctx(void); + +void auth_destroy_ctx(struct auth_ctx * ctx); + +int auth_add_crt_to_store(struct auth_ctx * ctx, + void * crt); + +void auth_destroy_ctx(struct auth_ctx * ctx); + +int auth_verify_crt(struct auth_ctx * ctx, + void * crt); + +int auth_sign(void * pkp, + buffer_t msg, + buffer_t * sig); + +int auth_verify_sig(void * pk, + buffer_t msg, + buffer_t sig); #endif /* OUROBOROS_LIB_CRYPT_H */ diff --git a/include/ouroboros/sockets.h.in b/include/ouroboros/sockets.h.in index 095674a9..1a6974ac 100644 --- a/include/ouroboros/sockets.h.in +++ b/include/ouroboros/sockets.h.in @@ -27,16 +27,20 @@ #include <sys/types.h> -#define SOCK_PATH "/var/run/ouroboros/" +#ifndef OUROBOROS_TEST + #define SOCK_PATH "/var/run/ouroboros/" +#else + #define SOCK_PATH "/tmp/" +#endif #define SOCK_PATH_SUFFIX ".sock" #define IRM_SOCK_PATH SOCK_PATH "irm" SOCK_PATH_SUFFIX -#define IPCP_SOCK_PATH_PREFIX SOCK_PATH "ipcp" +#define IPCP_SOCK_PATH_PREFIX SOCK_PATH "ipcp." #define SOCK_BUF_SIZE @SOCK_BUF_SIZE@ -/* Returns the full socket path of an IPCP */ -char * ipcp_sock_path(pid_t pid); +char * sock_path(pid_t pid, + const char * path); int server_socket_open(char * file_name); diff --git a/include/ouroboros/test.h b/include/ouroboros/test.h index 096e145c..12214f15 100644 --- a/include/ouroboros/test.h +++ b/include/ouroboros/test.h @@ -23,11 +23,19 @@ #ifndef OUROBOROS_LIB_TEST_H #define OUROBOROS_LIB_TEST_H +#define OUROBOROS_TEST + #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> +#include <sys/types.h> + + +#define TEST_RC_SUCCESS 0 +#define TEST_RC_SKIP 1 +#define TEST_RC_FAIL -1 #define TEST_START() \ do { \ @@ -40,6 +48,12 @@ fflush(stdout); \ } while (0) +#define TEST_SKIPPED() \ + do { \ + printf("%s skipped.\n", __func__); \ + fflush(stdout); \ + } while (0) + #define TEST_FAIL() \ do { \ printf("%s failed.\n", __func__); \ @@ -57,7 +71,7 @@ static int __attribute__((unused)) test_assert_fail(int(* testfunc)(void)) pid = fork(); if (pid == -1) { printf("Failed to fork: %s.\n", strerror(errno)); - return -1; + return TEST_RC_FAIL; } if (pid == 0) @@ -66,17 +80,17 @@ static int __attribute__((unused)) test_assert_fail(int(* testfunc)(void)) waitpid(pid, &wstatus, 0); #ifdef CONFIG_OUROBOROS_DEBUG if (WIFSIGNALED(wstatus) && (wstatus == 134 || wstatus == 6)) - return 0; + return TEST_RC_SUCCESS; printf("Process did not abort, status: %d.\n", wstatus); #else if (WIFEXITED(wstatus) && wstatus == 0) - return 0; + return TEST_RC_SUCCESS; printf("Process did not exit, status: %d.\n", wstatus); #endif - return -1; + return TEST_RC_FAIL; } #endif /* OUROBOROS_LIB_TEST_H */ diff --git a/include/ouroboros/tpm.h b/include/ouroboros/tpm.h index 445f9306..7188dc91 100644 --- a/include/ouroboros/tpm.h +++ b/include/ouroboros/tpm.h @@ -38,8 +38,8 @@ int tpm_start(struct tpm * tpm); void tpm_stop(struct tpm * tpm); -void tpm_dec(struct tpm * tpm); +void tpm_begin_work(struct tpm * tpm); -void tpm_inc(struct tpm * tpm); +void tpm_end_work(struct tpm * tpm); #endif /* OUROBOROS_LIB_TPM_H */ diff --git a/include/ouroboros/utils.h b/include/ouroboros/utils.h index 93fbf402..7f625c90 100644 --- a/include/ouroboros/utils.h +++ b/include/ouroboros/utils.h @@ -24,8 +24,9 @@ #define OUROBOROS_LIB_UTILS_H #include <stdint.h> -#include <unistd.h> +#include <stdlib.h> #include <string.h> +#include <unistd.h> #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index c2678fc8..39b053d6 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -643,17 +643,17 @@ static void do_flow_dealloc(int flow_id, static void * mainloop(void * o) { - int sfd; - buffer_t buffer; - ipcp_msg_t * msg; + int sfd; + buffer_t buffer; + ipcp_msg_t * msg; (void) o; while (true) { - ipcp_msg_t ret_msg = IPCP_MSG__INIT; - qosspec_t qs; - struct cmd * cmd; - buffer_t data; + ipcp_msg_t ret_msg = IPCP_MSG__INIT; + qosspec_t qs; + struct cmd * cmd; + buffer_t data; ret_msg.code = IPCP_MSG_CODE__IPCP_REPLY; @@ -679,7 +679,7 @@ static void * mainloop(void * o) continue; } - tpm_dec(ipcpi.tpm); + tpm_begin_work(ipcpi.tpm); pthread_cleanup_push(__cleanup_close_ptr, &sfd); pthread_cleanup_push(free_msg, msg); @@ -753,7 +753,7 @@ static void * mainloop(void * o) if (buffer.len == 0) { log_err("Failed to pack reply message"); close(sfd); - tpm_inc(ipcpi.tpm); + tpm_end_work(ipcpi.tpm); continue; } @@ -761,7 +761,7 @@ static void * mainloop(void * o) if (buffer.data == NULL) { log_err("Failed to create reply buffer."); close(sfd); - tpm_inc(ipcpi.tpm); + tpm_end_work(ipcpi.tpm); continue; } @@ -770,16 +770,16 @@ static void * mainloop(void * o) if (ret_msg.layer_info != NULL) layer_info_msg__free_unpacked(ret_msg.layer_info, NULL); - pthread_cleanup_push(__cleanup_close_ptr, &sfd); pthread_cleanup_push(free, buffer.data) + pthread_cleanup_push(__cleanup_close_ptr, &sfd); if (write(sfd, buffer.data, buffer.len) == -1) log_warn("Failed to send reply message"); - pthread_cleanup_pop(true); - pthread_cleanup_pop(true); + pthread_cleanup_pop(true); /* close sfd */ + pthread_cleanup_pop(true); /* free buffer.data */ - tpm_inc(ipcpi.tpm); + tpm_end_work(ipcpi.tpm); } return (void *) 0; @@ -817,39 +817,38 @@ int ipcp_init(int argc, { bool log; pthread_condattr_t cattr; - int ret = -1; if (parse_args(argc, argv, &log)) return -1; log_init(log); - ipcpi.irmd_fd = -1; ipcpi.state = IPCP_NULL; ipcpi.type = type; #if defined (__linux__) prctl(PR_SET_TIMERSLACK, IPCP_LINUX_SLACK_NS, 0, 0, 0); #endif - ipcpi.sock_path = ipcp_sock_path(getpid()); + ipcpi.sock_path = sock_path(getpid(), IPCP_SOCK_PATH_PREFIX); if (ipcpi.sock_path == NULL) goto fail_sock_path; ipcpi.sockfd = server_socket_open(ipcpi.sock_path); if (ipcpi.sockfd < 0) { - log_err("Could not open server socket."); + log_err("Failed to open server socket at %s.", + ipcpi.sock_path); goto fail_serv_sock; } ipcpi.ops = ops; if (pthread_mutex_init(&ipcpi.state_mtx, NULL)) { - log_err("Could not create mutex."); + log_err("Failed to create mutex."); goto fail_state_mtx; } if (pthread_condattr_init(&cattr)) { - log_err("Could not create condattr."); + log_err("Failed to create condattr."); goto fail_cond_attr; } @@ -857,7 +856,7 @@ int ipcp_init(int argc, pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); #endif if (pthread_cond_init(&ipcpi.state_cond, &cattr)) { - log_err("Could not init condvar."); + log_err("Failed to init condvar."); goto fail_state_cond; } @@ -891,6 +890,8 @@ int ipcp_init(int argc, goto fail_rib_reg; } + list_head_init(&ipcpi.cmds); + ipcpi.tpm = tpm_create(IPCP_MIN_THREADS, IPCP_ADD_THREADS, mainloop, NULL); if (ipcpi.tpm == NULL) { @@ -898,8 +899,6 @@ int ipcp_init(int argc, goto fail_tpm_create; } - list_head_init(&ipcpi.cmds); - ipcpi.alloc_id = -1; pthread_condattr_destroy(&cattr); @@ -931,7 +930,7 @@ int ipcp_init(int argc, fail_serv_sock: free(ipcpi.sock_path); fail_sock_path: - return ret; + return -1; } int ipcp_start(void) @@ -952,8 +951,10 @@ int ipcp_start(void) strcpy(info.name, ipcpi.name); info.state = IPCP_OPERATIONAL; - if (tpm_start(ipcpi.tpm)) + if (tpm_start(ipcpi.tpm)) { + log_err("Failed to start threadpool manager."); goto fail_tpm_start; + } if (pthread_create(&ipcpi.acceptor, NULL, acceptloop, NULL)) { log_err("Failed to create acceptor thread."); diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h index aab490c7..b29f0bf4 100644 --- a/src/ipcpd/ipcp.h +++ b/src/ipcpd/ipcp.h @@ -123,9 +123,6 @@ void ipcp_set_state(enum ipcp_state state); enum ipcp_state ipcp_get_state(void); -int ipcp_parse_arg(int argc, - char * argv[]); - /* Helper functions to handle races during flow allocation */ int ipcp_wait_flow_req_arr(const uint8_t * dst, qosspec_t qs, diff --git a/src/ipcpd/unicast/dir/dht.c b/src/ipcpd/unicast/dir/dht.c index 08a5a5a9..95c5f19a 100644 --- a/src/ipcpd/unicast/dir/dht.c +++ b/src/ipcpd/unicast/dir/dht.c @@ -884,12 +884,12 @@ static void lookup_update(struct dht * dht, contact_destroy(c); } else { struct contact * d; - list_add_tail(&c->next, p); d = list_last_entry(&lu->contacts, struct contact, next); list_del(&d->next); assert(lu->contacts.prv != &d->next); contact_destroy(d); + list_add_tail(&c->next, p); mod = true; } } @@ -2503,7 +2503,7 @@ static void * dht_handle_packet(void * o) continue; } - tpm_dec(dht->tpm); + tpm_begin_work(dht->tpm); addr = msg->s_addr; @@ -2604,7 +2604,7 @@ static void * dht_handle_packet(void * o) free(resp_msg.addrs); if (resp_msg.n_contacts == 0) { - tpm_inc(dht->tpm); + tpm_end_work(dht->tpm); continue; } @@ -2613,7 +2613,7 @@ static void * dht_handle_packet(void * o) NULL); free(resp_msg.contacts); - tpm_inc(dht->tpm); + tpm_end_work(dht->tpm); } return (void *) 0; diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c index 5a9a79d3..28f870a7 100644 --- a/src/irmd/ipcp.c +++ b/src/irmd/ipcp.c @@ -83,7 +83,7 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid, { int sockfd; uint8_t buf[SOCK_BUF_SIZE]; - char * sock_path; + char * spath; ssize_t len; ipcp_msg_t * recv_msg; struct timeval tv; @@ -94,17 +94,17 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid, if (kill(pid, 0) < 0) return NULL; - sock_path = ipcp_sock_path(pid); - if (sock_path == NULL) + spath = sock_path(pid, IPCP_SOCK_PATH_PREFIX); + if (spath == NULL) return NULL; - sockfd = client_socket_open(sock_path); + sockfd = client_socket_open(spath); if (sockfd < 0) { - free(sock_path); + free(spath); return NULL; } - free(sock_path); + free(spath); len = ipcp_msg__get_packed_size(msg); if (len == 0 || len >= SOCK_BUF_SIZE) { diff --git a/src/irmd/main.c b/src/irmd/main.c index cc15078f..cf079698 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -72,7 +72,6 @@ #define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo) #define BIND_TIMEOUT 10 /* ms */ #define DEALLOC_TIME 300 /* s */ -#define MSGBUFSZ 2048 enum irm_state { IRMD_NULL = 0, @@ -1024,7 +1023,6 @@ static int flow_alloc(struct flow_info * flow, log_info("Allocating flow for %d to %s.", flow->n_pid, dst); - if (flow->qs.cypher_s > 0) { ssize_t key_len; @@ -1380,7 +1378,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg) res = disconnect_ipcp(msg->pid, msg->dst, msg->comp); break; case IRM_MSG_CODE__IRM_BIND_PROGRAM: - /* Make exec NULL terminated instead of empty string terminated */ + /* Terminate with NULL instead of "" */ free(msg->exec[msg->n_exec - 1]); msg->exec[msg->n_exec - 1] = NULL; res = bind_program(msg->exec, msg->name, msg->opts); @@ -1540,7 +1538,7 @@ static void * mainloop(void * o) continue; } - tpm_dec(irmd.tpm); + tpm_begin_work(irmd.tpm); pthread_cleanup_push(__cleanup_close_ptr, &sfd); pthread_cleanup_push(free_msg, msg); @@ -1556,12 +1554,12 @@ static void * mainloop(void * o) } if (ret_msg->result == -EPIPE) { - log_dbg("Terminated command: application closed socket."); + log_dbg("Terminated command: remote closed socket."); goto fail; } if (ret_msg->result == -EIRMD) { - log_dbg("Terminated command: IRMd not in running state."); + log_dbg("Terminated command: IRMd not running."); goto fail; } @@ -1596,14 +1594,14 @@ static void * mainloop(void * o) pthread_cleanup_pop(true); pthread_cleanup_pop(true); - tpm_inc(irmd.tpm); + tpm_end_work(irmd.tpm); continue; fail: irm_msg__free_unpacked(ret_msg, NULL); fail_msg: close(sfd); - tpm_inc(irmd.tpm); + tpm_end_work(irmd.tpm); continue; } diff --git a/src/irmd/reg/proc.h b/src/irmd/reg/proc.h index 99f74fef..499ecc72 100644 --- a/src/irmd/reg/proc.h +++ b/src/irmd/reg/proc.h @@ -32,8 +32,8 @@ struct reg_proc { struct proc_info info; - struct list_head names; /* names for which process accepts flows */ - size_t n_names; /* number of names */ + struct list_head names; /* process accepts flows for names */ + size_t n_names; /* number of names */ struct shm_flow_set * set; }; diff --git a/src/irmd/reg/tests/flow_test.c b/src/irmd/reg/tests/flow_test.c index f9d23fd1..3e586341 100644 --- a/src/irmd/reg/tests/flow_test.c +++ b/src/irmd/reg/tests/flow_test.c @@ -28,7 +28,7 @@ #define TEST_DATA "testpiggybackdata" -static int test_reg_flow_create(void) +static int test_reg_flow_create_destroy(void) { struct reg_flow * f; @@ -51,10 +51,10 @@ static int test_reg_flow_create(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_flow_create_no_id(void) { @@ -67,7 +67,7 @@ static int test_reg_flow_create_no_id(void) { reg_flow_create(&info); /* assert fail */ - return 0; + return TEST_RC_SUCCESS; } static int test_reg_flow_create_no_pid(void) { @@ -80,7 +80,7 @@ static int test_reg_flow_create_no_pid(void) { reg_flow_create(&info); /* assert fail */ - return 0; + return TEST_RC_SUCCESS; } static int test_reg_flow_create_has_n_1_pid(void) { @@ -94,7 +94,7 @@ static int test_reg_flow_create_has_n_1_pid(void) { reg_flow_create(&info); /* assert fail */ - return 0; + return TEST_RC_SUCCESS; } static int test_reg_flow_create_wrong_state(void) { @@ -108,7 +108,7 @@ static int test_reg_flow_create_wrong_state(void) { reg_flow_create(&info); /* assert fail */ - return 0; + return TEST_RC_SUCCESS; } static int test_reg_flow_create_has_mpl(void) { @@ -123,7 +123,7 @@ static int test_reg_flow_create_has_mpl(void) { reg_flow_create(&info); /* assert fail */ - return 0; + return TEST_RC_SUCCESS; } static int test_reg_flow_update(void) @@ -163,10 +163,10 @@ static int test_reg_flow_update(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_flow_update_wrong_id(void) @@ -199,10 +199,10 @@ static int test_reg_flow_update_wrong_id(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_flow_assert_fails(void) @@ -210,15 +210,10 @@ static int test_reg_flow_assert_fails(void) int ret = 0; ret |= test_assert_fail(test_reg_flow_create_no_id); - ret |= test_assert_fail(test_reg_flow_create_no_pid); - ret |= test_assert_fail(test_reg_flow_create_has_n_1_pid); - ret |= test_assert_fail(test_reg_flow_create_wrong_state); - ret |= test_assert_fail(test_reg_flow_create_has_mpl); - ret |= test_assert_fail(test_reg_flow_update_wrong_id); return ret; @@ -267,11 +262,11 @@ static int test_flow_data(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: free(data); TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } int flow_test(int argc, @@ -282,12 +277,9 @@ int flow_test(int argc, (void) argc; (void) argv; - ret |= test_reg_flow_create(); - + ret |= test_reg_flow_create_destroy(); ret |= test_reg_flow_update(); - ret |= test_reg_flow_assert_fails(); - ret |= test_flow_data(); return ret; diff --git a/src/irmd/reg/tests/name_test.c b/src/irmd/reg/tests/name_test.c index 48f132e9..64635eec 100644 --- a/src/irmd/reg/tests/name_test.c +++ b/src/irmd/reg/tests/name_test.c @@ -20,8 +20,11 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ + #include "../name.c" +#include <ouroboros/test.h> + #define TEST_PID 65534 #define TEST_PROG "/usr/bin/testprog" #define TEST_NAME "testservicename" @@ -34,6 +37,8 @@ static int test_reg_name_create(void) .pol_lb = LB_RR, }; + TEST_START(); + n = reg_name_create(&info); if (n == NULL) { printf("Failed to create name %s.\n", info.name); @@ -42,9 +47,12 @@ static int test_reg_name_create(void) reg_name_destroy(n); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } static int test_reg_name_add_proc(void) @@ -55,6 +63,8 @@ static int test_reg_name_add_proc(void) .pol_lb = LB_RR, }; + TEST_START(); + n = reg_name_create(&info); if (n == NULL) { printf("Failed to create name %s.\n", info.name); @@ -85,9 +95,12 @@ static int test_reg_name_add_proc(void) reg_name_destroy(n); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } static int test_reg_name_add_prog(void) @@ -100,6 +113,8 @@ static int test_reg_name_add_prog(void) char * exec[] = { TEST_PROG, "--argswitch", "argvalue", NULL}; + TEST_START(); + n = reg_name_create(&info); if (n == NULL) { printf("Failed to create name %s.\n", info.name); @@ -130,9 +145,12 @@ static int test_reg_name_add_prog(void) reg_name_destroy(n); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } static int test_reg_name_add_active(enum pol_balance lb) @@ -144,6 +162,8 @@ static int test_reg_name_add_active(enum pol_balance lb) .pol_lb = lb, }; + TEST_START(); + n = reg_name_create(&info); if (n == NULL) { printf("Failed to create name %s.\n", info.name); @@ -255,9 +275,12 @@ static int test_reg_name_add_active(enum pol_balance lb) reg_name_destroy(n); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } @@ -270,13 +293,9 @@ int name_test(int argc, (void) argv; res |= test_reg_name_create(); - res |= test_reg_name_add_proc(); - res |= test_reg_name_add_prog(); - res |= test_reg_name_add_active(LB_RR); - res |= test_reg_name_add_active(LB_SPILL); return res; diff --git a/src/irmd/reg/tests/proc_test.c b/src/irmd/reg/tests/proc_test.c index 5c9dd865..df0527fb 100644 --- a/src/irmd/reg/tests/proc_test.c +++ b/src/irmd/reg/tests/proc_test.c @@ -22,10 +22,12 @@ #include "../proc.c" +#include <ouroboros/test.h> + #define TEST_PID 65534 #define TEST_PROG "usr/bin/testprog" -static int test_reg_proc_create(void) +static int test_reg_proc_create_destroy(void) { struct reg_proc * proc; struct proc_info info = { @@ -33,6 +35,8 @@ static int test_reg_proc_create(void) .prog = TEST_PROG }; + TEST_START(); + proc = reg_proc_create(&info); if (proc == NULL) { printf("Failed to create proc.\n"); @@ -41,9 +45,12 @@ static int test_reg_proc_create(void) reg_proc_destroy(proc); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } static int test_reg_proc_add_name(void) @@ -56,6 +63,8 @@ static int test_reg_proc_add_name(void) char * name = "testname"; + TEST_START(); + proc = reg_proc_create(&info); if (proc == NULL) { printf("Failed to create proc.\n"); @@ -86,9 +95,12 @@ static int test_reg_proc_add_name(void) reg_proc_destroy(proc); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } int proc_test(int argc, @@ -99,8 +111,7 @@ int proc_test(int argc, (void) argc; (void) argv; - res |= test_reg_proc_create(); - + res |= test_reg_proc_create_destroy(); res |= test_reg_proc_add_name(); return res; diff --git a/src/irmd/reg/tests/prog_test.c b/src/irmd/reg/tests/prog_test.c index 5e6931d8..c394c222 100644 --- a/src/irmd/reg/tests/prog_test.c +++ b/src/irmd/reg/tests/prog_test.c @@ -22,8 +22,9 @@ #include "../prog.c" -#define TEST_PROG "usr/bin/testprog" +#include <ouroboros/test.h> +#define TEST_PROG "usr/bin/testprog" static int test_reg_prog_create(void) { @@ -32,6 +33,8 @@ static int test_reg_prog_create(void) .name = TEST_PROG }; + TEST_START(); + prog = reg_prog_create(&info); if (prog == NULL) { printf("Failed to create prog.\n"); @@ -40,9 +43,12 @@ static int test_reg_prog_create(void) reg_prog_destroy(prog); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } static int test_reg_prog_add_name(void) @@ -54,6 +60,8 @@ static int test_reg_prog_add_name(void) char * name = "testname"; + TEST_START(); + prog = reg_prog_create(&info); if (prog == NULL) { printf("Failed to create prog.\n"); @@ -84,9 +92,12 @@ static int test_reg_prog_add_name(void) reg_prog_destroy(prog); - return 0; + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; fail: - return -1; + TEST_FAIL(); + return TEST_RC_FAIL; } int prog_test(int argc, @@ -98,7 +109,6 @@ int prog_test(int argc, (void) argv; ret |= test_reg_prog_create(); - ret |= test_reg_prog_add_name(); return ret; diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c index c341c297..80fc64d6 100644 --- a/src/irmd/reg/tests/reg_test.c +++ b/src/irmd/reg/tests/reg_test.c @@ -51,10 +51,10 @@ static int test_reg_init(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_create_flow(void) @@ -105,10 +105,10 @@ static int test_reg_create_flow(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_allocate_flow_timeout(void) @@ -179,10 +179,10 @@ static int test_reg_allocate_flow_timeout(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static void * test_flow_respond_alloc(void * o) @@ -321,10 +321,10 @@ static int test_reg_accept_flow_success(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_accept_flow_success_no_crypt(void) @@ -416,10 +416,10 @@ static int test_reg_accept_flow_success_no_crypt(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } @@ -486,23 +486,19 @@ static int test_reg_allocate_flow_fail(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_flow(void) { int ret = 0; ret |= test_reg_create_flow(); - ret |= test_reg_allocate_flow_timeout(); - ret |= test_reg_accept_flow_success(); - ret |= test_reg_accept_flow_success_no_crypt(); - ret |= test_reg_allocate_flow_fail(); return ret; @@ -552,10 +548,10 @@ static int test_reg_create_ipcp(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_set_layer(void) @@ -614,10 +610,10 @@ static int test_set_layer(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_ipcp(void) @@ -625,7 +621,6 @@ static int test_reg_ipcp(void) int ret = 0; ret |= test_reg_create_ipcp(); - ret |= test_set_layer(); return ret; @@ -674,10 +669,10 @@ static int test_reg_create_name(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_name(void) @@ -732,10 +727,10 @@ static int test_reg_create_proc(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_proc(void) @@ -785,10 +780,10 @@ static int test_reg_spawned(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_create_prog(void) @@ -833,10 +828,10 @@ static int test_reg_create_prog(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_reg_prog(void) @@ -900,10 +895,10 @@ static int test_bind_proc(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_bind_prog(void) @@ -989,10 +984,10 @@ static int test_bind_prog(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_inherit_prog(void) @@ -1060,10 +1055,10 @@ static int test_inherit_prog(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_wait_accepting_timeout(void) @@ -1106,10 +1101,10 @@ static int test_wait_accepting_timeout(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_wait_accepting_fail_name(void) @@ -1140,10 +1135,10 @@ static int test_wait_accepting_fail_name(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static void * test_call_flow_accept(void * o) @@ -1242,10 +1237,10 @@ static int test_wait_accepting_success(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_wait_accepting(void) @@ -1253,9 +1248,7 @@ static int test_wait_accepting(void) int ret = 0; ret |= test_wait_accepting_timeout(); - ret |= test_wait_accepting_fail_name(); - ret |= test_wait_accepting_success(); return ret; @@ -1300,10 +1293,10 @@ static int test_wait_ipcp_boot_timeout(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static void * test_ipcp_respond(void * o) @@ -1371,10 +1364,10 @@ static int test_wait_ipcp_boot_fail(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_wait_ipcp_boot_success(void) @@ -1433,10 +1426,10 @@ static int test_wait_ipcp_boot_success(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_wait_ipcp_boot(void) @@ -1444,9 +1437,7 @@ static int test_wait_ipcp_boot(void) int ret = 0; ret |= test_wait_ipcp_boot_timeout(); - ret |= test_wait_ipcp_boot_fail(); - ret |= test_wait_ipcp_boot_success(); return ret; @@ -1477,10 +1468,10 @@ static int test_wait_proc_timeout(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static void * test_proc(void * o) @@ -1527,10 +1518,10 @@ static int test_wait_proc_success(void) TEST_SUCCESS(); - return 0; + return TEST_RC_SUCCESS; fail: REG_TEST_FAIL(); - return -1; + return TEST_RC_FAIL; } static int test_wait_proc(void) @@ -1538,7 +1529,6 @@ static int test_wait_proc(void) int ret = 0; ret |= test_wait_proc_timeout(); - ret |= test_wait_proc_success(); return ret; @@ -1554,29 +1544,17 @@ int reg_test(int argc, (void) argv; ret |= test_reg_init(); - ret |= test_reg_flow(); - ret |= test_reg_ipcp(); - ret |= test_reg_name(); - ret |= test_reg_proc(); - ret |= test_reg_prog(); - ret |= test_reg_spawned(); - ret |= test_bind_proc(); - ret |= test_bind_prog(); - ret |= test_inherit_prog(); - ret |= test_wait_accepting(); - ret |= test_wait_ipcp_boot(); - ret |= test_wait_proc(); return ret; diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 231eb785..cc73a9fc 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -121,6 +121,7 @@ if (OPENSSL_FOUND) unset(HAVE_OPENSSL) endif() endif () + set(OPENSSL_SOURCES crypt/openssl.c) else() message(STATUS "Install openSSL version >= \"1.1.0\" to enable OpenSSL support") unset(HAVE_OPENSSL_RNG) @@ -128,6 +129,7 @@ else() set(OPENSSL_INCLUDE_DIR "") set(OPENSSL_LIBRARIES "") set(OPENSSL_CRYPTO_LIBRARY "") + set(OPENSSL_SOURCES "") endif () if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") @@ -284,7 +286,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" add_library(ouroboros-common SHARED ${SOURCE_FILES_COMMON} ${IRM_PROTO_SRCS} ${IPCP_PROTO_SRCS} ${IPCP_CONFIG_PROTO_SRCS} ${MODEL_PROTO_SRCS} - ${ENROLL_PROTO_SRCS}) + ${ENROLL_PROTO_SRCS} ${OPENSSL_SOURCES}) add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CEP_PROTO_SRCS}) diff --git a/src/lib/config.h.in b/src/lib/config.h.in index 604038b4..21a30493 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -23,6 +23,7 @@ #cmakedefine HAVE_SYS_RANDOM #cmakedefine HAVE_LIBGCRYPT #cmakedefine HAVE_OPENSSL +#cmakedefine OPENSS_VERSION_MAJOR @OPENSSL_VERSION_MAJOR@ #ifdef HAVE_OPENSSL #define HAVE_ENCRYPTION diff --git a/src/lib/crypt.c b/src/lib/crypt.c index ad679501..756fcccc 100644 --- a/src/lib/crypt.c +++ b/src/lib/crypt.c @@ -1,8 +1,7 @@ /* * Ouroboros - Copyright (C) 2016 - 2024 * - * Elliptic curve Diffie-Hellman key exchange and - * AES encryption for flows using OpenSSL + * Cryptographic operations * * Dimitri Staessens <dimitri@ouroboros.rocks> * Sander Vrijders <sander@ouroboros.rocks> @@ -20,436 +19,386 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., http://www.fsf.org/about/contact/. */ + #include <config.h> #include <ouroboros/crypt.h> #include <ouroboros/errno.h> +#ifdef HAVE_OPENSSL + #include "crypt/openssl.h" +#endif /* HAVE_OPENSSL */ #include <assert.h> #include <string.h> -#ifdef HAVE_OPENSSL - -#include <ouroboros/hash.h> -#include <ouroboros/random.h> - -#include <openssl/evp.h> -#include <openssl/ec.h> -#include <openssl/pem.h> - -#include <openssl/bio.h> +struct crypt_ctx { + uint16_t flags; + void * ctx; + uint8_t key[SYMMKEYSZ]; +}; -#define IVSZ 16 -/* SYMMKEYSZ defined in dev.c */ +struct auth_ctx { + void * store; +}; -/* - * Derive the common secret from - * your public key pair (kp) - * the remote public key (pub). - * Store it in a preallocated buffer (s). - */ -static int __openssl_ecdh_derive_secret(EVP_PKEY * kp, - EVP_PKEY * pub, - uint8_t * s) +int crypt_dh_pkp_create(void ** pkp, + uint8_t * pk) { - EVP_PKEY_CTX * ctx; - int ret; - uint8_t * secret; - size_t secret_len; - - ctx = EVP_PKEY_CTX_new(kp, NULL); - if (ctx == NULL) - goto fail_new; - - ret = EVP_PKEY_derive_init(ctx); - if (ret != 1) - goto fail_ctx; - - ret = EVP_PKEY_derive_set_peer(ctx, pub); - if (ret != 1) - goto fail_ctx; - - ret = EVP_PKEY_derive(ctx, NULL, &secret_len); - if (ret != 1) - goto fail_ctx; - - if (secret_len < SYMMKEYSZ) - goto fail_ctx; - - secret = OPENSSL_malloc(secret_len); - if (secret == NULL) - goto fail_ctx; - - ret = EVP_PKEY_derive(ctx, secret, &secret_len); - if (ret != 1) - goto fail_derive; - - /* Hash the secret for use as AES key. */ - mem_hash(HASH_SHA3_256, s, secret, secret_len); +#ifdef HAVE_OPENSSL + assert(pkp != NULL); + *pkp = NULL; + return openssl_ecdh_pkp_create(pkp, pk); +#else + (void) pkp; + (void) pk; - OPENSSL_free(secret); - EVP_PKEY_CTX_free(ctx); + *pkp = NULL; return 0; - - fail_derive: - OPENSSL_free(secret); - fail_ctx: - EVP_PKEY_CTX_free(ctx); - fail_new: - return -ECRYPT; +#endif } -static int __openssl_ecdh_gen_key(void ** kp) +void crypt_dh_pkp_destroy(void * pkp) { - EVP_PKEY_CTX * ctx = NULL; - EVP_PKEY_CTX * kctx = NULL; - EVP_PKEY * params = NULL; - int ret; - - ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); - if (ctx == NULL) - goto fail_new_id; - - ret = EVP_PKEY_paramgen_init(ctx); - if (ret != 1) - goto fail_paramgen; - - ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1); - if (ret != 1) - goto fail_paramgen; - - ret = EVP_PKEY_paramgen(ctx, ¶ms); - if (ret != 1) - goto fail_paramgen; - - kctx = EVP_PKEY_CTX_new(params, NULL); - if (kctx == NULL) - goto fail_keygen_init; - - ret = EVP_PKEY_keygen_init(kctx); - if (ret != 1) - goto fail_keygen; - - ret = EVP_PKEY_keygen(kctx, (EVP_PKEY **) kp); - if (ret != 1) - goto fail_keygen; +#ifdef HAVE_OPENSSL + openssl_ecdh_pkp_destroy(pkp); +#else + (void) pkp; + return; +#endif +} - EVP_PKEY_free(params); - EVP_PKEY_CTX_free(kctx); - EVP_PKEY_CTX_free(ctx); +int crypt_dh_derive(void * pkp, + buffer_t pk, + uint8_t * s) +{ +#ifdef HAVE_OPENSSL + return openssl_ecdh_derive(pkp, pk, s); +#else + (void) pkp; + (void) pk; - return 0; + memset(s, 0, SYMMKEYSZ); - fail_keygen: - EVP_PKEY_CTX_free(kctx); - fail_keygen_init: - EVP_PKEY_free(params); - fail_paramgen: - EVP_PKEY_CTX_free(ctx); - fail_new_id: return -ECRYPT; +#endif } -static ssize_t openssl_ecdh_pkp_create(void ** pkp, - uint8_t * pk) +int crypt_encrypt(struct crypt_ctx * ctx, + buffer_t in, + buffer_t * out) { - uint8_t * pos; - ssize_t len; - - assert(pkp != NULL); - assert(*pkp == NULL); - assert(pk != NULL); - - if (__openssl_ecdh_gen_key(pkp) < 0) - return -ECRYPT; - - assert(*pkp != NULL); - - pos = pk; /* i2d_PUBKEY increments the pointer, don't use buf! */ - len = i2d_PUBKEY(*pkp, &pos); - if (len < 0) { - EVP_PKEY_free(*pkp); - return -ECRYPT; + if (ctx->flags == 0) { + clrbuf(*out); + return 0; } - return len; -} +#ifdef HAVE_OPENSSL + return openssl_encrypt(ctx->ctx, ctx->key, in, out); +#else + (void) in; + (void) out; -static void openssl_ecdh_pkp_destroy(void * pkp) -{ - EVP_PKEY_free((EVP_PKEY *) pkp); + return -ECRYPT; +#endif } -static int openssl_ecdh_derive(void * pkp, - buffer_t pk, - uint8_t * s) +int crypt_decrypt(struct crypt_ctx * ctx, + buffer_t in, + buffer_t * out) { - uint8_t * pos; - EVP_PKEY * pub; - - pos = pk.data; /* d2i_PUBKEY increments the pointer, don't use key ptr! */ - pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) pk.len); - if (pub == NULL) - return -ECRYPT; - - if (__openssl_ecdh_derive_secret(pkp, pub, s) < 0) { - EVP_PKEY_free(pub); - return -ECRYPT; + if (ctx->flags == 0) { + clrbuf(*out); + return 0; } - EVP_PKEY_free(pub); +#ifdef HAVE_OPENSSL + return openssl_decrypt(ctx->ctx, ctx->key, in, out); +#else + (void) in; + (void) out; - return 0; + return -ECRYPT; +#endif } -/* - * AES encryption calls. If FRCT is disabled, we should generate a - * 128-bit random IV and append it to the packet. If the flow is - * reliable, we could initialize the context once, and consider the - * stream a single encrypted message to avoid initializing the - * encryption context for each packet. - */ - -static int openssl_encrypt(void * ctx, - uint8_t * key, - struct shm_du_buff * sdb) +struct crypt_ctx * crypt_create_ctx(uint16_t flags, + const uint8_t * key) { - uint8_t * out; - uint8_t * in; - uint8_t * head; - uint8_t iv[IVSZ]; - int in_sz; - int out_sz; - int tmp_sz; - int ret; - - in = shm_du_buff_head(sdb); - in_sz = shm_du_buff_tail(sdb) - in; - - assert(in_sz > 0); - - if (random_buffer(iv, IVSZ) < 0) - goto fail_iv; - - out = malloc(in_sz + EVP_MAX_BLOCK_LENGTH); - if (out == NULL) - goto fail_iv; + struct crypt_ctx * crypt; - EVP_CIPHER_CTX_reset(ctx); + crypt = malloc(sizeof(*crypt)); + if (crypt == NULL) + goto fail_crypt; - ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); - if (ret != 1) - goto fail_encrypt_init; + memset(crypt, 0, sizeof(*crypt)); - ret = EVP_EncryptUpdate(ctx, out, &tmp_sz, in, in_sz); - if (ret != 1) - goto fail_encrypt; - - out_sz = tmp_sz; - ret = EVP_EncryptFinal_ex(ctx, out + tmp_sz, &tmp_sz); - if (ret != 1) - goto fail_encrypt; - - out_sz += tmp_sz; - - EVP_CIPHER_CTX_cleanup(ctx); - - assert(out_sz >= in_sz); + crypt->flags = flags; + if (key != NULL) + memcpy(crypt->key, key, SYMMKEYSZ); +#ifdef HAVE_OPENSSL + crypt->ctx=openssl_crypt_create_ctx(); + if (crypt->ctx == NULL) + goto fail_ctx; +#endif + return crypt; +#ifdef HAVE_OPENSSL + fail_ctx: + free(crypt); +#endif + fail_crypt: + return NULL; +} - head = shm_du_buff_head_alloc(sdb, IVSZ); - if (head == NULL) - goto fail_encrypt; +void crypt_destroy_ctx(struct crypt_ctx * crypt) +{ + if (crypt == NULL) + return; - if (shm_du_buff_tail_alloc(sdb, out_sz - in_sz) == NULL) - goto fail_tail_alloc; +#ifdef HAVE_OPENSSL + assert(crypt->ctx != NULL); + openssl_crypt_destroy_ctx(crypt->ctx); +#else + assert(crypt->ctx == NULL); +#endif + free(crypt); +} - memcpy(head, iv, IVSZ); - memcpy(in, out, out_sz); +int crypt_load_privkey_file(const char * path, + void ** key) +{ + *key = NULL; - free(out); +#ifdef HAVE_OPENSSL + return openssl_load_privkey_file(path, key); +#else + (void) path; return 0; - - fail_tail_alloc: - shm_du_buff_head_release(sdb, IVSZ); - fail_encrypt: - EVP_CIPHER_CTX_cleanup(ctx); - fail_encrypt_init: - free(out); - fail_iv: - return -ECRYPT; +#endif } -static int openssl_decrypt(void * ctx, - uint8_t * key, - struct shm_du_buff * sdb) +int crypt_load_privkey_str(const char * str, + void ** key) { - uint8_t * in; - uint8_t * out; - uint8_t iv[IVSZ]; - int ret; - int out_sz; - int in_sz; - int tmp_sz; + *key = NULL; - in_sz = shm_du_buff_len(sdb); - if (in_sz < IVSZ) - return -ECRYPT; - - in = shm_du_buff_head_release(sdb, IVSZ); +#ifdef HAVE_OPENSSL + return openssl_load_privkey_str(str, key); +#else + (void) str; - memcpy(iv, in, IVSZ); + return 0; +#endif +} - in = shm_du_buff_head(sdb); - in_sz = shm_du_buff_tail(sdb) - in; +int crypt_load_pubkey_str(const char * str, + void ** key) +{ + *key = NULL; - out = malloc(in_sz); - if (out == NULL) - goto fail_malloc; +#ifdef HAVE_OPENSSL + return openssl_load_pubkey_str(str, key); +#else + (void) str; - EVP_CIPHER_CTX_reset(ctx); + return 0; +#endif +} - ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); - if (ret != 1) - goto fail_decrypt_init; +int crypt_cmp_key(const void * key1, + const void * key2) +{ +#ifdef HAVE_OPENSSL + return openssl_cmp_key(key1, key2); +#else + (void) key1; + (void) key2; - ret = EVP_DecryptUpdate(ctx, out, &tmp_sz, in, in_sz); - if (ret != 1) - goto fail_decrypt; + return 0; +#endif +} - out_sz = tmp_sz; +void crypt_free_key(void * key) +{ + if (key == NULL) + return; - ret = EVP_DecryptFinal_ex(ctx, out + tmp_sz, &tmp_sz); - if (ret != 1) - goto fail_decrypt; +#ifdef HAVE_OPENSSL + openssl_free_key(key); +#endif +} - out_sz += tmp_sz; +int crypt_load_crt_file(const char * path, + void ** crt) +{ + *crt = NULL; - assert(out_sz <= in_sz); +#ifdef HAVE_OPENSSL + return openssl_load_crt_file(path, crt); +#else + (void) path; - shm_du_buff_tail_release(sdb, in_sz - out_sz); + return 0; +#endif +} - memcpy(in, out, out_sz); +int crypt_load_crt_str(const char * str, + void ** crt) +{ + *crt = NULL; - free(out); +#ifdef HAVE_OPENSSL + return openssl_load_crt_str(str, crt); +#else + (void) str; return 0; - - fail_decrypt: - EVP_CIPHER_CTX_cleanup(ctx); - fail_decrypt_init: - free(out); - fail_malloc: - return -ECRYPT; - +#endif } -static int openssl_crypt_init(void ** ctx) +int crypt_get_pubkey_crt(void * crt, + void ** pk) { - *ctx = EVP_CIPHER_CTX_new(); - if (*ctx == NULL) - return -ECRYPT; + assert(crt != NULL); + assert(pk != NULL); + +#ifdef HAVE_OPENSSL + return openssl_get_pubkey_crt(crt, pk); +#else + (void) crt; + + clrbuf(*pk); return 0; +#endif } -static void openssl_crypt_fini(void * ctx) +void crypt_free_crt(void * crt) { - EVP_CIPHER_CTX_free(ctx); + if (crt == NULL) + return; +#ifdef HAVE_OPENSSL + openssl_free_crt(crt); +#endif } -#endif /* HAVE_OPENSSL */ - -int crypt_dh_pkp_create(void ** pkp, - uint8_t * pk) +int crypt_crt_str(void * crt, + char * buf) { #ifdef HAVE_OPENSSL - assert(pkp != NULL); - *pkp = NULL; - return openssl_ecdh_pkp_create(pkp, pk); + return openssl_crt_str(crt, buf); #else - (void) pkp; - (void) pk; - - *pkp = NULL; + (void) crt; + (void) buf; return 0; #endif } -void crypt_dh_pkp_destroy(void * pkp) +int crypt_check_crt_name(void * crt, + const char * name) { #ifdef HAVE_OPENSSL - openssl_ecdh_pkp_destroy(pkp); + return openssl_check_crt_name(crt, name); #else - (void) pkp; - return; + (void) crt; + (void) name; + + return 0; #endif } -int crypt_dh_derive(void * pkp, - buffer_t pk, - uint8_t * s) +struct auth_ctx * auth_create_ctx(void) { -#ifdef HAVE_OPENSSL - return openssl_ecdh_derive(pkp, pk, s); -#else - (void) pkp; - (void) pk; + struct auth_ctx * ctx; - memset(s, 0, SYMMKEYSZ); + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + goto fail_malloc; - return -ECRYPT; + memset(ctx, 0, sizeof(*ctx)); +#ifdef HAVE_OPENSSL + ctx->store = openssl_auth_create_store(); + if (ctx->store == NULL) + goto fail_store; +#endif + return ctx; +#ifdef HAVE_OPENSSL + fail_store: + free(ctx); #endif + fail_malloc: + return NULL; } -int crypt_encrypt(struct crypt_info * info, - struct shm_du_buff * sdb) +void auth_destroy_ctx(struct auth_ctx * ctx) { - if (info->flags == 0) - return 0; + if (ctx == NULL) + return; +#ifdef HAVE_OPENSSL + openssl_auth_destroy_store(ctx->store); +#endif + free(ctx); +} + +int auth_add_crt_to_store(struct auth_ctx * ctx, + void * crt) +{ + assert(ctx != NULL); + assert(crt != NULL); #ifdef HAVE_OPENSSL - return openssl_encrypt(info->ctx, info->key, sdb); + return openssl_auth_add_crt_to_store(ctx->store, crt); #else - (void) sdb; + (void) ctx; + (void) crt; - return 0; + return -1; #endif } -int crypt_decrypt(struct crypt_info * info, - struct shm_du_buff * sdb) +int auth_verify_crt(struct auth_ctx * ctx, + void * crt) { - if (info->flags == 0) - return 0; - #ifdef HAVE_OPENSSL - return openssl_decrypt(info->ctx, info->key, sdb); + return openssl_verify_crt(ctx->store, crt); #else - (void) sdb; + (void) ctx; + (void) crt; - return -ECRYPT; + return 0; #endif } -int crypt_init(struct crypt_info * info) +int auth_sign(void * pkp, + buffer_t msg, + buffer_t * sig) { #ifdef HAVE_OPENSSL - return openssl_crypt_init(&info->ctx); + return openssl_sign(pkp, msg, sig); #else - info->ctx = NULL; + (void) pkp; + (void) msg; + (void) sig; + + clrbuf(*sig); + return 0; #endif } -void crypt_fini(struct crypt_info * info) +int auth_verify_sig(void * pk, + buffer_t msg, + buffer_t sig) { #ifdef HAVE_OPENSSL - openssl_crypt_fini(info->ctx); + return openssl_verify_sig(pk, msg, sig); #else - (void) info; - assert(info->ctx == NULL); + (void) pk; + (void) msg; + (void) sig; + + return 0; #endif } diff --git a/src/lib/crypt/openssl.c b/src/lib/crypt/openssl.c new file mode 100644 index 00000000..6e7a5dab --- /dev/null +++ b/src/lib/crypt/openssl.c @@ -0,0 +1,744 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * OpenSSL based cryptographic operations + * Elliptic curve Diffie-Hellman key exchange + * AES encryption + # Authentication + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include <ouroboros/errno.h> +#include <ouroboros/crypt.h> +#include <ouroboros/hash.h> +#include <ouroboros/random.h> +#include <ouroboros/utils.h> + +#include <assert.h> + +#include <openssl/evp.h> +#include <openssl/bio.h> +#include <openssl/ec.h> +#include <openssl/pem.h> +#include <openssl/sha.h> +#include <openssl/x509v3.h> +#include <openssl/x509_vfy.h> + +/* + * Derive the common secret from + * - your public key pair (kp) + * - the remote public key (pub). + * Store it in a preallocated buffer (s). + */ +static int __openssl_ecdh_derive_secret(EVP_PKEY * kp, + EVP_PKEY * pub, + uint8_t * s) +{ + EVP_PKEY_CTX * ctx; + int ret; + uint8_t * secret; + size_t secret_len; + + ctx = EVP_PKEY_CTX_new(kp, NULL); + if (ctx == NULL) + goto fail_new; + + ret = EVP_PKEY_derive_init(ctx); + if (ret != 1) + goto fail_ctx; + + ret = EVP_PKEY_derive_set_peer(ctx, pub); + if (ret != 1) + goto fail_ctx; + + ret = EVP_PKEY_derive(ctx, NULL, &secret_len); + if (ret != 1) + goto fail_ctx; + + if (secret_len < SYMMKEYSZ) + goto fail_ctx; + + secret = OPENSSL_malloc(secret_len); + if (secret == NULL) + goto fail_ctx; + + ret = EVP_PKEY_derive(ctx, secret, &secret_len); + if (ret != 1) + goto fail_derive; + + /* Hash the secret for use as AES key. */ + mem_hash(HASH_SHA3_256, s, secret, secret_len); + + OPENSSL_free(secret); + EVP_PKEY_CTX_free(ctx); + + return 0; + fail_derive: + OPENSSL_free(secret); + fail_ctx: + EVP_PKEY_CTX_free(ctx); + fail_new: + return -ECRYPT; +} + +static int __openssl_ecdh_gen_key(void ** kp) +{ + EVP_PKEY_CTX * ctx = NULL; + EVP_PKEY_CTX * kctx = NULL; + EVP_PKEY * params = NULL; + int ret; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (ctx == NULL) + goto fail_new_id; + + ret = EVP_PKEY_paramgen_init(ctx); + if (ret != 1) + goto fail_paramgen; + + ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1); + if (ret != 1) + goto fail_paramgen; + + ret = EVP_PKEY_paramgen(ctx, ¶ms); + if (ret != 1) + goto fail_paramgen; + + kctx = EVP_PKEY_CTX_new(params, NULL); + if (kctx == NULL) + goto fail_keygen_init; + + ret = EVP_PKEY_keygen_init(kctx); + if (ret != 1) + goto fail_keygen; + + ret = EVP_PKEY_keygen(kctx, (EVP_PKEY **) kp); + if (ret != 1) + goto fail_keygen; + + EVP_PKEY_free(params); + EVP_PKEY_CTX_free(kctx); + EVP_PKEY_CTX_free(ctx); + + return 0; + fail_keygen: + EVP_PKEY_CTX_free(kctx); + fail_keygen_init: + EVP_PKEY_free(params); + fail_paramgen: + EVP_PKEY_CTX_free(ctx); + fail_new_id: + return -ECRYPT; +} + +ssize_t openssl_ecdh_pkp_create(void ** pkp, + uint8_t * pk) +{ + uint8_t * pos; + ssize_t len; + + assert(pkp != NULL); + assert(*pkp == NULL); + assert(pk != NULL); + + if (__openssl_ecdh_gen_key(pkp) < 0) + goto fail_key; + + pos = pk; /* i2d_PUBKEY increments the pointer, don't use buf! */ + len = i2d_PUBKEY(*pkp, &pos); + if (len < 0) + goto fail_pubkey; + + return len; + fail_pubkey: + EVP_PKEY_free(*pkp); + fail_key: + return -ECRYPT; +} + +void openssl_ecdh_pkp_destroy(void * pkp) +{ + EVP_PKEY_free((EVP_PKEY *) pkp); +} + +int openssl_ecdh_derive(void * pkp, + buffer_t pk, + uint8_t * s) +{ + uint8_t * pos; + EVP_PKEY * pub; + + pos = pk.data; /* d2i_PUBKEY increments pos, don't use key ptr! */ + pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) pk.len); + if (pub == NULL) + goto fail_pubkey; + + if (__openssl_ecdh_derive_secret(pkp, pub, s) < 0) + goto fail_key; + + EVP_PKEY_free(pub); + + return 0; + fail_pubkey: + EVP_PKEY_free(pub); + fail_key: + return -ECRYPT; +} + +/* + * AES encryption calls. If FRCT is disabled, we should generate a + * 128-bit random IV and append it to the packet. If the flow is + * reliable, we could initialize the context once, and consider the + * stream a single encrypted message to avoid initializing the + * encryption context for each packet. + */ + +int openssl_encrypt(void * ctx, + uint8_t * key, + buffer_t in, + buffer_t * out) +{ + uint8_t * ptr; + uint8_t * iv; + int in_sz; + int out_sz; + int tmp_sz; + int ret; + + in_sz = (int) in.len; + + out->data = malloc(in.len + EVP_MAX_BLOCK_LENGTH + IVSZ); + if (out->data == NULL) + goto fail_malloc; + + iv = out->data; + ptr = out->data + IVSZ; + + if (random_buffer(iv, IVSZ) < 0) + goto fail_iv; + + EVP_CIPHER_CTX_reset(ctx); + + ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); + if (ret != 1) + goto fail_iv; + + ret = EVP_EncryptUpdate(ctx, ptr, &tmp_sz, in.data, in_sz); + if (ret != 1) + goto fail_encrypt; + + out_sz = tmp_sz; + ret = EVP_EncryptFinal_ex(ctx, ptr + tmp_sz, &tmp_sz); + if (ret != 1) + goto fail_encrypt; + + out_sz += tmp_sz; + + EVP_CIPHER_CTX_cleanup(ctx); + + assert(out_sz >= in_sz); + + out->len = (size_t) out_sz + IVSZ; + + return 0; + fail_encrypt: + EVP_CIPHER_CTX_cleanup(ctx); + fail_iv: + free(out->data); + fail_malloc: + clrbuf(*out); + return -ECRYPT; +} + +int openssl_decrypt(void * ctx, + uint8_t * key, + buffer_t in, + buffer_t * out) +{ + uint8_t * ptr; + uint8_t * iv; + uint8_t * input; + int ret; + int out_sz; + int in_sz; + int tmp_sz; + + in_sz = (int) in.len - IVSZ; + if (in_sz < 0) + return -ECRYPT; + + out->data = malloc(in_sz); + if (out->data == NULL) + goto fail_malloc; + + iv = in.data; + ptr = out->data; + input = in.data + IVSZ; + + EVP_CIPHER_CTX_reset(ctx); + + ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); + if (ret != 1) + goto fail_decrypt_init; + + ret = EVP_DecryptUpdate(ctx, ptr, &tmp_sz, input, in_sz); + if (ret != 1) + goto fail_decrypt; + + out_sz = tmp_sz; + ret = EVP_DecryptFinal_ex(ctx, ptr + tmp_sz, &tmp_sz); + if (ret != 1) + goto fail_decrypt; + + out_sz += tmp_sz; + + assert(out_sz <= in_sz); + + out->len = (size_t) out_sz; + + return 0; + fail_decrypt: + EVP_CIPHER_CTX_cleanup(ctx); + fail_decrypt_init: + free(out->data); + fail_malloc: + clrbuf(*out); + return -ECRYPT; +} + +void * openssl_crypt_create_ctx(void) +{ + return (void *) EVP_CIPHER_CTX_new(); +} + +void openssl_crypt_destroy_ctx(void * ctx) +{ + EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *) ctx); +} + +/* AUTHENTICATION */ + +int openssl_load_crt_file(const char * path, + void ** crt) +{ + FILE * fp; + X509 * xcrt; + + fp = fopen(path, "r"); + if (fp == NULL) + goto fail_file; + + xcrt = PEM_read_X509(fp, NULL, NULL, NULL); + if (xcrt == NULL) + goto fail_crt; + + fclose(fp); + + *crt = (void *) xcrt; + + return 0; + fail_crt: + fclose(fp); + fail_file: + *crt = NULL; + return -1; +} + +int openssl_load_crt_str(const char * str, + void ** crt) +{ + BIO * bio; + X509 * xcrt; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto fail_bio; + + if (BIO_write(bio, str, strlen(str)) < 0) + goto fail_crt; + + xcrt = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (xcrt == NULL) + goto fail_crt; + + BIO_free(bio); + + *crt = (void *) xcrt; + + return 0; + fail_crt: + BIO_free(bio); + fail_bio: + *crt = NULL; + return -1; +} + +int openssl_get_pubkey_crt(void * crt, + void ** key) +{ + EVP_PKEY * pk; + X509 * xcrt; + + assert(crt != NULL); + assert(key != NULL); + + xcrt = (X509 *) crt; + + pk = X509_get_pubkey(xcrt); + if (pk == NULL) + goto fail_key; + + *key = (void *) pk; + + return 0; + fail_key: + return -1; +} + +void openssl_free_crt(void * crt) +{ + X509_free((X509 *) crt); +} + +int openssl_load_privkey_file(const char * path, + void ** key) +{ + FILE * fp; + EVP_PKEY * pkey; + + fp = fopen(path, "r"); + if (fp == NULL) + goto fail_file; + + pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); + if (pkey == NULL) + goto fail_key; + + fclose(fp); + + *key = (void *) pkey; + + return 0; + fail_key: + fclose(fp); + fail_file: + *key = NULL; + return -1; +} + +int openssl_load_privkey_str(const char * str, + void ** key) +{ + BIO * bio; + EVP_PKEY * pkey; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto fail_bio; + + if (BIO_write(bio, str, strlen(str)) < 0) + goto fail_key; + + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (pkey == NULL) + goto fail_key; + + BIO_free(bio); + + *key = (void *) pkey; + + return 0; + fail_key: + BIO_free(bio); + fail_bio: + *key = NULL; + return -1; +} + +int openssl_load_pubkey_file(const char * path, + void ** key) +{ + FILE * fp; + EVP_PKEY * pkey; + + fp = fopen(path, "r"); + if (fp == NULL) + goto fail_file; + + pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); + if (pkey == NULL) + goto fail_key; + + fclose(fp); + + *key = (void *) pkey; + + return 0; + fail_key: + fclose(fp); + fail_file: + *key = NULL; + return -1; +} + +int openssl_load_pubkey_str(const char * str, + void ** key) +{ + BIO * bio; + EVP_PKEY * pkey; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto fail_bio; + + if (BIO_write(bio, str, strlen(str)) < 0) + goto fail_key; + + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (pkey == NULL) + goto fail_key; + + BIO_free(bio); + + *key = (void *) pkey; + + return 0; + fail_key: + BIO_free(bio); + fail_bio: + *key = NULL; + return -1; +} + +int openssl_cmp_key(const void * key1, + const void * key2) +{ + EVP_PKEY * pkey1; + EVP_PKEY * pkey2; + + assert(key1 != NULL); + assert(key2 != NULL); + + pkey1 = (EVP_PKEY *) key1; + pkey2 = (EVP_PKEY *) key2; + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_PKEY_eq(pkey1, pkey2) == 1 ? 0 : -1; +#else + return EVP_PKEY_cmp(pkey1, pkey2) == 1 ? 0 : -1; +#endif +} + +void openssl_free_key(void * key) +{ + EVP_PKEY_free((EVP_PKEY *) key); +} + +int openssl_check_crt_name(void * crt, + const char * name) +{ + char * subj; + char * cn; + X509 * xcrt; + + xcrt = (X509 *) crt; + + subj = X509_NAME_oneline(X509_get_subject_name(xcrt), NULL, 0); + if (subj == NULL) + goto fail_subj; + + cn = strstr(subj, "CN="); + if (cn == NULL) + goto fail_cn; + + if (strcmp(cn + 3, name) != 0) + goto fail_cn; + + free(subj); + + return 0; + fail_cn: + free(subj); + fail_subj: + return -1; +} + +int openssl_crt_str(void * crt, + char * str) +{ + BIO * bio; + X509 * xcrt; + char * p; + + xcrt = (X509 *) crt; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto fail_bio; + + X509_print(bio, xcrt); + + BIO_get_mem_data(bio, &p); + if (p == NULL) + goto fail_p; + + sprintf(str, "%s", p); + + BIO_free(bio); + + return 0; + fail_p: + BIO_free(bio); + fail_bio: + return -1; +} + +void * openssl_auth_create_store(void) +{ + return X509_STORE_new(); +} + +void openssl_auth_destroy_store(void * ctx) +{ + X509_STORE_free((X509_STORE *) ctx); +} + +int openssl_auth_add_crt_to_store(void * store, + void * crt) +{ + int ret; + + ret = X509_STORE_add_cert((X509_STORE *) store, (X509 *) crt); + + return ret == 1 ? 0 : -1; +} + +int openssl_verify_crt(void * store, + void * crt) +{ + X509_STORE_CTX * ctx; + X509_STORE * _store; + X509* _crt; + int ret; + + _store = (X509_STORE *) store; + _crt = (X509 *) crt; + + ctx = X509_STORE_CTX_new(); + if (ctx == NULL) + goto fail_store_ctx; + + ret = X509_STORE_CTX_init(ctx, _store, _crt, NULL); + if (ret != 1) + goto fail_ca; + + ret = X509_verify_cert(ctx); + if (ret != 1) + goto fail_ca; + + X509_STORE_CTX_free(ctx); + + return 0; + fail_ca: + X509_STORE_CTX_free(ctx); + fail_store_ctx: + return -1; +} + +int openssl_sign(void * pkp, + buffer_t msg, + buffer_t * sig) +{ + EVP_PKEY * pkey; + EVP_MD_CTX * mdctx; + size_t required; + + assert(pkp != NULL); + assert(sig != NULL); + + pkey = (EVP_PKEY *) pkp; + + mdctx = EVP_MD_CTX_new(); + if (!mdctx) + goto fail_ctx; + + if (EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) + goto fail_digest; + + if (EVP_DigestSignUpdate(mdctx, msg.data, msg.len) != 1) + goto fail_digest; + + if (EVP_DigestSignFinal(mdctx, NULL, &required) != 1) + goto fail_digest; + + sig->data = malloc(required); + if (sig->data == NULL) + goto fail_digest; + + if (EVP_DigestSignFinal(mdctx, sig->data, &required) != 1) + goto fail_sign; + + sig->len = required; + + EVP_MD_CTX_free(mdctx); + + return 0; + fail_sign: + freebuf(*sig); + fail_digest: + EVP_MD_CTX_free(mdctx); + fail_ctx: + clrbuf(*sig); + return -1; +} + +int openssl_verify_sig(void * pk, + buffer_t msg, + buffer_t sig) +{ + EVP_PKEY * pkey; + EVP_MD_CTX * mdctx; + int ret; + + assert(pk != NULL); + + pkey = (EVP_PKEY *) pk; + + mdctx = EVP_MD_CTX_new(); + if (!mdctx) + goto fail_ctx; + + if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) + goto fail_digest; + + if (EVP_DigestVerifyUpdate(mdctx, msg.data, msg.len) != 1) + goto fail_digest; + + ret = EVP_DigestVerifyFinal(mdctx, sig.data, sig.len); + if (ret != 1) + goto fail_digest; + + EVP_MD_CTX_free(mdctx); + + return 0; + fail_digest: + EVP_MD_CTX_free(mdctx); + fail_ctx: + clrbuf(sig); + return -1; +} diff --git a/src/lib/crypt/openssl.h b/src/lib/crypt/openssl.h new file mode 100644 index 00000000..5d6f50dd --- /dev/null +++ b/src/lib/crypt/openssl.h @@ -0,0 +1,106 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * OpenSSL based cryptographic operations + * Elliptic curve Diffie-Hellman key exchange + * AES encryption + # Authentication + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#ifndef OUROBOROS_LIB_CRYPT_OPENSSL_H +#define OUROBOROS_LIB_CRYPT_OPENSSL_H + +ssize_t openssl_ecdh_pkp_create(void ** pkp, + uint8_t * pk); + +void openssl_ecdh_pkp_destroy(void * pkp); + +int openssl_ecdh_derive(void * pkp, + buffer_t pk, + uint8_t * s); + +int openssl_encrypt(void * ctx, + uint8_t * key, + buffer_t in, + buffer_t * out); + +int openssl_decrypt(void * ctx, + uint8_t * key, + buffer_t in, + buffer_t * out); + +void * openssl_crypt_create_ctx(void); + +void openssl_crypt_destroy_ctx(void * ctx); + +/* AUTHENTICATION */ + +int openssl_load_crt_file(const char * path, + void ** crt); + +int openssl_load_crt_str(const char * str, + void ** crt); + +int openssl_get_pubkey_crt(void * crt, + void ** pk); + +void openssl_free_crt(void * crt); + +int openssl_load_privkey_file(const char * path, + void ** key); + +int openssl_load_privkey_str(const char * str, + void ** key); + +int openssl_load_pubkey_file(const char * path, + void ** key); + +int openssl_load_pubkey_str(const char * str, + void ** key); + +int openssl_cmp_key(const void * key1, + const void * key2); + +void openssl_free_key(void * key); + +int openssl_check_crt_name(void * crt, + const char * name); + +int openssl_crt_str(void * crt, + char * str); + +void * openssl_auth_create_store(void); + +void openssl_auth_destroy_store(void * store); + +int openssl_auth_add_crt_to_store(void * store, + void * crt); + +int openssl_verify_crt(void * store, + void * crt); + +int openssl_sign(void * pkp, + buffer_t msg, + buffer_t * sig); + +int openssl_verify_sig(void * pk, + buffer_t msg, + buffer_t sig); + +#endif /* OUROBOROS_LIB_CRYPT_OPENSSL_H */ diff --git a/src/lib/dev.c b/src/lib/dev.c index 92310b9e..cb35f3f9 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -99,7 +99,7 @@ struct flow { uint16_t oflags; ssize_t part_idx; - struct crypt_info crypt; + struct crypt_ctx * crypt; struct timespec snd_act; struct timespec rcv_act; @@ -252,6 +252,69 @@ static void proc_exit(void) send_recv_msg(&msg); } +static int sdb_encrypt(struct flow * flow, + struct shm_du_buff * sdb) +{ + buffer_t in; + buffer_t out; + uint8_t * head; + uint8_t * tail; + + if (flow->crypt == NULL) + return 0; /* No encryption */ + + in.data = shm_du_buff_head(sdb); + in.len = shm_du_buff_len(sdb); + + if (crypt_encrypt(flow->crypt, in, &out) < 0) + goto fail_encrypt; + + head = shm_du_buff_head_alloc(sdb, IVSZ); + if (head == NULL) + goto fail_alloc; + + tail = shm_du_buff_tail_alloc(sdb, (out.len - in.len) - IVSZ); + if (tail == NULL) + goto fail_alloc; + + memcpy(head, out.data, out.len); + + freebuf(out); + + return 0; + fail_alloc: + freebuf(out); + fail_encrypt: + return -ECRYPT; +} + +static int sdb_decrypt(struct flow * flow, + struct shm_du_buff * sdb) +{ + buffer_t in; + buffer_t out; + uint8_t * head; + + if (flow->crypt == NULL) + return 0; /* No decryption */ + + in.data = shm_du_buff_head(sdb); + in.len = shm_du_buff_len(sdb); + + if (crypt_decrypt(flow->crypt, in, &out) < 0) + return -ENOMEM; + + + head = shm_du_buff_head_release(sdb, IVSZ) + IVSZ; + shm_du_buff_tail_release(sdb, (in.len - out.len) - IVSZ); + + memcpy(head, out.data, out.len); + + freebuf(out); + + return 0; +} + #include "frct.c" void * flow_tx(void * o) @@ -423,7 +486,7 @@ static void __flow_fini(int fd) shm_flow_set_close(ai.flows[fd].set); } - crypt_fini(&ai.flows[fd].crypt); + crypt_destroy_ctx(ai.flows[fd].crypt); list_del(&ai.flows[fd].next); @@ -477,16 +540,15 @@ static int flow_init(struct flow_info * info, flow->part_idx = NO_PART; flow->snd_act = now; flow->rcv_act = now; - - flow->crypt.flags = info->qs.cypher_s; /* TODO: move cypher_s */ - - memset(flow->crypt.key, 0, SYMMKEYSZ); - - if (flow->crypt.flags > 0 && sk!= NULL && sk->data != NULL) - memcpy(flow->crypt.key, sk->data , sk->len); - - if (crypt_init(&flow->crypt) < 0) - goto fail_crypt; + flow->crypt = NULL; + + if (sk!= NULL && sk->data != NULL) { + assert(sk->len == SYMMKEYSZ); + /* TODO: remove cypher_s from QoS */ + flow->crypt = crypt_create_ctx(info->qs.cypher_s, sk->data); + if (flow->crypt == NULL) + goto fail_crypt; + } assert(flow->frcti == NULL); @@ -519,7 +581,7 @@ static int flow_init(struct flow_info * info, fail_flow_set_add: frcti_destroy(flow->frcti); fail_frcti: - crypt_fini(&flow->crypt); + crypt_destroy_ctx(flow->crypt); fail_crypt: shm_flow_set_close(flow->set); fail_set: @@ -1200,7 +1262,7 @@ static int flow_tx_sdb(struct flow * flow, if (frcti_snd(flow->frcti, sdb) < 0) goto enomem; - if (crypt_encrypt(&flow->crypt, sdb) < 0) + if (sdb_encrypt(flow, sdb) < 0) goto enomem; if (flow->info.qs.ber == 0 && add_crc(sdb) != 0) @@ -1302,7 +1364,7 @@ static bool invalid_pkt(struct flow * flow, if (flow->info.qs.ber == 0 && chk_crc(sdb) != 0) return true; - if (crypt_decrypt(&flow->crypt, sdb) < 0) + if (sdb_decrypt(flow, sdb) < 0) return true; return false; @@ -1330,6 +1392,7 @@ static ssize_t flow_rx_sdb(struct flow * flow, pthread_rwlock_unlock(&ai.lock); *sdb = shm_rdrbuff_get(ai.rdrb, idx); + if (invalid_pkt(flow, *sdb)) { shm_rdrbuff_remove(ai.rdrb, idx); return -EAGAIN; diff --git a/src/lib/frct.c b/src/lib/frct.c index c6fef35c..d51cf006 100644 --- a/src/lib/frct.c +++ b/src/lib/frct.c @@ -261,7 +261,7 @@ static void __send_frct_pkt(int fd, f = &ai.flows[fd]; - if (crypt_encrypt(&f->crypt, sdb) < 0) + if (sdb_encrypt(f, sdb) < 0) goto fail; #ifdef RXM_BLOCKING diff --git a/src/lib/random.c b/src/lib/random.c index 09e0b844..2dc5f02f 100644 --- a/src/lib/random.c +++ b/src/lib/random.c @@ -24,22 +24,12 @@ #include <ouroboros/random.h> -#if defined(__APPLE__) /* Barf */ -#undef __OSX_AVAILABLE -#define __OSX_AVAILABLE(arg) -#undef __IOS_AVAILABLE -#define __IOS_AVAILABLE(arg) -#undef __TVOS_AVAILABLE -#define __TVOS_AVAILABLE(arg) -#undef __WATCHOS_AVAILABLE -#define __WATCHOS_AVAILABLE(arg) -#include <sys/random.h> +#if defined(__APPLE__) || defined(__FreeBSD__) +#include <stdlib.h> #elif defined(HAVE_SYS_RANDOM) #include <sys/random.h> #elif defined(HAVE_LIBGCRYPT) #include <gcrypt.h> -#elif defined(__FreeBSD__) -#include <stdlib.h> #elif defined(HAVE_OPENSSL_RNG) #include <openssl/rand.h> #include <limits.h> @@ -48,13 +38,11 @@ int random_buffer(void * buf, size_t len) { -#if defined(__APPLE__) - return getentropy(buf, len); -#elif defined(__FreeBSD__) +#if defined(__APPLE__) || defined(__FreeBSD__) arc4random_buf(buf, len); return 0; #elif defined(HAVE_SYS_RANDOM) - return getrandom(buf, len, GRND_NONBLOCK); /* glibc 2.25 */ + return getrandom(buf, len, GRND_NONBLOCK); #elif defined(HAVE_LIBGCRYPT) gcry_randomize(buf, len, GCRY_STRONG_RANDOM); return 0; diff --git a/src/lib/sockets.c b/src/lib/sockets.c index 13219db0..5dfbcb5c 100644 --- a/src/lib/sockets.c +++ b/src/lib/sockets.c @@ -154,12 +154,13 @@ int send_recv_msg(buffer_t * msg) return len < 0 ? -1 : 0; } -char * ipcp_sock_path(pid_t pid) +static char * __sock_path(pid_t pid, + const char * prefix, + const char * suffix) { char * full_name = NULL; char * pid_string = NULL; size_t len = 0; - char * delim = "_"; len = n_digits(pid); pid_string = malloc(len + 1); @@ -168,9 +169,9 @@ char * ipcp_sock_path(pid_t pid) sprintf(pid_string, "%d", pid); - len += strlen(IPCP_SOCK_PATH_PREFIX); - len += strlen(delim); - len += strlen(SOCK_PATH_SUFFIX); + len += strlen(prefix); + len += strlen(pid_string); + len += strlen(suffix); full_name = malloc(len + 1); if (full_name == NULL) { @@ -178,12 +179,17 @@ char * ipcp_sock_path(pid_t pid) return NULL; } - strcpy(full_name, IPCP_SOCK_PATH_PREFIX); - strcat(full_name, delim); + strcpy(full_name, prefix); strcat(full_name, pid_string); - strcat(full_name, SOCK_PATH_SUFFIX); + strcat(full_name, suffix); free(pid_string); return full_name; } + +char * sock_path(pid_t pid, + const char * prefix) +{ + return __sock_path(pid, prefix, SOCK_PATH_SUFFIX); +} diff --git a/src/lib/tests/CMakeLists.txt b/src/lib/tests/CMakeLists.txt index dc90671b..2791dd0d 100644 --- a/src/lib/tests/CMakeLists.txt +++ b/src/lib/tests/CMakeLists.txt @@ -3,14 +3,18 @@ get_filename_component(PARENT_DIR ${PARENT_PATH} NAME) create_test_sourcelist(${PARENT_DIR}_tests test_suite.c # Add new tests here + auth_test.c bitmap_test.c btree_test.c crc32_test.c + crypt_test.c hash_test.c md5_test.c sha3_test.c shm_rbuff_test.c + sockets_test.c time_test.c + tpm_test.c ) add_executable(${PARENT_DIR}_test EXCLUDE_FROM_ALL ${${PARENT_DIR}_tests}) @@ -30,3 +34,6 @@ foreach (test ${tests_to_run}) get_filename_component(test_name ${test} NAME_WE) add_test(${test_name} ${C_TEST_PATH}/${PARENT_DIR}_test ${test_name}) endforeach (test) + +set_property(TEST auth_test PROPERTY SKIP_RETURN_CODE 1) +set_property(TEST crypt_test PROPERTY SKIP_RETURN_CODE 1) diff --git a/src/lib/tests/auth_test.c b/src/lib/tests/auth_test.c new file mode 100644 index 00000000..5fabfbd4 --- /dev/null +++ b/src/lib/tests/auth_test.c @@ -0,0 +1,571 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the authentication functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include "config.h" + +#include <ouroboros/test.h> +#include <ouroboros/crypt.h> +#include <ouroboros/random.h> +#include <ouroboros/utils.h> + +#define TEST_MSG_SIZE 1500 + +/* +* Certificates created following the guide +* Building an openssl certificate authority +* on +* https://community.f5.com/kb/technicalarticles/ +*/ + +/* Root certificate for CA ca.unittest.o7s */ +static const char * root_ca_crt = \ +"-----BEGIN CERTIFICATE-----\n" +"MIICiTCCAi6gAwIBAgIUbTYRdvvGJpI99I3ag0Epj8PzOHwwCwYJYIZIAWUDBAMK\n" +"MIGQMQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYDVQQHDAVHaGVudDEM\n" +"MAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxGDAWBgNVBAMMD2Nh\n" +"LnVuaXR0ZXN0Lm83czEkMCIGCSqGSIb3DQEJARYVZHVtbXlAb3Vyb2Jvcm9zLnJv\n" +"Y2tzMB4XDTI1MDYyMjEzNDcwOVoXDTI1MDcyMjEzNDcwOVowgZAxCzAJBgNVBAYT\n" +"AkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50MQwwCgYDVQQKDANvN3Mx\n" +"FTATBgNVBAsMDHVuaXR0ZXN0Lm83czEYMBYGA1UEAwwPY2EudW5pdHRlc3Qubzdz\n" +"MSQwIgYJKoZIhvcNAQkBFhVkdW1teUBvdXJvYm9yb3Mucm9ja3MwWTATBgcqhkjO\n" +"PQIBBggqhkjOPQMBBwNCAATsvzzYnXYQuZVMA7ckGEb8KISyHhXCBmc/kVcRyAje\n" +"hVq+F6nuWEEJVy/zNyMdxC5Qm+hVQDwhmu1JkiGAIF1Jo2MwYTAdBgNVHQ4EFgQU\n" +"sbj19vaWoWYfY5IP901oDYN94tcwHwYDVR0jBBgwFoAUsbj19vaWoWYfY5IP901o\n" +"DYN94tcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwCwYJYIZIAWUD\n" +"BAMKA0gAMEUCIQCniTsnEYel6HscrUO7JWs+VnvyqGV5CkRIwgGCN5neQwIgCco6\n" +"aVh8ZrDsPkjclhFBXF70Qoh9T56f2LdYFvjybdc=\n" +"-----END CERTIFICATE-----\n"; + +/* Certificate for intermediary im.unittest.o7s used for signing */ +static const char * intermediate_ca_crt = \ +"-----BEGIN CERTIFICATE-----\n" +"MIICgzCCAimgAwIBAgICEAAwCwYJYIZIAWUDBAMKMIGQMQswCQYDVQQGEwJCRTEM\n" +"MAoGA1UECAwDT1ZMMQ4wDAYDVQQHDAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYD\n" +"VQQLDAx1bml0dGVzdC5vN3MxGDAWBgNVBAMMD2NhLnVuaXR0ZXN0Lm83czEkMCIG\n" +"CSqGSIb3DQEJARYVZHVtbXlAb3Vyb2Jvcm9zLnJvY2tzMB4XDTI1MDYyMjE0MTU0\n" +"M1oXDTM1MDYyMDE0MTU0M1owWjELMAkGA1UEBhMCQkUxDDAKBgNVBAgMA09WTDEM\n" +"MAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxGDAWBgNVBAMMD2lt\n" +"LnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABC1/rn6yG22c\n" +"38lxYGym4VcEZ6+lET5AfcaBsRKpvQj4NwfPG5BCoWwl/rwqKEGmcuwzubiGS1K9\n" +"hZaxZWp6WfejgaYwgaMwHQYDVR0OBBYEFBfSiMt8k7TKMp2lVsdlunBLGJQhMB8G\n" +"A1UdIwQYMBaAFLG49fb2lqFmH2OSD/dNaA2DfeLXMBIGA1UdEwEB/wQIMAYBAf8C\n" +"AQAwDgYDVR0PAQH/BAQDAgGGMBEGA1UdHwQKMAgwBqAEoAKGADAqBggrBgEFBQcB\n" +"AQQeMBwwDAYIKwYBBQUHMAKGADAMBggrBgEFBQcwAYYAMAsGCWCGSAFlAwQDCgNH\n" +"ADBEAiBjgMvCgnPz+xy4I1Msb6EwfwdIHr4eHqEfsGQjWf9M8gIgJyy6Bkg6Nkb4\n" +"uLdf/8CFP5yKKP1H26F8gx1VrGtr+PM=\n" +"-----END CERTIFICATE-----\n"; + +/* Server server-1.unittest.o7s private-public key pair */ +static const char * server_ec_pkp = \ +"-----BEGIN EC PRIVATE KEY-----\n" +"MHcCAQEEIOLEoARQqt9oQkZhdqYrrDltVtcX7TIOYTQqE+GWCIwEoAoGCCqGSM49\n" +"AwEHoUQDQgAEzHlm1xTYnWncOymJ29ubJ3cHShG67JE+floT7L8ipqRNW4/FUwPN\n" +"zR/49iM0+A3Nq0ImjzkA6B7E3LvlrwokYQ==\n" +"-----END EC PRIVATE KEY-----\n"; + +/* Public key for the Private key */ +static const char * server_ec_pk = \ +"-----BEGIN PUBLIC KEY-----\n" +"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzHlm1xTYnWncOymJ29ubJ3cHShG6\n" +"7JE+floT7L8ipqRNW4/FUwPNzR/49iM0+A3Nq0ImjzkA6B7E3LvlrwokYQ==\n" +"-----END PUBLIC KEY-----\n"; + +/* Valid signed server certificate for server-1.unittest.o7s */ +static const char * signed_server_crt = \ +"-----BEGIN CERTIFICATE-----\n" +"MIIDgzCCAyegAwIBAgICEAAwCwYJYIZIAWUDBAMKMFoxCzAJBgNVBAYTAkJFMQww\n" +"CgYDVQQIDANPVkwxDDAKBgNVBAoMA283czEVMBMGA1UECwwMdW5pdHRlc3Qubzdz\n" +"MRgwFgYDVQQDDA9pbS51bml0dGVzdC5vN3MwHhcNMjUwNjIyMTQzODMxWhcNMjcw\n" +"NjIyMTQzODMxWjBwMQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYDVQQH\n" +"DAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxHjAc\n" +"BgNVBAMMFXNlcnZlci0xLnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49\n" +"AwEHA0IABMx5ZtcU2J1p3Dspidvbmyd3B0oRuuyRPn5aE+y/IqakTVuPxVMDzc0f\n" +"+PYjNPgNzatCJo85AOgexNy75a8KJGGjggHEMIIBwDAJBgNVHRMEAjAAMBEGCWCG\n" +"SAGG+EIBAQQEAwIGQDA6BglghkgBhvhCAQ0ELRYrR3JpbGxlZCBDaGVlc2UgR2Vu\n" +"ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUIKmznLlTbfKaP78E\n" +"uSNauQ/4Mcwwgb4GA1UdIwSBtjCBs4AUF9KIy3yTtMoynaVWx2W6cEsYlCGhgZak\n" +"gZMwgZAxCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50\n" +"MQwwCgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEYMBYGA1UEAwwP\n" +"Y2EudW5pdHRlc3QubzdzMSQwIgYJKoZIhvcNAQkBFhVkdW1teUBvdXJvYm9yb3Mu\n" +"cm9ja3OCAhAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAR\n" +"BgNVHR8ECjAIMAagBKAChgAwKgYIKwYBBQUHAQEEHjAcMAwGCCsGAQUFBzAChgAw\n" +"DAYIKwYBBQUHMAGGADAgBgNVHREEGTAXghVzZXJ2ZXItMS51bml0dGVzdC5vN3Mw\n" +"CwYJYIZIAWUDBAMKA0kAMEYCIQDVoRxvr9j4mbX/CpxsQr5HhjxLnjYzI2SVM+0l\n" +"z2dxVgIhALwq2q6d8WDHPq59trrlNlnYO+kDqDLS3smnS6LOQYiq\n" +"-----END CERTIFICATE-----\n"; + +/* Self-signed by server server-1.unittest.o7s using its key */ +static const char * server_crt = \ +"-----BEGIN CERTIFICATE-----\n" +"MIICNzCCAdygAwIBAgIUaKYySFvp8nmd7LcJjdCyyHrgv0owCwYJYIZIAWUDBAMK\n" +"MHAxCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50MQww\n" +"CgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEeMBwGA1UEAwwVc2Vy\n" +"dmVyLTEudW5pdHRlc3QubzdzMB4XDTI1MDYyMjE0NTU1MFoXDTM1MDYyMDE0NTU1\n" +"MFowcDELMAkGA1UEBhMCQkUxDDAKBgNVBAgMA09WTDEOMAwGA1UEBwwFR2hlbnQx\n" +"DDAKBgNVBAoMA283czEVMBMGA1UECwwMdW5pdHRlc3QubzdzMR4wHAYDVQQDDBVz\n" +"ZXJ2ZXItMS51bml0dGVzdC5vN3MwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATM\n" +"eWbXFNidadw7KYnb25sndwdKEbrskT5+WhPsvyKmpE1bj8VTA83NH/j2IzT4Dc2r\n" +"QiaPOQDoHsTcu+WvCiRho1MwUTAdBgNVHQ4EFgQUIKmznLlTbfKaP78EuSNauQ/4\n" +"McwwHwYDVR0jBBgwFoAUIKmznLlTbfKaP78EuSNauQ/4McwwDwYDVR0TAQH/BAUw\n" +"AwEB/zALBglghkgBZQMEAwoDSAAwRQIhAMrhCV+4QY4Pzcn11qY8AW24xSYE77jN\n" +"oWkJQKoLEhSdAiBCFzCBItjChcDavsuy++HDo3e6VdpmAh0PlTlQTR6Wog==\n" +"-----END CERTIFICATE-----\n"; + +static int test_auth_create_destroy_ctx(void) +{ + struct auth_ctx * ctx; + + TEST_START(); + + ctx = auth_create_ctx(); + if (ctx == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create; + } + + auth_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_create: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_crt(void) +{ + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(root_ca_crt, &crt) < 0) { + printf("Failed to load certificate string.\n"); + goto fail_load; + } + + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_get_pubkey_crt(void) +{ + void * pk; + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt, &crt) < 0) { + printf("Failed to load server certificate from string.\n"); + goto fail_load; + } + + if (crypt_get_pubkey_crt(crt, &pk) < 0) { + printf("Failed to get public key from certificate.\n"); + goto fail_get_pubkey; + } + + crypt_free_key(pk); + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + + fail_get_pubkey: + crypt_free_crt(crt); + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_check_crt_name(void) +{ + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt, &crt) < 0) { + printf("Failed to load certificate from string.\n"); + goto fail_load; + } + + if (crypt_check_crt_name(crt, "server-1.unittest.o7s") < 0) { + printf("Failed to verify correct name.\n"); + goto fail_check; + } + + if (crypt_check_crt_name(crt, "bogus.name") == 0) { + printf("Failed to detect incorrect name.\n"); + goto fail_check; + } + + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_check: + crypt_free_crt(crt); + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_privkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_privkey_str(server_ec_pkp, &key) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_load; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_load_free_pubkey(void) +{ + void * key; + + TEST_START(); + + if (crypt_load_pubkey_str(server_ec_pk, &key) < 0) { + printf("Failed to load server public key from string.\n"); + goto fail_load; + } + + crypt_free_key(key); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_load: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_check_pubkey_crt(void) +{ + void * pk; + void * crt_pk; + void * crt; + + TEST_START(); + + if (crypt_load_crt_str(signed_server_crt, &crt) < 0) { + printf("Failed to load public certificate from string.\n"); + goto fail_crt; + } + + if (crypt_load_pubkey_str(server_ec_pk, &pk) < 0) { + printf("Failed to load public key from string.\n"); + goto fail_pubkey; + } + + if (crypt_get_pubkey_crt(crt, &crt_pk) < 0) { + printf("Failed to get public key from certificate.\n"); + goto fail_get_pubkey; + } + + if (crypt_cmp_key(pk, crt_pk) != 0) { + printf("Public keys do not match .\n"); + goto fail_check; + } + + + crypt_free_key(crt_pk); + crypt_free_key(pk); + crypt_free_crt(crt); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_check: + crypt_free_key(crt_pk); + fail_get_pubkey: + crypt_free_key(pk); + fail_pubkey: + crypt_free_crt(crt); + fail_crt: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_verify_crt(void) +{ + struct auth_ctx * auth; + void * _server_crt; + void * _signed_server_crt; + void * _root_ca_crt; + void * _intermediate_ca_crt; + + TEST_START(); + + + auth = auth_create_ctx(); + if (auth == NULL) { + printf("Failed to create auth context.\n"); + goto fail_create_ctx; + } + + if (crypt_load_crt_str(server_crt, &_server_crt) < 0) { + printf("Failed to load self-signed crt from string.\n"); + goto fail_load_server_crt; + } + + if (crypt_load_crt_str(signed_server_crt, &_signed_server_crt) < 0) { + printf("Failed to load signed crt from string.\n"); + goto fail_load_signed_server_crt; + } + + if (crypt_load_crt_str(root_ca_crt, &_root_ca_crt) < 0) { + printf("Failed to load root crt from string.\n"); + goto fail_load_root_ca_crt; + } + + if (crypt_load_crt_str(intermediate_ca_crt, &_intermediate_ca_crt) < 0) { + printf("Failed to load intermediate crt from string.\n"); + goto fail_load_intermediate_ca_crt; + } + + if (auth_add_crt_to_store(auth, _root_ca_crt) < 0) { + printf("Failed to add root ca crt to auth store.\n"); + goto fail_verify; + } + + if (auth_add_crt_to_store(auth, _intermediate_ca_crt) < 0) { + printf("Failed to add intermediate ca crt to auth store.\n"); + goto fail_verify; + } + + if (auth_verify_crt(auth, _signed_server_crt) < 0) { + printf("Failed to verify signed crt with ca crt.\n"); + goto fail_verify; + } + + if (auth_verify_crt(auth, _server_crt) == 0) { + printf("Failed to detect untrusted crt.\n"); + goto fail_verify; + } + + crypt_free_crt(_intermediate_ca_crt); + crypt_free_crt(_root_ca_crt); + crypt_free_crt(_signed_server_crt); + crypt_free_crt(_server_crt); + + auth_destroy_ctx(auth); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + crypt_free_crt(_intermediate_ca_crt); + fail_load_intermediate_ca_crt: + crypt_free_crt(_root_ca_crt); + fail_load_root_ca_crt: + crypt_free_crt(_signed_server_crt); + fail_load_signed_server_crt: + crypt_free_crt(_server_crt); + fail_load_server_crt: + auth_destroy_ctx(auth); + fail_create_ctx: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int test_auth_sign(void) +{ + uint8_t buf[TEST_MSG_SIZE]; + void * pkp; + void * pk; + buffer_t msg; + buffer_t sig; + + TEST_START(); + + msg.data = buf; + msg.len = sizeof(buf); + + if (random_buffer(msg.data, msg.len) < 0) { + printf("Failed to generate random message.\n"); + goto fail_init; + } + + if (crypt_load_privkey_str(server_ec_pkp, &pkp) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_init; + } + + if (crypt_load_pubkey_str(server_ec_pk, &pk) < 0) { + printf("Failed to load public key.\n"); + goto fail_pubkey; + } + + if (auth_sign(pkp, msg, &sig) < 0) { + printf("Failed to sign message.\n"); + goto fail_sign; + } + + if (auth_verify_sig(pk, msg, sig) < 0) { + printf("Failed to verify signature.\n"); + goto fail_verify; + } + + freebuf(sig); + + crypt_free_key(pk); + crypt_free_key(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + freebuf(sig); + fail_sign: + crypt_free_key(pk); + fail_pubkey: + crypt_free_key(pkp); + fail_init: + return TEST_RC_FAIL; +} + +int test_auth_bad_signature(void) +{ + uint8_t buf[TEST_MSG_SIZE]; + void * pkp; + void * pk; + buffer_t msg; + buffer_t sig; + buffer_t fake_sig; + + TEST_START(); + + msg.data = buf; + msg.len = sizeof(buf); + + if (random_buffer(msg.data, msg.len) < 0) { + printf("Failed to generate random message.\n"); + goto fail_init; + } + + if (crypt_load_privkey_str(server_ec_pkp, &pkp) < 0) { + printf("Failed to load server key pair from string.\n"); + goto fail_init; + } + + if (crypt_load_pubkey_str(server_ec_pk, &pk) < 0) { + printf("Failed to load public key.\n"); + goto fail_pubkey; + } + + if (auth_sign(pkp, msg, &sig) < 0) { + printf("Failed to sign message.\n"); + goto fail_sign; + } + + fake_sig.data = malloc(sig.len); + if (fake_sig.data == NULL) { + printf("Failed to allocate memory for fake signature.\n"); + goto fail_malloc; + } + + fake_sig.len = sig.len; + if (random_buffer(fake_sig.data, fake_sig.len) < 0) { + printf("Failed to generate random fake signature.\n"); + goto fail_malloc; + } + + if (auth_verify_sig(pk, msg, fake_sig) == 0) { + printf("Failed to detect bad signature.\n"); + goto fail_verify; + } + + freebuf(sig); + + crypt_free_key(pk); + crypt_free_key(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_verify: + freebuf(fake_sig); + fail_malloc: + freebuf(sig); + fail_sign: + crypt_free_key(pk); + fail_pubkey: + crypt_free_key(pkp); + fail_init: + return TEST_RC_FAIL; +} + +int auth_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_auth_create_destroy_ctx(); +#ifdef HAVE_OPENSSL + ret |= test_load_free_crt(); + ret |= test_check_crt_name(); + ret |= test_crypt_get_pubkey_crt(); + ret |= test_load_free_privkey(); + ret |= test_load_free_pubkey(); + ret |= test_crypt_check_pubkey_crt(); + ret |= test_verify_crt(); + ret |= test_auth_sign(); + ret |= test_auth_bad_signature(); +#else + (void) test_load_free_crt; + (void) test_check_crt_name; + (void) test_crypt_get_pubkey_crt; + (void) test_load_free_privkey; + (void) test_load_free_pubkey; + (void) test_crypt_check_pubkey_crt; + (void) test_verify_crt; + (void) test_auth_sign; + (void) test_auth_bad_signature; + + ret = TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/crypt_test.c b/src/lib/tests/crypt_test.c new file mode 100644 index 00000000..7f011e5c --- /dev/null +++ b/src/lib/tests/crypt_test.c @@ -0,0 +1,256 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Test of the cryptography functions + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#include "config.h" + +#include <ouroboros/test.h> +#include <ouroboros/crypt.h> +#include <ouroboros/random.h> +#include <ouroboros/utils.h> + +#define TEST_PACKET_SIZE 1500 + +static int test_crypt_create_destroy(void) +{ + struct crypt_ctx * ctx; + + TEST_START(); + + ctx = crypt_create_ctx(0, NULL); + if (ctx == NULL) { + printf("Failed to initialize cryptography.\n"); + goto fail; + } + + crypt_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_create_destroy_with_key(void) +{ + struct crypt_ctx * ctx; + uint8_t key[SYMMKEYSZ]; + + TEST_START(); + + memset(key, 0, sizeof(key)); + + ctx = crypt_create_ctx(1, key); + if (ctx == NULL) { + printf("Failed to initialize cryptography.\n"); + goto fail; + } + + crypt_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_dh_pkp_create_destroy(void) +{ + void * pkp; + uint8_t buf[MSGBUFSZ]; + + TEST_START(); + + if (crypt_dh_pkp_create(&pkp, buf) < 0) { + printf("Failed to create DH PKP."); + goto fail; + } + + crypt_dh_pkp_destroy(pkp); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_crypt_dh_derive(void) +{ + void * pkp1; + void * pkp2; + buffer_t pk1; + buffer_t pk2; + ssize_t len; + uint8_t buf1[MSGBUFSZ]; + uint8_t buf2[MSGBUFSZ]; + uint8_t s1[SYMMKEYSZ]; + uint8_t s2[SYMMKEYSZ]; + + TEST_START(); + + len = crypt_dh_pkp_create(&pkp1, buf1); + if (len < 0) { + printf("Failed to create first key pair."); + goto fail_pkp1; + } + + pk1.len = (size_t) len; + pk1.data = buf1; + + len = crypt_dh_pkp_create(&pkp2, buf2); + if (len < 0) { + printf("Failed to create second key pair."); + goto fail_pkp2; + } + + pk2.len = (size_t) len; + pk2.data = buf2; + + if (crypt_dh_derive(pkp1, pk2, s1) < 0) { + printf("Failed to derive first key."); + goto fail; + } + + if (crypt_dh_derive(pkp2, pk1, s2) < 0) { + printf("Failed to derive second key."); + goto fail; + } + + if (memcmp(s1, s2, SYMMKEYSZ) != 0) { + printf("Derived keys do not match."); + goto fail; + } + + crypt_dh_pkp_destroy(pkp2); + crypt_dh_pkp_destroy(pkp1); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + crypt_dh_pkp_destroy(pkp2); + fail_pkp2: + crypt_dh_pkp_destroy(pkp1); + fail_pkp1: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int test_crypt_encrypt_decrypt(void) +{ + uint8_t pkt[TEST_PACKET_SIZE]; + uint8_t key[SYMMKEYSZ]; + struct crypt_ctx * ctx; + buffer_t in; + buffer_t out; + buffer_t out2; + + TEST_START(); + + if (random_buffer(key, sizeof(key)) < 0) { + printf("Failed to generate random key.\n"); + goto fail_init; + } + + if (random_buffer(pkt, sizeof(pkt)) < 0) { + printf("Failed to generate random data.\n"); + goto fail_init; + } + + ctx = crypt_create_ctx(1, key); + if (ctx == NULL) { + printf("Failed to initialize cryptography.\n"); + goto fail_init; + } + + in.len = sizeof(pkt); + in.data = pkt; + + if (crypt_encrypt(ctx, in, &out) < 0) { + printf("Encryption failed.\n"); + goto fail_encrypt; + } + + if (out.len < in.len) { + printf("Encryption returned too little data.\n"); + goto fail_encrypt; + } + + if (crypt_decrypt(ctx, out, &out2) < 0) { + printf("Decryption failed.\n"); + goto fail_decrypt; + } + + if (out2.len != in.len) { + printf("Decrypted data length does not match original.\n"); + goto fail_chk; + } + + if (memcmp(in.data, out2.data, in.len) != 0) { + printf("Decrypted data does not match original.\n"); + goto fail_chk; + } + + crypt_destroy_ctx(ctx); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_chk: + freebuf(out2); + fail_decrypt: + freebuf(out); + fail_encrypt: + crypt_destroy_ctx(ctx); + fail_init: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int crypt_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_crypt_create_destroy(); + ret |= test_crypt_create_destroy_with_key(); +#ifdef HAVE_OPENSSL + ret |= test_crypt_dh_pkp_create_destroy(); + ret |= test_crypt_dh_derive(); + ret |= test_crypt_encrypt_decrypt(); +#else + (void) test_crypt_dh_pkp_create_destroy; + (void) test_crypt_dh_derive; + (void) test_crypt_encrypt_decrypt; + + ret = TEST_RC_SKIP; +#endif + return ret; +} diff --git a/src/lib/tests/sockets_test.c b/src/lib/tests/sockets_test.c new file mode 100644 index 00000000..bbf2323b --- /dev/null +++ b/src/lib/tests/sockets_test.c @@ -0,0 +1,98 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Tests for socket.c + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _POSIX_C_SOURCE 200112L + +#include <ouroboros/sockets.h> +#include <ouroboros/test.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#define TEST_PID 1234 +#define TEST_PID_STR "1234" +#define TEST_SERVER_PATH "/tmp/test.sock" +#define TEST_SERVER_PREFIX "/tmp/ouroboros/test." +#define TEST_SOCK_PATH_PREFIX "var/run/ouroboros/test." + +static int test_sock_path(void) +{ + char * path; + char * exp = TEST_SOCK_PATH_PREFIX TEST_PID_STR SOCK_PATH_SUFFIX; + + TEST_START(); + + path = sock_path(TEST_PID, TEST_SOCK_PATH_PREFIX); + if (path == NULL) { + printf("Path is NULL.\n"); + goto fail_path; + } + + if (strcmp(path, exp) != 0) { + printf("Expected path '%s', got '%s'.\n", exp, path); + goto fail_cmp; + } + + free(path); + + TEST_SUCCESS(); + return TEST_RC_SUCCESS; + fail_cmp: + free(path); + fail_path: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_server_socket_open(void) +{ + int sockfd; + + TEST_START(); + + sockfd = server_socket_open(TEST_SERVER_PATH); + if (sockfd < 0) { + printf("Failed to open server socket.\n"); + goto fail_sock; + } + + close(sockfd); + + unlink(TEST_SERVER_PATH); + + TEST_SUCCESS(); + return TEST_RC_SUCCESS; + fail_sock: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int sockets_test(void) +{ + int ret = 0; + + ret |= test_sock_path(); + ret |= test_server_socket_open(); + + return ret; +} diff --git a/src/lib/tests/time_test.c b/src/lib/tests/time_test.c index 65f896bb..77fecdac 100644 --- a/src/lib/tests/time_test.c +++ b/src/lib/tests/time_test.c @@ -28,12 +28,14 @@ static void ts_print(struct timespec * s) { - printf("timespec is %zd:%ld.\n", (ssize_t) s->tv_sec, s->tv_nsec); + printf("timespec is %zd:%ld.\n", + (ssize_t) s->tv_sec, s->tv_nsec); } static void tv_print(struct timeval * v) { - printf("timeval is %zd:%zu.\n", (ssize_t) v->tv_sec, (size_t) v->tv_usec); + printf("timeval is %zd:%zu.\n", + (ssize_t) v->tv_sec, (size_t) v->tv_usec); } static void ts_init(struct timespec * s, diff --git a/src/lib/tests/tpm_test.c b/src/lib/tests/tpm_test.c new file mode 100644 index 00000000..98d4fab3 --- /dev/null +++ b/src/lib/tests/tpm_test.c @@ -0,0 +1,104 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * Tests for the threadpool manager + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + + +#include "tpm.c" + +#include <ouroboros/test.h> + +static void * test_func(void * o) +{ + (void) o; + + while(1) + sleep(1); + + return NULL; +} + +static int test_tpm_create_destroy(void) +{ + struct tpm *tpm; + + TEST_START(); + + tpm = tpm_create(2, 2, &test_func, NULL); + if (tpm == NULL) { + printf("Failed to initialize TPM.\n"); + goto fail; + } + + tpm_destroy(tpm); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +static int test_tpm_start_stop(void * (* fn)(void *), + void * o) +{ + struct tpm *tpm; + + TEST_START(); + + tpm = tpm_create(2, 2, fn, o); + if (tpm == NULL) { + printf("Failed to initialize TPM.\n"); + goto fail_create; + } + + if (tpm_start(tpm) < 0) { + printf("Failed to start TPM.\n"); + goto fail_start; + } + + tpm_stop(tpm); + + tpm_destroy(tpm); + + TEST_SUCCESS(); + + return TEST_RC_SUCCESS; + fail_start: + tpm_destroy(tpm); + fail_create: + TEST_FAIL(); + return TEST_RC_FAIL; +} + +int tpm_test(int argc, + char ** argv) +{ + int ret = 0; + + (void) argc; + (void) argv; + + ret |= test_tpm_create_destroy(); + ret |= test_tpm_start_stop(&test_func, NULL); + + return ret; +} diff --git a/src/lib/tpm.c b/src/lib/tpm.c index 0ef1fda8..64777815 100644 --- a/src/lib/tpm.c +++ b/src/lib/tpm.c @@ -63,7 +63,7 @@ struct tpm { enum tpm_state state; pthread_cond_t cond; - pthread_mutex_t lock; + pthread_mutex_t mtx; pthread_t mgr; }; @@ -90,11 +90,11 @@ static void tpm_join(struct tpm * tpm) pthread_t thr = e->thr; list_del(&e->next); free(e); - pthread_mutex_unlock(&tpm->lock); + pthread_mutex_unlock(&tpm->mtx); pthread_join(thr, NULL); - pthread_mutex_lock(&tpm->lock); + pthread_mutex_lock(&tpm->mtx); } } } @@ -114,56 +114,59 @@ static void tpm_kill(struct tpm * tpm) } } -static void * tpmgr(void * o) +static int __tpm(struct tpm * tpm) { struct timespec dl; struct timespec to = TIMESPEC_INIT_MS(TPM_TIMEOUT); - struct tpm * tpm = (struct tpm *) o; - - while (true) { - clock_gettime(PTHREAD_COND_CLOCK, &dl); - ts_add(&dl, &to, &dl); - pthread_mutex_lock(&tpm->lock); + clock_gettime(PTHREAD_COND_CLOCK, &dl); + ts_add(&dl, &to, &dl); - if (tpm->state != TPM_RUNNING) { - tpm_join(tpm); - pthread_mutex_unlock(&tpm->lock); - break; - } + pthread_mutex_lock(&tpm->mtx); + if (tpm->state != TPM_RUNNING) { tpm_join(tpm); + pthread_mutex_unlock(&tpm->mtx); + return -1; + } - if (tpm->cur - tpm->wrk < tpm->min) { - size_t i; - for (i = 0; i < tpm->inc; ++i) { - struct pthr_el * e = malloc(sizeof(*e)); - if (e == NULL) - break; + tpm_join(tpm); - e->kill = false; - e->busy = false; + if (tpm->cur - tpm->wrk < tpm->min) { + size_t i; + for (i = 0; i < tpm->inc; ++i) { + struct pthr_el * e = malloc(sizeof(*e)); + if (e == NULL) + break; - if (pthread_create(&e->thr, NULL, - tpm->func, tpm->o)) { - free(e); - break; - } + e->kill = false; + e->busy = false; - list_add(&e->next, &tpm->pool); + if (pthread_create(&e->thr, NULL, + tpm->func, tpm->o)) { + free(e); + break; } - tpm->cur += i; + list_add(&e->next, &tpm->pool); } - if (pthread_cond_timedwait(&tpm->cond, &tpm->lock, &dl) - == ETIMEDOUT) - if (tpm->cur - tpm->wrk > tpm->min) - tpm_kill(tpm); - - pthread_mutex_unlock(&tpm->lock); + tpm->cur += i; } + if (pthread_cond_timedwait(&tpm->cond, &tpm->mtx, &dl) == ETIMEDOUT) + if (tpm->cur - tpm->wrk > tpm->min) + tpm_kill(tpm); + + pthread_mutex_unlock(&tpm->mtx); + + return 0; +} + +static void * tpmgr(void * o) +{ + while (__tpm((struct tpm *) o) == 0); + return (void *) 0; } @@ -175,11 +178,14 @@ struct tpm * tpm_create(size_t min, struct tpm * tpm; pthread_condattr_t cattr; + assert(func != NULL); + assert(inc > 0); + tpm = malloc(sizeof(*tpm)); if (tpm == NULL) goto fail_malloc; - if (pthread_mutex_init(&tpm->lock, NULL)) + if (pthread_mutex_init(&tpm->mtx, NULL)) goto fail_lock; if (pthread_condattr_init(&cattr)) @@ -208,7 +214,7 @@ struct tpm * tpm_create(size_t min, fail_cond: pthread_condattr_destroy(&cattr); fail_cattr: - pthread_mutex_destroy(&tpm->lock); + pthread_mutex_destroy(&tpm->mtx); fail_lock: free(tpm); fail_malloc: @@ -217,34 +223,39 @@ struct tpm * tpm_create(size_t min, int tpm_start(struct tpm * tpm) { - pthread_mutex_lock(&tpm->lock); + pthread_mutex_lock(&tpm->mtx); if (pthread_create(&tpm->mgr, NULL, tpmgr, tpm)) { - pthread_mutex_unlock(&tpm->lock); + pthread_mutex_unlock(&tpm->mtx); return -1; } tpm->state = TPM_RUNNING; - pthread_mutex_unlock(&tpm->lock); + pthread_mutex_unlock(&tpm->mtx); return 0; } void tpm_stop(struct tpm * tpm) { - pthread_mutex_lock(&tpm->lock); + pthread_mutex_lock(&tpm->mtx); + + if (tpm->state != TPM_RUNNING) { + pthread_mutex_unlock(&tpm->mtx); + return; + } tpm->state = TPM_NULL; - pthread_mutex_unlock(&tpm->lock); + pthread_mutex_unlock(&tpm->mtx); pthread_join(tpm->mgr, NULL); } void tpm_destroy(struct tpm * tpm) { - pthread_mutex_destroy(&tpm->lock); + pthread_mutex_destroy(&tpm->mtx); pthread_cond_destroy(&tpm->cond); free(tpm); @@ -260,40 +271,39 @@ static struct pthr_el * tpm_pthr_el(struct tpm * tpm, e = list_entry(p, struct pthr_el, next); if (e->thr == thr) return e; - } return NULL; } -void tpm_inc(struct tpm * tpm) +void tpm_begin_work(struct tpm * tpm) { struct pthr_el * e; - pthread_mutex_lock(&tpm->lock); + pthread_mutex_lock(&tpm->mtx); e = tpm_pthr_el(tpm, pthread_self()); if (e != NULL) { - e->busy = false; - --tpm->wrk; + e->busy = true; + ++tpm->wrk; } - pthread_mutex_unlock(&tpm->lock); + pthread_cond_signal(&tpm->cond); + + pthread_mutex_unlock(&tpm->mtx); } -void tpm_dec(struct tpm * tpm) +void tpm_end_work(struct tpm * tpm) { struct pthr_el * e; - pthread_mutex_lock(&tpm->lock); + pthread_mutex_lock(&tpm->mtx); e = tpm_pthr_el(tpm, pthread_self()); if (e != NULL) { - e->busy = true; - ++tpm->wrk; + e->busy = false; + --tpm->wrk; } - pthread_cond_signal(&tpm->cond); - - pthread_mutex_unlock(&tpm->lock); + pthread_mutex_unlock(&tpm->mtx); } diff --git a/src/tools/oping/oping_server.c b/src/tools/oping/oping_server.c index 6f76869c..11e10a77 100644 --- a/src/tools/oping/oping_server.c +++ b/src/tools/oping/oping_server.c @@ -36,6 +36,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ + #include <ouroboros/hash.h> + void shutdown_server(int signo, siginfo_t * info, void * c) { (void) info; @@ -100,14 +102,15 @@ void * server_thread(void *o) if (msg_len < 0) continue; + if (!server.quiet) + printf("Received %d bytes on fd %d.\n", + msg_len, fd); + if (ntohl(msg->type) != ECHO_REQUEST) { printf("Invalid message on fd %d.\n", fd); continue; } - if (!server.quiet) - printf("Received %d bytes on fd %d.\n", msg_len, fd); - clock_gettime(CLOCK_REALTIME, &now); pthread_mutex_lock(&server.lock); |