]> www.wagner.pp.ru Git - openssl-gost/engine.git/blobdiff - test_tls.c
MSVC: Fix absence of 'setenv'
[openssl-gost/engine.git] / test_tls.c
index fa4048c7afd844a9e4fcd9731536a6b478fb1d27..d016e62ca920a7d8427b46302439a34603b89195 100644 (file)
 #include <unistd.h>
 #include <sys/wait.h>
 #include <sys/types.h>
+#include <signal.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <err.h>
 
+#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"
@@ -62,14 +64,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()));
@@ -77,34 +93,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 */
@@ -127,7 +120,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;
 }
@@ -136,7 +128,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()));
@@ -146,28 +138,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));
@@ -300,29 +285,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;
 }
 
@@ -330,15 +357,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");
@@ -347,9 +373,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