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>
30 #include <sys/types.h>
33 /* For X509_NAME_add_entry_by_txt */
34 # pragma GCC diagnostic ignored "-Wpointer-sign"
39 ERR_print_errors_fp(stderr); \
40 OpenSSLDie(__FILE__, __LINE__, #e); \
44 ERR_print_errors_fp(stderr); \
45 fprintf(stderr, "Error at %s:%d %s\n", __FILE__, __LINE__, #e); \
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); \
59 printf(cGREEN " Test passed\n" cNORM);}
67 static const char *cipher_list;
69 static void err(int eval, const char *fmt, ...)
76 printf(": %s\n", strerror(errno));
80 /* Generate simple cert+key pair. Based on req.c */
81 static struct certkey certgen(const char *algname, const char *paramset)
85 T(tkey = EVP_PKEY_new());
86 T(EVP_PKEY_set_type_str(tkey, algname, strlen(algname)));
88 T(ctx = EVP_PKEY_CTX_new(tkey, NULL));
89 T(EVP_PKEY_keygen_init(ctx));
91 T(EVP_PKEY_CTX_ctrl_str(ctx, "paramset", paramset));
92 EVP_PKEY *pkey = NULL;
93 T((EVP_PKEY_keygen(ctx, &pkey)) == 1);
94 EVP_PKEY_CTX_free(ctx);
99 T(req = X509_REQ_new());
100 T(X509_REQ_set_version(req, 0L));
102 T(name = X509_NAME_new());
103 T(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Test CA", -1, -1, 0));
104 T(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"Test Key", -1, -1, 0));
105 T(X509_REQ_set_subject_name(req, name));
106 T(X509_REQ_set_pubkey(req, pkey));
107 X509_NAME_free(name);
111 T(x509ss = X509_new());
112 T(X509_set_version(x509ss, 2));
113 BIGNUM *brnd = BN_new();
114 T(BN_rand(brnd, 20 * 8 - 1, -1, 0));
115 T(BN_to_ASN1_INTEGER(brnd, X509_get_serialNumber(x509ss)));
116 T(X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)));
117 T(X509_gmtime_adj(X509_getm_notBefore(x509ss), 0));
118 T(X509_time_adj_ex(X509_getm_notAfter(x509ss), 1, 0, NULL));
119 T(X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req)));
120 T(X509_set_pubkey(x509ss, X509_REQ_get0_pubkey(req)));
125 X509V3_set_ctx_nodb(&v3ctx);
126 X509V3_set_ctx(&v3ctx, x509ss, x509ss, NULL, NULL, 0);
128 T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_basic_constraints, "critical,CA:TRUE"));
129 T(X509_add_ext(x509ss, ext, 0));
130 X509_EXTENSION_free(ext);
131 T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_subject_key_identifier, "hash"));
132 T(X509_add_ext(x509ss, ext, 1));
133 X509_EXTENSION_free(ext);
134 T(ext = X509V3_EXT_conf_nid(NULL, &v3ctx, NID_authority_key_identifier, "keyid:always,issuer"));
135 T(X509_add_ext(x509ss, ext, 2));
136 X509_EXTENSION_free(ext);
139 T(mctx = EVP_MD_CTX_new());
140 T(EVP_DigestSignInit(mctx, NULL, NULL, NULL, pkey));
141 T(X509_sign_ctx(x509ss, mctx));
142 EVP_MD_CTX_free(mctx);
144 /* Print cert in text format. */
145 X509_print_fp(stdout, x509ss);
148 /* Print cert in PEM format. */
149 BIO *out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
150 PEM_write_bio_X509(out, x509ss);
153 return (struct certkey){ .pkey = pkey, .cert = x509ss };
156 /* Non-blocking BIO test mechanic is based on sslapitest.c */
157 int test(const char *algname, const char *paramset)
161 printf(cBLUE "Test %s", algname);
163 printf(cBLUE ":%s", paramset);
167 ck = certgen(algname, paramset);
169 SSL_CTX *cctx, *sctx;
171 T(sctx = SSL_CTX_new(TLS_server_method()));
172 T(SSL_CTX_use_certificate(sctx, ck.cert));
173 T(SSL_CTX_use_PrivateKey(sctx, ck.pkey));
174 T(SSL_CTX_check_private_key(sctx));
176 T(cctx = SSL_CTX_new(TLS_client_method()));
178 /* create_ssl_objects */
179 SSL *serverssl, *clientssl;
180 T(serverssl = SSL_new(sctx));
181 T(clientssl = SSL_new(cctx));
182 BIO *s_to_c_bio, *c_to_s_bio;
183 T(s_to_c_bio = BIO_new(BIO_s_mem()));
184 T(c_to_s_bio = BIO_new(BIO_s_mem()));
185 /* Non-blocking IO. */
186 BIO_set_mem_eof_return(s_to_c_bio, -1);
187 BIO_set_mem_eof_return(c_to_s_bio, -1);
188 /* Transfer BIOs to SSL objects. */
189 SSL_set_bio(serverssl, c_to_s_bio, s_to_c_bio);
190 BIO_up_ref(s_to_c_bio);
191 BIO_up_ref(c_to_s_bio);
192 SSL_set_bio(clientssl, s_to_c_bio, c_to_s_bio);
196 /* create_ssl_connection */
197 int retc = -1, rets = -1, err;
199 err = SSL_ERROR_WANT_WRITE;
200 while (retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
201 retc = SSL_connect(clientssl);
203 err = SSL_get_error(clientssl, retc);
205 printf("SSL_connect: %d %d\n", retc, err);
207 if (retc <= 0 && err != SSL_ERROR_WANT_READ) {
208 ERR_print_errors_fp(stderr);
209 OpenSSLDie(__FILE__, __LINE__, "SSL_connect");
211 err = SSL_ERROR_WANT_WRITE;
212 while (rets <= 0 && err == SSL_ERROR_WANT_WRITE) {
213 rets = SSL_accept(serverssl);
215 err = SSL_get_error(serverssl, rets);
217 printf("SSL_accept: %d %d\n", rets, err);
219 if (rets <= 0 && err != SSL_ERROR_WANT_READ &&
220 err != SSL_ERROR_WANT_X509_LOOKUP) {
221 ERR_print_errors_fp(stderr);
222 OpenSSLDie(__FILE__, __LINE__, "SSL_accept");
224 } while (retc <=0 || rets <= 0);
226 /* Two SSL_read_ex should fail. */
229 T(!SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes));
230 T(!SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes));
232 /* Connect client to the server. */
233 T(SSL_do_handshake(clientssl) == 1);
234 printf("Protocol: %s\n", SSL_get_version(clientssl));
235 printf("Cipher: %s\n", SSL_get_cipher_name(clientssl));
237 SSL_SESSION *sess = SSL_get0_session(clientssl);
238 SSL_SESSION_print_fp(stdout, sess);
241 /* Transfer some data. */
243 for (i = 0; i < 16; i++) {
244 char pbuf[512], lbuf[512];
246 memset(pbuf, 'c' + i, sizeof(pbuf));
247 T(SSL_write(serverssl, pbuf, sizeof(pbuf)) == sizeof(pbuf));
248 T(SSL_read(clientssl, lbuf, sizeof(lbuf)) == sizeof(lbuf));
249 T(memcmp(pbuf, lbuf, sizeof(pbuf)) == 0);
251 memset(lbuf, 's' + i, sizeof(lbuf));
252 T(SSL_write(clientssl, lbuf, sizeof(lbuf)) == sizeof(lbuf));
253 T(SSL_read(serverssl, pbuf, sizeof(pbuf)) == sizeof(pbuf));
254 T(memcmp(pbuf, lbuf, sizeof(pbuf)) == 0);
257 SSL_shutdown(clientssl);
258 SSL_shutdown(serverssl);
265 /* Every responsible process should free this. */
267 EVP_PKEY_free(ck.pkey);
271 int main(int argc, char **argv)
275 OPENSSL_add_all_algorithms_conf();
278 if ((p = getenv("VERBOSE")))
281 ret |= test("rsa", NULL);
282 cipher_list = "LEGACY-GOST2012-GOST8912-GOST8912";
283 ret |= test("gost2012_256", "A");
284 ret |= test("gost2012_256", "B");
285 ret |= test("gost2012_256", "C");
286 ret |= test("gost2012_256", "TCA");
287 ret |= test("gost2012_512", "A");
288 ret |= test("gost2012_512", "B");
289 ret |= test("gost2012_512", "C");
292 printf(cDRED "= Some tests FAILED!\n" cNORM);
294 printf(cDGREEN "= All tests passed!\n" cNORM);