X-Git-Url: http://wagner.pp.ru/gitweb/?a=blobdiff_plain;f=test_tls.c;h=1e805c3e67118d57a18a1f381f9c0ccbd14794a6;hb=9d390a3369bfc121d7fe83f49c12828f0413af67;hp=6a9c02de20c5d6529b54c5ba6ddc84bbb0334896;hpb=419263293a3075c630d028b94378107714ab6fa6;p=openssl-gost%2Fengine.git diff --git a/test_tls.c b/test_tls.c index 6a9c02d..1e805c3 100644 --- a/test_tls.c +++ b/test_tls.c @@ -8,6 +8,11 @@ * See https://www.openssl.org/source/license.html for details */ +#ifdef _MSC_VER +# pragma warning(push, 3) +# include +# pragma warning(pop) +#endif #include "e_gost_err.h" #include "gost_lcl.h" #include @@ -25,24 +30,27 @@ #include #include #include +#include #include +#include #include -#include +#ifdef __GNUC__ /* For X509_NAME_add_entry_by_txt */ -#pragma GCC diagnostic ignored "-Wpointer-sign" - -#define T(e) ({ if (!(e)) { \ - ERR_print_errors_fp(stderr); \ - OpenSSLDie(__FILE__, __LINE__, #e); \ - } \ - }) -#define TE(e) ({ if (!(e)) { \ - ERR_print_errors_fp(stderr); \ - fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \ - return -1; \ - } \ - }) +# pragma GCC diagnostic ignored "-Wpointer-sign" +#endif + +#define T(e) \ + if (!(e)) { \ + ERR_print_errors_fp(stderr); \ + OpenSSLDie(__FILE__, __LINE__, #e); \ + } +#define TE(e) \ + if (!(e)) { \ + ERR_print_errors_fp(stderr); \ + fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \ + return -1; \ + } #define cRED "\033[1;31m" #define cDRED "\033[0;31m" @@ -61,14 +69,28 @@ struct certkey { X509 *cert; }; +static int verbose; +static const char *cipher_list; + /* How much K to transfer between client and server. */ #define KTRANSFER (1 * 1024) +static void err(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf(": %s\n", strerror(errno)); + exit(eval); +} + /* * Simple TLS Server code is based on * https://wiki.openssl.org/index.php/Simple_TLS_Server */ -static int s_server(EVP_PKEY *pkey, X509 *cert, int pipewr) +static int s_server(EVP_PKEY *pkey, X509 *cert, int client) { SSL_CTX *ctx; T(ctx = SSL_CTX_new(TLS_server_method())); @@ -76,34 +98,11 @@ static int s_server(EVP_PKEY *pkey, X509 *cert, int pipewr) T(SSL_CTX_use_PrivateKey(ctx, pkey)); T(SSL_CTX_check_private_key(ctx)); - struct sockaddr_in addr = { .sin_family = AF_INET }; - socklen_t len; - int sock; - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) - err(1, "socket"); - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) - err(1, "setsockopt"); - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) - err(1, "bind"); - len = sizeof(addr); - if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) - err(1, "getsockname"); - int port = ntohs(addr.sin_port); - if (listen(sock, 1) < 0) - err(1, "listen"); - /* Signal to client that server is ready. */ - if (write(pipewr, &port, sizeof(port)) != sizeof(port)) - err(1, "write pipe"); - len = sizeof(addr); - alarm(1); - int client = accept(sock, (struct sockaddr *)&addr, &len); - if (client < 0) - err(1, "accept"); - alarm(0); SSL *ssl; - ssl = SSL_new(ctx); - SSL_set_fd(ssl, client); + T(ssl = SSL_new(ctx)); + T(SSL_set_fd(ssl, client)); + if (cipher_list) + T(SSL_set_cipher_list(ssl, cipher_list)); T(SSL_accept(ssl) == 1); /* Receive data from client */ @@ -126,7 +125,6 @@ static int s_server(EVP_PKEY *pkey, X509 *cert, int pipewr) SSL_free(ssl); close(client); - close(sock); SSL_CTX_free(ctx); return 0; } @@ -135,7 +133,7 @@ static int s_server(EVP_PKEY *pkey, X509 *cert, int pipewr) * Simple TLC Client code is based on man BIO_f_ssl and * https://wiki.openssl.org/index.php/SSL/TLS_Client */ -static int s_client(int piperd) +static int s_client(int server) { SSL_CTX *ctx; T(ctx = SSL_CTX_new(TLS_client_method())); @@ -145,28 +143,21 @@ static int s_client(int piperd) SSL *ssl; T(BIO_get_ssl(sbio, &ssl)); T(SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY)); + if (cipher_list) + T(SSL_set_cipher_list(ssl, cipher_list)); #if 0 /* Does not work with reneg. */ BIO_set_ssl_renegotiate_bytes(sbio, 100 * 1024); #endif - int port; - alarm(1); - /* Wait for server to be ready. */ - if (read(piperd, &port, sizeof(port)) != sizeof(port)) - err(1, "read pipe"); - char tport[8]; - snprintf(tport, sizeof(tport), "%d", port); - T(BIO_set_conn_port(sbio, tport)); - T(BIO_do_connect(sbio) == 1); + T(SSL_set_fd(ssl, server)); T(BIO_do_handshake(sbio) == 1); - alarm(0); printf("Protocol: %s\n", SSL_get_version(ssl)); printf("Cipher: %s\n", SSL_get_cipher_name(ssl)); -#if 0 - SSL_SESSION *sess = SSL_get0_session(ssl); - SSL_SESSION_print_fp(stdout, sess); -#endif + if (verbose) { + SSL_SESSION *sess = SSL_get0_session(ssl); + SSL_SESSION_print_fp(stdout, sess); + } X509 *cert; T(cert = SSL_get_peer_certificate(ssl)); @@ -299,29 +290,71 @@ int test(const char *algname, const char *paramset) struct certkey ck; ck = certgen(algname, paramset); - int pipefd[2]; - if (pipe(pipefd)) - err(1, "pipe"); - - pid_t pid = fork(); - if (pid < 0) - err(1, "fork"); + int sockfd[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1) + err(1, "socketpair"); - if (pid > 0) { - int status; + setpgid(0, 0); - ret = s_client(pipefd[0]); - wait(&status); - ret |= WIFEXITED(status) && WEXITSTATUS(status); + /* Run server in separate process. */ + pid_t server_pid = fork(); + if (server_pid < 0) + err(1, "fork server"); + if (server_pid == 0) { + ret = s_server(ck.pkey, ck.cert, sockfd[1]); X509_free(ck.cert); EVP_PKEY_free(ck.pkey); - } else if (pid == 0) { - ret = s_server(ck.pkey, ck.cert, pipefd[1]); + exit(ret); + } + + /* Run client in separate process. */ + pid_t client_pid = fork(); + if (client_pid < 0) + err(1, "fork client"); + if (client_pid == 0) { + ret = s_client(sockfd[0]); X509_free(ck.cert); EVP_PKEY_free(ck.pkey); exit(ret); } + /* Wait for first child to exit. */ + int status; + pid_t exited_pid = wait(&status); + ret = (WIFEXITED(status) && WEXITSTATUS(status)) || + (WIFSIGNALED(status) && WTERMSIG(status)); + if (ret) { + fprintf(stderr, cRED "%s child %s with %d %s" cNORM, + exited_pid == server_pid? "server" : "client", + WIFSIGNALED(status)? "killed" : "exited", + WIFSIGNALED(status)? WTERMSIG(status) : WEXITSTATUS(status), + WIFSIGNALED(status)? strsignal(WTERMSIG(status)) : ""); + + /* If first child exited with error, kill other. */ + fprintf(stderr, "terminating %s by force", + exited_pid == server_pid? "client" : "server"); + kill(exited_pid == server_pid? client_pid : server_pid, SIGTERM); + } + + exited_pid = wait(&status); + /* Report error unless we killed it. */ + if (!ret && (!WIFEXITED(status) || WEXITSTATUS(status))) + fprintf(stderr, cRED "%s child %s with %d %s" cNORM, + exited_pid == server_pid? "server" : "client", + WIFSIGNALED(status)? "killed" : "exited", + WIFSIGNALED(status)? WTERMSIG(status) : WEXITSTATUS(status), + WIFSIGNALED(status)? strsignal(WTERMSIG(status)) : ""); + ret |= (WIFEXITED(status) && WEXITSTATUS(status)) || + (WIFSIGNALED(status) && WTERMSIG(status)); + + /* Every responsible process should free this. */ + X509_free(ck.cert); + EVP_PKEY_free(ck.pkey); +#ifdef __SANITIZE_ADDRESS__ + /* Abort on the first (hopefully) ASan error. */ + if (ret) + _exit(ret); +#endif return ret; } @@ -329,15 +362,14 @@ int main(int argc, char **argv) { int ret = 0; - setenv("OPENSSL_ENGINES", ENGINE_DIR, 0); OPENSSL_add_all_algorithms_conf(); - ERR_load_crypto_strings(); - ENGINE *eng; - T(eng = ENGINE_by_id("gost")); - T(ENGINE_init(eng)); - T(ENGINE_set_default(eng, ENGINE_METHOD_ALL)); + + char *p; + if ((p = getenv("VERBOSE"))) + verbose = atoi(p); ret |= test("rsa", NULL); + cipher_list = "LEGACY-GOST2012-GOST8912-GOST8912"; ret |= test("gost2012_256", "A"); ret |= test("gost2012_256", "B"); ret |= test("gost2012_256", "C"); @@ -346,9 +378,6 @@ int main(int argc, char **argv) ret |= test("gost2012_512", "B"); ret |= test("gost2012_512", "C"); - ENGINE_finish(eng); - ENGINE_free(eng); - if (ret) printf(cDRED "= Some tests FAILED!\n" cNORM); else