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
11 #include "e_gost_err.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>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
33 /* For X509_NAME_add_entry_by_txt */
34 #pragma GCC diagnostic ignored "-Wpointer-sign"
36 #define T(e) ({ if (!(e)) { \
37 ERR_print_errors_fp(stderr); \
38 OpenSSLDie(__FILE__, __LINE__, #e); \
41 #define TE(e) ({ if (!(e)) { \
42 ERR_print_errors_fp(stderr); \
43 fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \
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); \
58 printf(cGREEN " Test passed\n" cNORM);}
65 /* How much K to transfer between client and server. */
66 #define KTRANSFER (1 * 1024)
69 * Simple TLS Server code is based on
70 * https://wiki.openssl.org/index.php/Simple_TLS_Server
72 static int s_server(EVP_PKEY *pkey, X509 *cert, int pipewr)
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));
80 struct sockaddr_in addr = { .sin_family = AF_INET };
83 sock = socket(AF_INET, SOCK_STREAM, 0);
86 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)
88 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
91 if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0)
92 err(1, "getsockname");
93 int port = ntohs(addr.sin_port);
94 if (listen(sock, 1) < 0)
96 /* Signal to client that server is ready. */
97 if (write(pipewr, &port, sizeof(port)) != sizeof(port))
101 int client = accept(sock, (struct sockaddr *)&addr, &len);
107 SSL_set_fd(ssl, client);
108 T(SSL_accept(ssl) == 1);
110 /* Receive data from client */
113 for (i = 0; i < KTRANSFER; i++) {
116 T(SSL_read(ssl, buf, sizeof(buf)) == sizeof(buf));
117 for (k = 0; k < sizeof(buf); k++)
119 err(1, "corruption from client");
121 /* Send data to client. */
122 memset(buf, 's', sizeof(buf));
123 for (i = 0; i < KTRANSFER; i++) {
124 T(SSL_write(ssl, buf, sizeof(buf)) == sizeof(buf));
136 * Simple TLC Client code is based on man BIO_f_ssl and
137 * https://wiki.openssl.org/index.php/SSL/TLS_Client
139 static int s_client(int piperd)
142 T(ctx = SSL_CTX_new(TLS_client_method()));
145 T(sbio = BIO_new_ssl_connect(ctx));
147 T(BIO_get_ssl(sbio, &ssl));
148 T(SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY));
150 /* Does not work with reneg. */
151 BIO_set_ssl_renegotiate_bytes(sbio, 100 * 1024);
155 /* Wait for server to be ready. */
156 if (read(piperd, &port, sizeof(port)) != sizeof(port))
159 snprintf(tport, sizeof(tport), "%d", port);
160 T(BIO_set_conn_port(sbio, tport));
161 T(BIO_do_connect(sbio) == 1);
162 T(BIO_do_handshake(sbio) == 1);
165 printf("Protocol: %s\n", SSL_get_version(ssl));
166 printf("Cipher: %s\n", SSL_get_cipher_name(ssl));
168 SSL_SESSION *sess = SSL_get0_session(ssl);
169 SSL_SESSION_print_fp(stdout, sess);
173 T(cert = SSL_get_peer_certificate(ssl));
175 int verify = SSL_get_verify_result(ssl);
176 printf("Verify: %s\n", X509_verify_cert_error_string(verify));
177 if (verify != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
178 err(1, "invalid SSL_get_verify_result");
180 /* Send data to server. */
183 memset(buf, 'c', sizeof(buf));
184 for (i = 0; i < KTRANSFER; i++) {
185 T(BIO_write(sbio, buf, sizeof(buf)) == sizeof(buf));
187 (void)BIO_shutdown_wr(sbio);
189 /* Receive data from server. */
190 for (i = 0; i < KTRANSFER; i++) {
192 int n = BIO_read(sbio, buf, sizeof(buf));
194 if (n != sizeof(buf)) {
195 printf("i:%d BIO_read:%d SSL_get_error:%d\n", i, n,
196 SSL_get_error(ssl, n));
197 ERR_print_errors_fp(stderr);
201 for (k = 0; k < sizeof(buf); k++)
203 err(1, "corruption from server");
206 i = BIO_get_num_renegotiates(sbio);
208 printf("Renegs: %d\n", i);
215 /* Generate simple cert+key pair. Based on req.c */
216 static struct certkey certgen(const char *algname, const char *paramset)
220 T(tkey = EVP_PKEY_new());
221 T(EVP_PKEY_set_type_str(tkey, algname, strlen(algname)));
223 T(ctx = EVP_PKEY_CTX_new(tkey, NULL));
224 T(EVP_PKEY_keygen_init(ctx));
226 T(EVP_PKEY_CTX_ctrl_str(ctx, "paramset", paramset));
227 EVP_PKEY *pkey = NULL;
228 T((EVP_PKEY_keygen(ctx, &pkey)) == 1);
229 EVP_PKEY_CTX_free(ctx);
233 X509_REQ *req = NULL;
234 T(req = X509_REQ_new());
235 T(X509_REQ_set_version(req, 0L));
237 T(name = X509_NAME_new());
238 T(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, "Test CA", -1, -1, 0));
239 T(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "Test Key", -1, -1, 0));
240 T(X509_REQ_set_subject_name(req, name));
241 T(X509_REQ_set_pubkey(req, pkey));
242 X509_NAME_free(name);
246 T(x509ss = X509_new());
247 T(X509_set_version(x509ss, 2));
248 BIGNUM *brnd = BN_new();
249 T(BN_rand(brnd, 20 * 8 - 1, -1, 0));
250 T(BN_to_ASN1_INTEGER(brnd, X509_get_serialNumber(x509ss)));
251 T(X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)));
252 T(X509_gmtime_adj(X509_getm_notBefore(x509ss), 0));
253 T(X509_time_adj_ex(X509_getm_notAfter(x509ss), 1, 0, NULL));
254 T(X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req)));
255 T(X509_set_pubkey(x509ss, X509_REQ_get0_pubkey(req)));
260 X509V3_set_ctx_nodb(&v3ctx);
261 X509V3_set_ctx(&v3ctx, x509ss, x509ss, NULL, NULL, 0);
263 T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_basic_constraints, "critical,CA:TRUE"));
264 T(X509_add_ext(x509ss, ext, 0));
265 X509_EXTENSION_free(ext);
266 T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_subject_key_identifier, "hash"));
267 T(X509_add_ext(x509ss, ext, 1));
268 X509_EXTENSION_free(ext);
269 T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_authority_key_identifier, "keyid:always,issuer"));
270 T(X509_add_ext(x509ss, ext, 2));
271 X509_EXTENSION_free(ext);
274 T(mctx = EVP_MD_CTX_new());
275 T(EVP_DigestSignInit(mctx, NULL, NULL, NULL, pkey));
276 T(X509_sign_ctx(x509ss, mctx));
277 EVP_MD_CTX_free(mctx);
279 /* Print cert in text format. */
280 X509_print_fp(stdout, x509ss);
283 /* Print cert in PEM format. */
284 BIO *out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
285 PEM_write_bio_X509(out, x509ss);
288 return (struct certkey){ .pkey = pkey, .cert = x509ss };
291 int test(const char *algname, const char *paramset)
295 printf(cBLUE "Test %s", algname);
297 printf(cBLUE ":%s", paramset);
301 ck = certgen(algname, paramset);
314 ret = s_client(pipefd[0]);
316 ret |= WIFEXITED(status) && WEXITSTATUS(status);
318 EVP_PKEY_free(ck.pkey);
319 } else if (pid == 0) {
320 ret = s_server(ck.pkey, ck.cert, pipefd[1]);
322 EVP_PKEY_free(ck.pkey);
329 int main(int argc, char **argv)
333 setenv("OPENSSL_ENGINES", ENGINE_DIR, 0);
334 OPENSSL_add_all_algorithms_conf();
335 ERR_load_crypto_strings();
337 T(eng = ENGINE_by_id("gost"));
339 T(ENGINE_set_default(eng, ENGINE_METHOD_ALL));
341 ret |= test("rsa", NULL);
342 ret |= test("gost2012_256", "A");
343 ret |= test("gost2012_256", "B");
344 ret |= test("gost2012_256", "C");
345 ret |= test("gost2012_256", "TCA");
346 ret |= test("gost2012_512", "A");
347 ret |= test("gost2012_512", "B");
348 ret |= test("gost2012_512", "C");
354 printf(cDRED "= Some tests FAILED!\n" cNORM);
356 printf(cDGREEN "= All tests passed!\n" cNORM);