2 * Simple Client/Server connection test
4 * Based on OpenSSL example code.
5 * Copyright (C) 2019 vt@altlinux.org. All Rights Reserved.
7 * Contents licensed under the terms of the OpenSSL license
8 * See https://www.openssl.org/source/license.html for details
12 # pragma warning(push, 3)
13 # include <openssl/applink.c>
16 #include "e_gost_err.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>
32 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
39 /* For X509_NAME_add_entry_by_txt */
40 # pragma GCC diagnostic ignored "-Wpointer-sign"
45 ERR_print_errors_fp(stderr); \
46 OpenSSLDie(__FILE__, __LINE__, #e); \
50 ERR_print_errors_fp(stderr); \
51 fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \
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); \
65 printf(cGREEN " Test passed\n" cNORM);}
73 static const char *cipher_list;
75 /* How much K to transfer between client and server. */
76 #define KTRANSFER (1 * 1024)
78 static void err(int eval, const char *fmt, ...)
85 printf(": %s\n", strerror(errno));
90 * Simple TLS Server code is based on
91 * https://wiki.openssl.org/index.php/Simple_TLS_Server
93 static int s_server(EVP_PKEY *pkey, X509 *cert, int client)
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));
102 T(ssl = SSL_new(ctx));
103 T(SSL_set_fd(ssl, client));
105 T(SSL_set_cipher_list(ssl, cipher_list));
106 T(SSL_accept(ssl) == 1);
108 /* Receive data from client */
111 for (i = 0; i < KTRANSFER; i++) {
114 T(SSL_read(ssl, buf, sizeof(buf)) == sizeof(buf));
115 for (k = 0; k < sizeof(buf); k++)
117 err(1, "corruption from client");
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));
133 * Simple TLC Client code is based on man BIO_f_ssl and
134 * https://wiki.openssl.org/index.php/SSL/TLS_Client
136 static int s_client(int server)
139 T(ctx = SSL_CTX_new(TLS_client_method()));
142 T(sbio = BIO_new_ssl_connect(ctx));
144 T(BIO_get_ssl(sbio, &ssl));
145 T(SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY));
147 T(SSL_set_cipher_list(ssl, cipher_list));
149 /* Does not work with reneg. */
150 BIO_set_ssl_renegotiate_bytes(sbio, 100 * 1024);
152 T(SSL_set_fd(ssl, server));
153 T(BIO_do_handshake(sbio) == 1);
155 printf("Protocol: %s\n", SSL_get_version(ssl));
156 printf("Cipher: %s\n", SSL_get_cipher_name(ssl));
158 SSL_SESSION *sess = SSL_get0_session(ssl);
159 SSL_SESSION_print_fp(stdout, sess);
163 T(cert = SSL_get_peer_certificate(ssl));
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");
170 /* Send data to server. */
173 memset(buf, 'c', sizeof(buf));
174 for (i = 0; i < KTRANSFER; i++) {
175 T(BIO_write(sbio, buf, sizeof(buf)) == sizeof(buf));
177 (void)BIO_shutdown_wr(sbio);
179 /* Receive data from server. */
180 for (i = 0; i < KTRANSFER; i++) {
182 int n = BIO_read(sbio, buf, sizeof(buf));
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);
191 for (k = 0; k < sizeof(buf); k++)
193 err(1, "corruption from server");
196 i = BIO_get_num_renegotiates(sbio);
198 printf("Renegs: %d\n", i);
205 /* Generate simple cert+key pair. Based on req.c */
206 static struct certkey certgen(const char *algname, const char *paramset)
210 T(tkey = EVP_PKEY_new());
211 T(EVP_PKEY_set_type_str(tkey, algname, strlen(algname)));
213 T(ctx = EVP_PKEY_CTX_new(tkey, NULL));
214 T(EVP_PKEY_keygen_init(ctx));
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);
223 X509_REQ *req = NULL;
224 T(req = X509_REQ_new());
225 T(X509_REQ_set_version(req, 0L));
227 T(name = X509_NAME_new());
228 T(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, "Test CA", -1, -1, 0));
229 T(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "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);
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)));
250 X509V3_set_ctx_nodb(&v3ctx);
251 X509V3_set_ctx(&v3ctx, x509ss, x509ss, NULL, NULL, 0);
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);
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);
269 /* Print cert in text format. */
270 X509_print_fp(stdout, x509ss);
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);
278 return (struct certkey){ .pkey = pkey, .cert = x509ss };
281 int test(const char *algname, const char *paramset)
285 printf(cBLUE "Test %s", algname);
287 printf(cBLUE ":%s", paramset);
291 ck = certgen(algname, paramset);
294 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1)
295 err(1, "socketpair");
299 /* Run server in separate process. */
300 pid_t server_pid = fork();
302 err(1, "fork server");
303 if (server_pid == 0) {
304 ret = s_server(ck.pkey, ck.cert, sockfd[1]);
306 EVP_PKEY_free(ck.pkey);
310 /* Run client in separate process. */
311 pid_t client_pid = fork();
313 err(1, "fork client");
314 if (client_pid == 0) {
315 ret = s_client(sockfd[0]);
317 EVP_PKEY_free(ck.pkey);
321 /* Wait for first child to exit. */
323 pid_t exited_pid = wait(&status);
324 ret = (WIFEXITED(status) && WEXITSTATUS(status)) ||
325 (WIFSIGNALED(status) && WTERMSIG(status));
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)) : "");
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);
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));
350 /* Every responsible process should free this. */
352 EVP_PKEY_free(ck.pkey);
353 #ifdef __SANITIZE_ADDRESS__
354 /* Abort on the first (hopefully) ASan error. */
361 int main(int argc, char **argv)
365 OPENSSL_add_all_algorithms_conf();
368 if ((p = getenv("VERBOSE")))
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");
382 printf(cDRED "= Some tests FAILED!\n" cNORM);
384 printf(cDGREEN "= All tests passed!\n" cNORM);