]> www.wagner.pp.ru Git - openssl-gost/engine.git/blobdiff - test_tls.c
tcl_tests: ca.try: Ignore openssl crl exit status for 'corrupted CRL' test
[openssl-gost/engine.git] / test_tls.c
index bee503385c018b603e222d5094b06a81806c0cb0..77e62815826d98039e6fdcb38a2ad31b5df0f885 100644 (file)
@@ -8,6 +8,11 @@
  * See https://www.openssl.org/source/license.html for details
  */
 
+#ifdef _MSC_VER
+# pragma warning(push, 3)
+# include <openssl/applink.c>
+# pragma warning(pop)
+#endif
 #include "e_gost_err.h"
 #include "gost_lcl.h"
 #include <openssl/evp.h>
 #include <openssl/bn.h>
 #include <string.h>
 #include <stdlib.h>
-#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"
@@ -66,123 +66,15 @@ struct certkey {
 static int verbose;
 static const char *cipher_list;
 
-/* How much K to transfer between client and server. */
-#define KTRANSFER (1 * 1024)
-
-/*
- * 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 client)
+static void err(int eval, const char *fmt, ...)
 {
-    SSL_CTX *ctx;
-    T(ctx = SSL_CTX_new(TLS_server_method()));
-    T(SSL_CTX_use_certificate(ctx, cert));
-    T(SSL_CTX_use_PrivateKey(ctx, pkey));
-    T(SSL_CTX_check_private_key(ctx));
-
-    SSL *ssl;
-    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 */
-    char buf[1024];
-    int i;
-    for (i = 0; i < KTRANSFER; i++) {
-       int k;
+    va_list ap;
 
-       T(SSL_read(ssl, buf, sizeof(buf)) == sizeof(buf));
-       for (k = 0; k < sizeof(buf); k++)
-           if (buf[k] != 'c')
-               err(1, "corruption from client");
-    }
-    /* Send data to client. */
-    memset(buf, 's', sizeof(buf));
-    for (i = 0; i < KTRANSFER; i++) {
-       T(SSL_write(ssl, buf, sizeof(buf)) == sizeof(buf));
-    }
-    SSL_shutdown(ssl);
-    SSL_free(ssl);
-    close(client);
-
-    SSL_CTX_free(ctx);
-    return 0;
-}
-
-/*
- * 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 server)
-{
-    SSL_CTX *ctx;
-    T(ctx = SSL_CTX_new(TLS_client_method()));
-
-    BIO *sbio;
-    T(sbio = BIO_new_ssl_connect(ctx));
-    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
-    T(SSL_set_fd(ssl, server));
-    T(BIO_do_handshake(sbio) == 1);
-
-    printf("Protocol: %s\n", SSL_get_version(ssl));
-    printf("Cipher:   %s\n", SSL_get_cipher_name(ssl));
-    if (verbose) {
-       SSL_SESSION *sess = SSL_get0_session(ssl);
-       SSL_SESSION_print_fp(stdout, sess);
-    }
-
-    X509 *cert;
-    T(cert = SSL_get_peer_certificate(ssl));
-    X509_free(cert);
-    int verify = SSL_get_verify_result(ssl);
-    printf("Verify:   %s\n", X509_verify_cert_error_string(verify));
-    if (verify != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
-       err(1, "invalid SSL_get_verify_result");
-
-    /* Send data to server. */
-    char buf[1024];
-    int i;
-    memset(buf, 'c', sizeof(buf));
-    for (i = 0; i < KTRANSFER; i++) {
-       T(BIO_write(sbio, buf, sizeof(buf)) == sizeof(buf));
-    }
-    (void)BIO_shutdown_wr(sbio);
-
-    /* Receive data from server. */
-    for (i = 0; i < KTRANSFER; i++) {
-       int k;
-       int n = BIO_read(sbio, buf, sizeof(buf));
-
-       if (n != sizeof(buf)) {
-           printf("i:%d BIO_read:%d SSL_get_error:%d\n", i, n,
-               SSL_get_error(ssl, n));
-           ERR_print_errors_fp(stderr);
-           err(1, "BIO_read");
-       }
-
-       for (k = 0; k < sizeof(buf); k++)
-           if (buf[k] != 's')
-               err(1, "corruption from server");
-    }
-
-    i = BIO_get_num_renegotiates(sbio);
-    if (i)
-       printf("Renegs:   %d\n", i);
-    BIO_free_all(sbio);
-    SSL_CTX_free(ctx);
-
-    return 0;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
+    printf(": %s\n", strerror(errno));
+    exit(eval);
 }
 
 /* Generate simple cert+key pair. Based on req.c */
@@ -208,8 +100,8 @@ static struct certkey certgen(const char *algname, const char *paramset)
     T(X509_REQ_set_version(req, 0L));
     X509_NAME *name;
     T(name = X509_NAME_new());
-    T(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, "Test CA", -1, -1, 0));
-    T(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "Test Key", -1, -1, 0));
+    T(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Test CA", -1, -1, 0));
+    T(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"Test Key", -1, -1, 0));
     T(X509_REQ_set_subject_name(req, name));
     T(X509_REQ_set_pubkey(req, pkey));
     X509_NAME_free(name);
@@ -261,6 +153,7 @@ static struct certkey certgen(const char *algname, const char *paramset)
     return (struct certkey){ .pkey = pkey, .cert = x509ss };
 }
 
+/* Non-blocking BIO test mechanic is based on sslapitest.c */
 int test(const char *algname, const char *paramset)
 {
     int ret = 0;
@@ -273,71 +166,105 @@ int test(const char *algname, const char *paramset)
     struct certkey ck;
     ck = certgen(algname, paramset);
 
-    int sockfd[2];
-    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) == -1)
-       err(1, "socketpair");
-
-    setpgid(0, 0);
-
-    /* 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);
-       exit(ret);
+    SSL_CTX *cctx, *sctx;
+
+    T(sctx = SSL_CTX_new(TLS_server_method()));
+    T(SSL_CTX_use_certificate(sctx, ck.cert));
+    T(SSL_CTX_use_PrivateKey(sctx, ck.pkey));
+    T(SSL_CTX_check_private_key(sctx));
+
+    T(cctx = SSL_CTX_new(TLS_client_method()));
+
+    /* create_ssl_objects */
+    SSL *serverssl, *clientssl;
+    T(serverssl = SSL_new(sctx));
+    T(clientssl = SSL_new(cctx));
+    BIO *s_to_c_bio, *c_to_s_bio;
+    T(s_to_c_bio = BIO_new(BIO_s_mem()));
+    T(c_to_s_bio = BIO_new(BIO_s_mem()));
+    /* Non-blocking IO. */
+    BIO_set_mem_eof_return(s_to_c_bio, -1);
+    BIO_set_mem_eof_return(c_to_s_bio, -1);
+    /* Transfer BIOs to SSL objects. */
+    SSL_set_bio(serverssl, c_to_s_bio, s_to_c_bio);
+    BIO_up_ref(s_to_c_bio);
+    BIO_up_ref(c_to_s_bio);
+    SSL_set_bio(clientssl, s_to_c_bio, c_to_s_bio);
+    c_to_s_bio = NULL;
+    c_to_s_bio = NULL;
+
+    /* create_ssl_connection */
+    int retc = -1, rets = -1, err;
+    do {
+        err = SSL_ERROR_WANT_WRITE;
+        while (retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
+            retc = SSL_connect(clientssl);
+            if (retc <= 0)
+                err = SSL_get_error(clientssl, retc);
+            if (verbose)
+                printf("SSL_connect: %d %d\n", retc, err);
+        }
+        if (retc <= 0 && err != SSL_ERROR_WANT_READ) {
+            ERR_print_errors_fp(stderr);
+            OpenSSLDie(__FILE__, __LINE__, "SSL_connect");
+        }
+        err = SSL_ERROR_WANT_WRITE;
+        while (rets <= 0 && err == SSL_ERROR_WANT_WRITE) {
+            rets = SSL_accept(serverssl);
+            if (rets <= 0)
+                err = SSL_get_error(serverssl, rets);
+            if (verbose)
+                printf("SSL_accept: %d %d\n", rets, err);
+        }
+        if (rets <= 0 && err != SSL_ERROR_WANT_READ &&
+            err != SSL_ERROR_WANT_X509_LOOKUP) {
+            ERR_print_errors_fp(stderr);
+            OpenSSLDie(__FILE__, __LINE__, "SSL_accept");
+        }
+    } while (retc <=0 || rets <= 0);
+
+    /* Two SSL_read_ex should fail. */
+    unsigned char buf;
+    size_t readbytes;
+    T(!SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes));
+    T(!SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes));
+
+    /* Connect client to the server. */
+    T(SSL_do_handshake(clientssl) == 1);
+    printf("Protocol: %s\n", SSL_get_version(clientssl));
+    printf("Cipher:   %s\n", SSL_get_cipher_name(clientssl));
+    if (verbose) {
+        SSL_SESSION *sess = SSL_get0_session(clientssl);
+        SSL_SESSION_print_fp(stdout, sess);
     }
 
-    /* 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);
+    /* Transfer some data. */
+    int i;
+    for (i = 0; i < 16; i++) {
+        char pbuf[512], lbuf[512];
+
+        memset(pbuf, 'c' + i, sizeof(pbuf));
+        T(SSL_write(serverssl, pbuf, sizeof(pbuf)) == sizeof(pbuf));
+        T(SSL_read(clientssl, lbuf, sizeof(lbuf)) == sizeof(lbuf));
+        T(memcmp(pbuf, lbuf, sizeof(pbuf)) == 0);
+
+        memset(lbuf, 's' + i, sizeof(lbuf));
+        T(SSL_write(clientssl, lbuf, sizeof(lbuf)) == sizeof(lbuf));
+        T(SSL_read(serverssl, pbuf, sizeof(pbuf)) == sizeof(pbuf));
+        T(memcmp(pbuf, lbuf, sizeof(pbuf)) == 0);
     }
 
-    /* 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) {
-       warnx(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. */
-       warnx("terminating %s by force",
-           exited_pid == server_pid? "client" : "server");
-       kill(exited_pid == server_pid? client_pid : server_pid, SIGTERM);
-    }
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
 
-    exited_pid = wait(&status);
-    /* Report error unless we killed it. */
-    if (!ret && (!WIFEXITED(status) || WEXITSTATUS(status)))
-       warnx(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));
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
 
     /* 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;
 }
 
@@ -345,13 +272,7 @@ 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")))
@@ -367,9 +288,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