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