]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - test_tls.c
MSVC: Fix casting warning C4057
[openssl-gost/engine.git] / test_tls.c
1 /*
2  * Simple Client/Server connection test
3  *
4  * Based on OpenSSL example code.
5  * Copyright (C) 2019 vt@altlinux.org. All Rights Reserved.
6  *
7  * Contents licensed under the terms of the OpenSSL license
8  * See https://www.openssl.org/source/license.html for details
9  */
10
11 #ifdef _MSC_VER
12 # pragma warning(push, 3)
13 # include <openssl/applink.c>
14 # pragma warning(pop)
15 #endif
16 #include "e_gost_err.h"
17 #include "gost_lcl.h"
18 #include <openssl/evp.h>
19 #include <openssl/ssl.h>
20 #include <openssl/bio.h>
21 #include <openssl/rand.h>
22 #include <openssl/err.h>
23 #include <openssl/asn1.h>
24 #include <openssl/obj_mac.h>
25 #include <openssl/x509v3.h>
26 #include <openssl/ec.h>
27 #include <openssl/bn.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/wait.h>
32 #include <sys/types.h>
33 #include <signal.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37
38 #ifdef __GNUC__
39 /* For X509_NAME_add_entry_by_txt */
40 # pragma GCC diagnostic ignored "-Wpointer-sign"
41 #endif
42
43 #define T(e) \
44     if (!(e)) { \
45         ERR_print_errors_fp(stderr); \
46         OpenSSLDie(__FILE__, __LINE__, #e); \
47     }
48 #define TE(e) \
49     if (!(e)) { \
50         ERR_print_errors_fp(stderr); \
51         fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \
52         return -1; \
53     }
54
55 #define cRED    "\033[1;31m"
56 #define cDRED   "\033[0;31m"
57 #define cGREEN  "\033[1;32m"
58 #define cDGREEN "\033[0;32m"
59 #define cBLUE   "\033[1;34m"
60 #define cDBLUE  "\033[0;34m"
61 #define cNORM   "\033[m"
62 #define TEST_ASSERT(e) {if ((test = (e))) \
63                  printf(cRED "  Test FAILED\n" cNORM); \
64              else \
65                  printf(cGREEN "  Test passed\n" cNORM);}
66
67 struct certkey {
68     EVP_PKEY *pkey;
69     X509 *cert;
70 };
71
72 static int verbose;
73 static const char *cipher_list;
74
75 /* How much K to transfer between client and server. */
76 #define KTRANSFER (1 * 1024)
77
78 static void err(int eval, const char *fmt, ...)
79 {
80     va_list ap;
81
82     va_start(ap, fmt);
83     vprintf(fmt, ap);
84     va_end(ap);
85     printf(": %s\n", strerror(errno));
86     exit(eval);
87 }
88
89 /*
90  * Simple TLS Server code is based on
91  * https://wiki.openssl.org/index.php/Simple_TLS_Server
92  */
93 static int s_server(EVP_PKEY *pkey, X509 *cert, int client)
94 {
95     SSL_CTX *ctx;
96     T(ctx = SSL_CTX_new(TLS_server_method()));
97     T(SSL_CTX_use_certificate(ctx, cert));
98     T(SSL_CTX_use_PrivateKey(ctx, pkey));
99     T(SSL_CTX_check_private_key(ctx));
100
101     SSL *ssl;
102     T(ssl = SSL_new(ctx));
103     T(SSL_set_fd(ssl, client));
104     if (cipher_list)
105         T(SSL_set_cipher_list(ssl, cipher_list));
106     T(SSL_accept(ssl) == 1);
107
108     /* Receive data from client */
109     char buf[1024];
110     int i;
111     for (i = 0; i < KTRANSFER; i++) {
112         int k;
113
114         T(SSL_read(ssl, buf, sizeof(buf)) == sizeof(buf));
115         for (k = 0; k < sizeof(buf); k++)
116             if (buf[k] != 'c')
117                 err(1, "corruption from client");
118     }
119     /* Send data to client. */
120     memset(buf, 's', sizeof(buf));
121     for (i = 0; i < KTRANSFER; i++) {
122         T(SSL_write(ssl, buf, sizeof(buf)) == sizeof(buf));
123     }
124     SSL_shutdown(ssl);
125     SSL_free(ssl);
126     close(client);
127
128     SSL_CTX_free(ctx);
129     return 0;
130 }
131
132 /*
133  * Simple TLC Client code is based on man BIO_f_ssl and
134  * https://wiki.openssl.org/index.php/SSL/TLS_Client
135  */
136 static int s_client(int server)
137 {
138     SSL_CTX *ctx;
139     T(ctx = SSL_CTX_new(TLS_client_method()));
140
141     BIO *sbio;
142     T(sbio = BIO_new_ssl_connect(ctx));
143     SSL *ssl;
144     T(BIO_get_ssl(sbio, &ssl));
145     T(SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY));
146     if (cipher_list)
147         T(SSL_set_cipher_list(ssl, cipher_list));
148 #if 0
149     /* Does not work with reneg. */
150     BIO_set_ssl_renegotiate_bytes(sbio, 100 * 1024);
151 #endif
152     T(SSL_set_fd(ssl, server));
153     T(BIO_do_handshake(sbio) == 1);
154
155     printf("Protocol: %s\n", SSL_get_version(ssl));
156     printf("Cipher:   %s\n", SSL_get_cipher_name(ssl));
157     if (verbose) {
158         SSL_SESSION *sess = SSL_get0_session(ssl);
159         SSL_SESSION_print_fp(stdout, sess);
160     }
161
162     X509 *cert;
163     T(cert = SSL_get_peer_certificate(ssl));
164     X509_free(cert);
165     int verify = SSL_get_verify_result(ssl);
166     printf("Verify:   %s\n", X509_verify_cert_error_string(verify));
167     if (verify != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
168         err(1, "invalid SSL_get_verify_result");
169
170     /* Send data to server. */
171     char buf[1024];
172     int i;
173     memset(buf, 'c', sizeof(buf));
174     for (i = 0; i < KTRANSFER; i++) {
175         T(BIO_write(sbio, buf, sizeof(buf)) == sizeof(buf));
176     }
177     (void)BIO_shutdown_wr(sbio);
178
179     /* Receive data from server. */
180     for (i = 0; i < KTRANSFER; i++) {
181         int k;
182         int n = BIO_read(sbio, buf, sizeof(buf));
183
184         if (n != sizeof(buf)) {
185             printf("i:%d BIO_read:%d SSL_get_error:%d\n", i, n,
186                 SSL_get_error(ssl, n));
187             ERR_print_errors_fp(stderr);
188             err(1, "BIO_read");
189         }
190
191         for (k = 0; k < sizeof(buf); k++)
192             if (buf[k] != 's')
193                 err(1, "corruption from server");
194     }
195
196     i = BIO_get_num_renegotiates(sbio);
197     if (i)
198         printf("Renegs:   %d\n", i);
199     BIO_free_all(sbio);
200     SSL_CTX_free(ctx);
201
202     return 0;
203 }
204
205 /* Generate simple cert+key pair. Based on req.c */
206 static struct certkey certgen(const char *algname, const char *paramset)
207 {
208     /* Keygen. */
209     EVP_PKEY *tkey;
210     T(tkey = EVP_PKEY_new());
211     T(EVP_PKEY_set_type_str(tkey, algname, strlen(algname)));
212     EVP_PKEY_CTX *ctx;
213     T(ctx = EVP_PKEY_CTX_new(tkey, NULL));
214     T(EVP_PKEY_keygen_init(ctx));
215     if (paramset)
216         T(EVP_PKEY_CTX_ctrl_str(ctx, "paramset", paramset));
217     EVP_PKEY *pkey = NULL;
218     T((EVP_PKEY_keygen(ctx, &pkey)) == 1);
219     EVP_PKEY_CTX_free(ctx);
220     EVP_PKEY_free(tkey);
221
222     /* REQ. */
223     X509_REQ *req = NULL;
224     T(req = X509_REQ_new());
225     T(X509_REQ_set_version(req, 0L));
226     X509_NAME *name;
227     T(name = X509_NAME_new());
228     T(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Test CA", -1, -1, 0));
229     T(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"Test Key", -1, -1, 0));
230     T(X509_REQ_set_subject_name(req, name));
231     T(X509_REQ_set_pubkey(req, pkey));
232     X509_NAME_free(name);
233
234     /* Cert. */
235     X509 *x509ss = NULL;
236     T(x509ss = X509_new());
237     T(X509_set_version(x509ss, 2));
238     BIGNUM *brnd = BN_new();
239     T(BN_rand(brnd, 20 * 8 - 1, -1, 0));
240     T(BN_to_ASN1_INTEGER(brnd, X509_get_serialNumber(x509ss)));
241     T(X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)));
242     T(X509_gmtime_adj(X509_getm_notBefore(x509ss), 0));
243     T(X509_time_adj_ex(X509_getm_notAfter(x509ss), 1, 0, NULL));
244     T(X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req)));
245     T(X509_set_pubkey(x509ss, X509_REQ_get0_pubkey(req)));
246     X509_REQ_free(req);
247     BN_free(brnd);
248
249     X509V3_CTX v3ctx;
250     X509V3_set_ctx_nodb(&v3ctx);
251     X509V3_set_ctx(&v3ctx, x509ss, x509ss, NULL, NULL, 0);
252     X509_EXTENSION *ext;
253     T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_basic_constraints, "critical,CA:TRUE"));
254     T(X509_add_ext(x509ss, ext, 0));
255     X509_EXTENSION_free(ext);
256     T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_subject_key_identifier, "hash"));
257     T(X509_add_ext(x509ss, ext, 1));
258     X509_EXTENSION_free(ext);
259     T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_authority_key_identifier, "keyid:always,issuer"));
260     T(X509_add_ext(x509ss, ext, 2));
261     X509_EXTENSION_free(ext);
262
263     EVP_MD_CTX *mctx;
264     T(mctx = EVP_MD_CTX_new());
265     T(EVP_DigestSignInit(mctx, NULL, NULL, NULL, pkey));
266     T(X509_sign_ctx(x509ss, mctx));
267     EVP_MD_CTX_free(mctx);
268 #if 0
269     /* Print cert in text format. */
270     X509_print_fp(stdout, x509ss);
271 #endif
272 #if 0
273     /* Print cert in PEM format. */
274     BIO *out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
275     PEM_write_bio_X509(out, x509ss);
276     BIO_free_all(out);
277 #endif
278     return (struct certkey){ .pkey = pkey, .cert = x509ss };
279 }
280
281 int test(const char *algname, const char *paramset)
282 {
283     int ret = 0;
284
285     printf(cBLUE "Test %s", algname);
286     if (paramset)
287         printf(cBLUE ":%s", paramset);
288     printf(cNORM "\n");
289
290     struct certkey ck;
291     ck = certgen(algname, paramset);
292
293     int sockfd[2];
294     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1)
295         err(1, "socketpair");
296
297     setpgid(0, 0);
298
299     /* Run server in separate process. */
300     pid_t server_pid = fork();
301     if (server_pid < 0)
302         err(1, "fork server");
303     if (server_pid == 0) {
304         ret = s_server(ck.pkey, ck.cert, sockfd[1]);
305         X509_free(ck.cert);
306         EVP_PKEY_free(ck.pkey);
307         exit(ret);
308     }
309
310     /* Run client in separate process. */
311     pid_t client_pid = fork();
312     if (client_pid < 0)
313         err(1, "fork client");
314     if (client_pid == 0) {
315         ret = s_client(sockfd[0]);
316         X509_free(ck.cert);
317         EVP_PKEY_free(ck.pkey);
318         exit(ret);
319     }
320
321     /* Wait for first child to exit. */
322     int status;
323     pid_t exited_pid = wait(&status);
324     ret = (WIFEXITED(status) && WEXITSTATUS(status)) ||
325         (WIFSIGNALED(status) && WTERMSIG(status));
326     if (ret) {
327         fprintf(stderr, cRED "%s child %s with %d %s" cNORM,
328             exited_pid == server_pid? "server" : "client",
329             WIFSIGNALED(status)? "killed" : "exited",
330             WIFSIGNALED(status)? WTERMSIG(status) : WEXITSTATUS(status),
331             WIFSIGNALED(status)? strsignal(WTERMSIG(status)) : "");
332
333         /* If first child exited with error, kill other. */
334         fprintf(stderr, "terminating %s by force",
335             exited_pid == server_pid? "client" : "server");
336         kill(exited_pid == server_pid? client_pid : server_pid, SIGTERM);
337     }
338
339     exited_pid = wait(&status);
340     /* Report error unless we killed it. */
341     if (!ret && (!WIFEXITED(status) || WEXITSTATUS(status)))
342         fprintf(stderr, cRED "%s child %s with %d %s" cNORM,
343             exited_pid == server_pid? "server" : "client",
344             WIFSIGNALED(status)? "killed" : "exited",
345             WIFSIGNALED(status)? WTERMSIG(status) : WEXITSTATUS(status),
346             WIFSIGNALED(status)? strsignal(WTERMSIG(status)) : "");
347     ret |= (WIFEXITED(status) && WEXITSTATUS(status)) ||
348         (WIFSIGNALED(status) && WTERMSIG(status));
349
350     /* Every responsible process should free this. */
351     X509_free(ck.cert);
352     EVP_PKEY_free(ck.pkey);
353 #ifdef __SANITIZE_ADDRESS__
354     /* Abort on the first (hopefully) ASan error. */
355     if (ret)
356         _exit(ret);
357 #endif
358     return ret;
359 }
360
361 int main(int argc, char **argv)
362 {
363     int ret = 0;
364
365     OPENSSL_add_all_algorithms_conf();
366
367     char *p;
368     if ((p = getenv("VERBOSE")))
369         verbose = atoi(p);
370
371     ret |= test("rsa", NULL);
372     cipher_list = "LEGACY-GOST2012-GOST8912-GOST8912";
373     ret |= test("gost2012_256", "A");
374     ret |= test("gost2012_256", "B");
375     ret |= test("gost2012_256", "C");
376     ret |= test("gost2012_256", "TCA");
377     ret |= test("gost2012_512", "A");
378     ret |= test("gost2012_512", "B");
379     ret |= test("gost2012_512", "C");
380
381     if (ret)
382         printf(cDRED "= Some tests FAILED!\n" cNORM);
383     else
384         printf(cDGREEN "= All tests passed!\n" cNORM);
385     return ret;
386 }