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