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