OpenSSL options min-version, max-version
[socat.git] / xio-openssl.c
blob0710f1d4c60b50d28b01ecc694d6c9feb884680a
1 /* source: xio-openssl.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the implementation of the openssl addresses */
7 #include "xiosysincludes.h"
8 #if WITH_OPENSSL /* make this address configure dependend */
9 #include <openssl/conf.h>
10 #include <openssl/x509v3.h>
12 #include "xioopen.h"
14 #include "xio-fd.h"
15 #include "xio-socket.h" /* _xioopen_connect() */
16 #include "xio-listen.h"
17 #include "xio-ipapp.h"
18 #include "xio-openssl.h"
20 /* the openssl library requires a file descriptor for external communications.
21 so our best effort is to provide any possible kind of un*x file descriptor
22 (not only tcp, but also pipes, stdin, files...)
23 for tcp we want to provide support for socks and proxy.
24 read and write functions must use the openssl crypt versions.
25 but currently only plain tcp4 is implemented.
28 /* Linux: "man 3 ssl" */
30 /* generate a simple openssl server for testing:
31 1) generate a private key
32 openssl genrsa -out server.key 1024
33 2) generate a self signed cert
34 openssl req -new -key server.key -x509 -days 3653 -out server.crt
35 enter fields...
36 3) generate the pem file
37 cat server.key server.crt >server.pem
38 openssl s_server (listens on 4433/tcp)
41 /* static declaration of ssl's open function */
42 static int xioopen_openssl_connect(int argc, const char *argv[], struct opt *opts,
43 int xioflags, xiofile_t *fd, unsigned groups,
44 int dummy1, int dummy2, int dummy3);
46 /* static declaration of ssl's open function */
47 static int xioopen_openssl_listen(int argc, const char *argv[], struct opt *opts,
48 int xioflags, xiofile_t *fd, unsigned groups,
49 int dummy1, int dummy2, int dummy3);
50 static int openssl_SSL_ERROR_SSL(int level, const char *funcname);
51 static int openssl_handle_peer_certificate(struct single *xfd,
52 const char *peername,
53 bool opt_ver,
54 int level);
55 static int xioSSL_set_fd(struct single *xfd, int level);
56 static int xioSSL_connect(struct single *xfd, const char *opt_commonname, bool opt_ver, int level);
57 static int openssl_delete_cert_info(void);
60 /* description record for ssl connect */
61 const struct addrdesc addr_openssl = {
62 "openssl", /* keyword for selecting this address type in xioopen calls
63 (canonical or main name) */
64 3, /* data flow directions this address supports on API layer:
65 1..read, 2..write, 3..both */
66 xioopen_openssl_connect, /* a function pointer used to "open" these addresses.*/
67 GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
68 You might have to specify a new group in xioopts.h */
69 0, /* an integer passed to xioopen_openssl; makes it possible to
70 use the same xioopen_openssl function for slightly different
71 address types. */
72 0, /* like previous argument */
73 0 /* like previous arguments, but pointer type.
74 No trailing comma or semicolon! */
75 HELP(":<host>:<port>") /* a text displayed from xio help function.
76 No trailing comma or semicolon!
77 only generates this text if WITH_HELP is != 0 */
78 } ;
80 #if WITH_LISTEN
81 /* description record for ssl listen */
82 const struct addrdesc addr_openssl_listen = {
83 "openssl-listen", /* keyword for selecting this address type in xioopen calls
84 (canonical or main name) */
85 3, /* data flow directions this address supports on API layer:
86 1..read, 2..write, 3..both */
87 xioopen_openssl_listen, /* a function pointer used to "open" these addresses.*/
88 GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to.
89 You might have to specify a new group in xioopts.h */
90 0, /* an integer passed to xioopen_openssl_listen; makes it possible to
91 use the same xioopen_openssl_listen function for slightly different
92 address types. */
93 0, /* like previous argument */
94 0 /* like previous arguments, but pointer type.
95 No trailing comma or semicolon! */
96 HELP(":<port>") /* a text displayed from xio help function.
97 No trailing comma or semicolon!
98 only generates this text if WITH_HELP is != 0 */
99 } ;
100 #endif /* WITH_LISTEN */
102 /* both client and server */
103 const struct optdesc opt_openssl_cipherlist = { "openssl-cipherlist", "ciphers", OPT_OPENSSL_CIPHERLIST, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC };
104 #if WITH_OPENSSL_METHOD
105 const struct optdesc opt_openssl_method = { "openssl-method", "method", OPT_OPENSSL_METHOD, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC };
106 #endif
107 #if HAVE_SSL_CTX_set_min_proto_version || defined(SSL_CTX_set_min_proto_version)
108 const struct optdesc opt_openssl_min_proto_version = { "openssl-min-proto-version", "min-version", OPT_OPENSSL_MIN_PROTO_VERSION, GROUP_OPENSSL, PH_INIT, TYPE_STRING, OFUNC_OFFSET, XIO_OFFSETOF(para.openssl.min_proto_version) };
109 #endif
110 #if HAVE_SSL_CTX_set_max_proto_version || defined(SSL_CTX_set_max_proto_version)
111 const struct optdesc opt_openssl_max_proto_version = { "openssl-max-proto-version", "max-version", OPT_OPENSSL_MAX_PROTO_VERSION, GROUP_OPENSSL, PH_INIT, TYPE_STRING, OFUNC_OFFSET, XIO_OFFSETOF(para.openssl.max_proto_version) };
112 #endif
113 const struct optdesc opt_openssl_verify = { "openssl-verify", "verify", OPT_OPENSSL_VERIFY, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC };
114 const struct optdesc opt_openssl_certificate = { "openssl-certificate", "cert", OPT_OPENSSL_CERTIFICATE, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC };
115 const struct optdesc opt_openssl_key = { "openssl-key", "key", OPT_OPENSSL_KEY, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC };
116 const struct optdesc opt_openssl_dhparam = { "openssl-dhparam", "dh", OPT_OPENSSL_DHPARAM, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC };
117 const struct optdesc opt_openssl_cafile = { "openssl-cafile", "cafile", OPT_OPENSSL_CAFILE, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC };
118 const struct optdesc opt_openssl_capath = { "openssl-capath", "capath", OPT_OPENSSL_CAPATH, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC };
119 const struct optdesc opt_openssl_egd = { "openssl-egd", "egd", OPT_OPENSSL_EGD, GROUP_OPENSSL, PH_SPEC, TYPE_FILENAME, OFUNC_SPEC };
120 const struct optdesc opt_openssl_pseudo = { "openssl-pseudo", "pseudo", OPT_OPENSSL_PSEUDO, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC };
121 #if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_COMP)
122 const struct optdesc opt_openssl_compress = { "openssl-compress", "compress", OPT_OPENSSL_COMPRESS, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC };
123 #endif
124 #if WITH_FIPS
125 const struct optdesc opt_openssl_fips = { "openssl-fips", "fips", OPT_OPENSSL_FIPS, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC };
126 #endif
127 const struct optdesc opt_openssl_commonname = { "openssl-commonname", "cn", OPT_OPENSSL_COMMONNAME, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC };
130 /* If FIPS is compiled in, we need to track if the user asked for FIPS mode.
131 * On forks, the FIPS mode must be reset by a disable, then enable since
132 * FIPS tracks the process ID that initializes things.
133 * If FIPS is not compiled in, no tracking variable is needed
134 * and we make the reset code compile out. This keeps the
135 * rest of the code below free of FIPS related #ifs
137 #if WITH_FIPS
138 static bool xio_openssl_fips = false;
139 int xio_reset_fips_mode(void) {
140 if (xio_openssl_fips) {
141 if(!sycFIPS_mode_set(0) || !sycFIPS_mode_set(1)) {
142 ERR_load_crypto_strings();
143 ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE));
144 Error("Failed to reset OpenSSL FIPS mode");
145 xio_openssl_fips = false;
146 return -1;
149 return 0;
151 #else
152 #define xio_reset_fips_mode() 0
153 #endif
155 static void openssl_conn_loginfo(SSL *ssl) {
156 const char *string;
158 string = SSL_get_cipher_version(ssl);
159 Notice1("SSL proto version used: %s", string);
160 xiosetenv("OPENSSL_PROTO_VERSION", string, 1, NULL);
162 string = SSL_get_cipher(ssl);
163 Notice1("SSL connection using %s", string);
164 xiosetenv("OPENSSL_CIPHER", string, 1, NULL);
166 #if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_COMP)
168 const COMP_METHOD *comp, *expansion;
170 comp = sycSSL_get_current_compression(ssl);
171 expansion = sycSSL_get_current_expansion(ssl);
173 Notice1("SSL connection compression \"%s\"",
174 comp?sycSSL_COMP_get_name(comp):"none");
175 Notice1("SSL connection expansion \"%s\"",
176 expansion?sycSSL_COMP_get_name(expansion):"none");
178 #endif
181 /* the open function for OpenSSL client */
182 static int
183 xioopen_openssl_connect(int argc,
184 const char *argv[], /* the arguments in the address string */
185 struct opt *opts,
186 int xioflags, /* is the open meant for reading (0),
187 writing (1), or both (2) ? */
188 xiofile_t *xxfd, /* a xio file descriptor structure,
189 already allocated */
190 unsigned groups, /* the matching address groups... */
191 int dummy1, /* first transparent integer value from
192 addr_openssl */
193 int dummy2, /* second transparent integer value from
194 addr_openssl */
195 int dummy3) /* transparent pointer value from
196 addr_openssl */
198 struct single *xfd = &xxfd->stream;
199 struct opt *opts0 = NULL;
200 const char *hostname, *portname;
201 int pf = PF_UNSPEC;
202 int ipproto = IPPROTO_TCP;
203 int socktype = SOCK_STREAM;
204 bool dofork = false;
205 union sockaddr_union us_sa, *us = &us_sa;
206 union sockaddr_union them_sa, *them = &them_sa;
207 socklen_t uslen = sizeof(us_sa);
208 socklen_t themlen = sizeof(them_sa);
209 bool needbind = false;
210 bool lowport = false;
211 int level;
212 SSL_CTX* ctx;
213 bool opt_ver = true; /* verify peer certificate */
214 char *opt_cert = NULL; /* file name of client certificate */
215 const char *opt_commonname = NULL; /* for checking peer certificate */
216 int result;
218 if (!(xioflags & XIO_MAYCONVERT)) {
219 Error("address with data processing not allowed here");
220 return STAT_NORETRY;
222 xfd->flags |= XIO_DOESCONVERT;
224 if (argc != 3) {
225 Error1("%s: 2 parameters required", argv[0]);
226 return STAT_NORETRY;
228 hostname = argv[1];
229 portname = argv[2];
230 if (hostname[0] == '\0') {
231 /* we catch this explicitely because empty commonname (peername) disables
232 commonName check of peer certificate */
233 Error1("%s: empty host name", argv[0]);
234 return STAT_NORETRY;
237 xfd->howtoend = END_SHUTDOWN;
238 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
239 applyopts(-1, opts, PH_INIT);
241 retropt_bool(opts, OPT_FORK, &dofork);
243 retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
244 retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
246 if (opt_commonname == NULL) {
247 opt_commonname = hostname;
250 result =
251 _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx);
252 if (result != STAT_OK) return STAT_NORETRY;
254 result =
255 _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
256 xfd->para.socket.ip.res_opts[1],
257 xfd->para.socket.ip.res_opts[0],
258 them, &themlen, us, &uslen,
259 &needbind, &lowport, socktype);
260 if (result != STAT_OK) return STAT_NORETRY;
262 if (xioopts.logopt == 'm') {
263 Info("starting connect loop, switching to syslog");
264 diag_set('y', xioopts.syslogfac); xioopts.logopt = 'y';
265 } else {
266 Info("starting connect loop");
269 do { /* loop over failed connect and SSL handshake attempts */
271 #if WITH_RETRY
272 if (xfd->forever || xfd->retry) {
273 level = E_INFO;
274 } else
275 #endif /* WITH_RETRY */
276 level = E_ERROR;
278 /* this cannot fork because we retrieved fork option above */
279 result =
280 _xioopen_connect(xfd,
281 needbind?(struct sockaddr *)us:NULL, uslen,
282 (struct sockaddr *)them, themlen,
283 opts, pf, socktype, ipproto, lowport, level);
284 switch (result) {
285 case STAT_OK: break;
286 #if WITH_RETRY
287 case STAT_RETRYLATER:
288 case STAT_RETRYNOW:
289 if (xfd->forever || xfd->retry) {
290 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
291 if (result == STAT_RETRYLATER) {
292 Nanosleep(&xfd->intervall, NULL);
294 --xfd->retry;
295 continue;
297 return STAT_NORETRY;
298 #endif /* WITH_RETRY */
299 default:
300 return result;
303 /*! isn't this too early? */
304 if ((result = _xio_openlate(xfd, opts)) < 0) {
305 return result;
308 result = _xioopen_openssl_connect(xfd, opt_ver, opt_commonname, ctx, level);
309 switch (result) {
310 case STAT_OK: break;
311 #if WITH_RETRY
312 case STAT_RETRYLATER:
313 case STAT_RETRYNOW:
314 if (xfd->forever || xfd->retry) {
315 Close(xfd->fd);
316 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
317 if (result == STAT_RETRYLATER) {
318 Nanosleep(&xfd->intervall, NULL);
320 --xfd->retry;
321 continue;
323 #endif /* WITH_RETRY */
324 default: return STAT_NORETRY;
327 if (dofork) {
328 xiosetchilddied(); /* set SIGCHLD handler */
331 #if WITH_RETRY
332 if (dofork) {
333 pid_t pid;
334 int level = E_ERROR;
335 if (xfd->forever || xfd->retry) {
336 level = E_WARN;
338 while ((pid = xio_fork(false, level)) < 0) {
339 if (xfd->forever || --xfd->retry) {
340 Nanosleep(&xfd->intervall, NULL); continue;
342 return STAT_RETRYLATER;
345 if (pid == 0) { /* child process */
346 xfd->forever = false; xfd->retry = 0;
347 break;
350 /* parent process */
351 Close(xfd->fd);
352 sycSSL_free(xfd->para.openssl.ssl);
353 xfd->para.openssl.ssl = NULL;
354 /* with and without retry */
355 Nanosleep(&xfd->intervall, NULL);
356 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
357 continue; /* with next socket() bind() connect() */
359 #endif /* WITH_RETRY */
360 break;
361 } while (true); /* drop out on success */
363 openssl_conn_loginfo(xfd->para.openssl.ssl);
365 /* fill in the fd structure */
366 return STAT_OK;
370 /* this function is typically called within the OpenSSL client fork/retry loop.
371 xfd must be of type DATA_OPENSSL, and its fd must be set with a valid file
372 descriptor. this function then performs all SSL related step to make a valid
373 SSL connection from an FD and a CTX. */
374 int _xioopen_openssl_connect(struct single *xfd,
375 bool opt_ver,
376 const char *opt_commonname,
377 SSL_CTX *ctx,
378 int level) {
379 SSL *ssl;
380 unsigned long err;
381 int result;
383 /* create a SSL object */
384 if ((ssl = sycSSL_new(ctx)) == NULL) {
385 if (ERR_peek_error() == 0) Msg(level, "SSL_new() failed");
386 while (err = ERR_get_error()) {
387 Msg1(level, "SSL_new(): %s", ERR_error_string(err, NULL));
389 /*Error("SSL_new()");*/
390 return STAT_RETRYLATER;
392 xfd->para.openssl.ssl = ssl;
394 result = xioSSL_set_fd(xfd, level);
395 if (result != STAT_OK) {
396 sycSSL_free(xfd->para.openssl.ssl);
397 xfd->para.openssl.ssl = NULL;
398 return result;
401 result = xioSSL_connect(xfd, opt_commonname, opt_ver, level);
402 if (result != STAT_OK) {
403 sycSSL_free(xfd->para.openssl.ssl);
404 xfd->para.openssl.ssl = NULL;
405 return result;
408 result = openssl_handle_peer_certificate(xfd, opt_commonname,
409 opt_ver, level);
410 if (result != STAT_OK) {
411 sycSSL_free(xfd->para.openssl.ssl);
412 xfd->para.openssl.ssl = NULL;
413 return result;
416 return STAT_OK;
420 #if WITH_LISTEN
422 static int
423 xioopen_openssl_listen(int argc,
424 const char *argv[], /* the arguments in the address string */
425 struct opt *opts,
426 int xioflags, /* is the open meant for reading (0),
427 writing (1), or both (2) ? */
428 xiofile_t *xxfd, /* a xio file descriptor structure,
429 already allocated */
430 unsigned groups, /* the matching address groups... */
431 int dummy1, /* first transparent integer value from
432 addr_openssl */
433 int dummy2, /* second transparent integer value from
434 addr_openssl */
435 int dummy3) /* transparent pointer value from
436 addr_openssl */
438 struct single *xfd = &xxfd->stream;
439 const char *portname;
440 struct opt *opts0 = NULL;
441 union sockaddr_union us_sa, *us = &us_sa;
442 socklen_t uslen = sizeof(us_sa);
443 int pf;
444 int socktype = SOCK_STREAM;
445 int ipproto = IPPROTO_TCP;
446 /*! lowport? */
447 int level;
448 SSL_CTX* ctx;
449 bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */
450 char *opt_cert = NULL; /* file name of server certificate */
451 const char *opt_commonname = NULL; /* for checking peer certificate */
452 int result;
454 if (!(xioflags & XIO_MAYCONVERT)) {
455 Error("address with data processing not allowed here");
456 return STAT_NORETRY;
458 xfd->flags |= XIO_DOESCONVERT;
460 if (argc != 2) {
461 Error1("%s: 1 parameter required", argv[0]);
462 return STAT_NORETRY;
465 #if WITH_IP4 && WITH_IP6
466 pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
467 #elif WITH_IP6
468 pf = PF_INET6;
469 #else
470 pf = PF_INET;
471 #endif
473 portname = argv[1];
475 xfd->howtoend = END_SHUTDOWN;
476 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
477 applyopts(-1, opts, PH_INIT);
479 retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
480 if (opt_cert == NULL) {
481 Warn("no certificate given; consider option \"cert\"");
484 retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
486 applyopts(-1, opts, PH_EARLY);
488 result =
489 _xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, &ctx);
490 if (result != STAT_OK) return STAT_NORETRY;
492 if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto,
493 xfd->para.socket.ip.res_opts[1],
494 xfd->para.socket.ip.res_opts[0],
495 us, &uslen, socktype)
496 != STAT_OK) {
497 return STAT_NORETRY;
500 xfd->addr = &addr_openssl_listen;
501 xfd->dtype = XIODATA_OPENSSL;
503 while (true) { /* loop over failed attempts */
505 #if WITH_RETRY
506 if (xfd->forever || xfd->retry) {
507 level = E_INFO;
508 } else
509 #endif /* WITH_RETRY */
510 level = E_ERROR;
512 /* tcp listen; this can fork() for us; it only returns on error or on
513 successful establishment of tcp connection */
514 result = _xioopen_listen(xfd, xioflags,
515 (struct sockaddr *)us, uslen,
516 opts, pf, socktype, IPPROTO_TCP,
517 #if WITH_RETRY
518 (xfd->retry||xfd->forever)?E_INFO:E_ERROR
519 #else
520 E_ERROR
521 #endif /* WITH_RETRY */
523 /*! not sure if we should try again on retry/forever */
524 switch (result) {
525 case STAT_OK: break;
526 #if WITH_RETRY
527 case STAT_RETRYLATER:
528 case STAT_RETRYNOW:
529 if (xfd->forever || xfd->retry) {
530 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
531 if (result == STAT_RETRYLATER) {
532 Nanosleep(&xfd->intervall, NULL);
534 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
535 --xfd->retry;
536 continue;
538 return STAT_NORETRY;
539 #endif /* WITH_RETRY */
540 default:
541 return result;
544 result = _xioopen_openssl_listen(xfd, opt_ver, opt_commonname, ctx, level);
545 switch (result) {
546 case STAT_OK: break;
547 #if WITH_RETRY
548 case STAT_RETRYLATER:
549 case STAT_RETRYNOW:
550 if (xfd->forever || xfd->retry) {
551 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
552 if (result == STAT_RETRYLATER) {
553 Nanosleep(&xfd->intervall, NULL);
555 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
556 --xfd->retry;
557 continue;
559 return STAT_NORETRY;
560 #endif /* WITH_RETRY */
561 default:
562 return result;
565 openssl_conn_loginfo(xfd->para.openssl.ssl);
566 break;
568 } /* drop out on success */
570 /* fill in the fd structure */
572 return STAT_OK;
576 int _xioopen_openssl_listen(struct single *xfd,
577 bool opt_ver,
578 const char *opt_commonname,
579 SSL_CTX *ctx,
580 int level) {
581 char error_string[120];
582 unsigned long err;
583 int errint, ret;
585 /* create an SSL object */
586 if ((xfd->para.openssl.ssl = sycSSL_new(ctx)) == NULL) {
587 if (ERR_peek_error() == 0) Msg(level, "SSL_new() failed");
588 while (err = ERR_get_error()) {
589 Msg1(level, "SSL_new(): %s", ERR_error_string(err, NULL));
591 /*Error("SSL_new()");*/
592 return STAT_NORETRY;
595 /* assign the network connection to the SSL object */
596 if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) {
597 if (ERR_peek_error() == 0) Msg(level, "SSL_set_fd() failed");
598 while (err = ERR_get_error()) {
599 Msg2(level, "SSL_set_fd(, %d): %s",
600 xfd->fd, ERR_error_string(err, NULL));
604 #if WITH_DEBUG
606 int i = 0;
607 const char *ciphers = NULL;
608 Debug("available ciphers:");
609 do {
610 ciphers = SSL_get_cipher_list(xfd->para.openssl.ssl, i);
611 if (ciphers == NULL) break;
612 Debug2("CIPHERS pri=%d: %s", i, ciphers);
613 ++i;
614 } while (1);
616 #endif /* WITH_DEBUG */
618 /* connect via SSL by performing handshake */
619 if ((ret = sycSSL_accept(xfd->para.openssl.ssl)) <= 0) {
620 /*if (ERR_peek_error() == 0) Msg(level, "SSL_accept() failed");*/
621 errint = SSL_get_error(xfd->para.openssl.ssl, ret);
622 switch (errint) {
623 case SSL_ERROR_NONE:
624 Msg(level, "ok"); break;
625 case SSL_ERROR_ZERO_RETURN:
626 Msg(level, "connection closed (wrong version number?)"); break;
627 case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE:
628 case SSL_ERROR_WANT_CONNECT:
629 case SSL_ERROR_WANT_X509_LOOKUP:
630 Msg(level, "nonblocking operation did not complete"); break; /*!*/
631 case SSL_ERROR_SYSCALL:
632 if (ERR_peek_error() == 0) {
633 if (ret == 0) {
634 Msg(level, "SSL_accept(): socket closed by peer");
635 } else if (ret == -1) {
636 Msg1(level, "SSL_accept(): %s", strerror(errno));
638 } else {
639 Msg(level, "I/O error"); /*!*/
640 while (err = ERR_get_error()) {
641 ERR_error_string_n(err, error_string, sizeof(error_string));
642 Msg4(level, "SSL_accept(): %s / %s / %s / %s", error_string,
643 ERR_lib_error_string(err), ERR_func_error_string(err),
644 ERR_reason_error_string(err));
646 /* Msg1(level, "SSL_accept(): %s", ERR_error_string(e, buf));*/
648 break;
649 case SSL_ERROR_SSL:
650 /*ERR_print_errors_fp(stderr);*/
651 openssl_SSL_ERROR_SSL(level, "SSL_accept");
652 break;
653 default:
654 Msg(level, "unknown error");
657 return STAT_RETRYLATER;
660 if (openssl_handle_peer_certificate(xfd, opt_commonname, opt_ver, E_ERROR/*!*/) < 0) {
661 return STAT_NORETRY;
664 return STAT_OK;
667 #endif /* WITH_LISTEN */
670 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
671 /* In OpenSSL 0.9.7 compression methods could be added using
672 * SSL_COMP_add_compression_method(3), but the implemntation is not compatible
673 * with the standard (RFC3749).
675 static int openssl_setup_compression(SSL_CTX *ctx, char *method)
677 STACK_OF(SSL_COMP)* comp_methods;
679 assert(method);
681 /* Getting the stack of compression methods has the intended side-effect of
682 * initializing the SSL library's compression part.
684 comp_methods = SSL_COMP_get_compression_methods();
685 if (!comp_methods) {
686 Info("OpenSSL built without compression support");
687 return STAT_OK;
690 if (strcasecmp(method, "auto") == 0) {
691 Info("Using default OpenSSL compression");
692 return STAT_OK;
695 if (strcasecmp(method, "none") == 0) {
696 /* Disable compression */
697 #ifdef SSL_OP_NO_COMPRESSION
698 Info("Disabling OpenSSL compression");
699 SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
700 #else
701 /* SSL_OP_NO_COMPRESSION was only introduced in OpenSSL 0.9.9 (released
702 * as 1.0.0). Removing all compression methods is a work-around for
703 * earlier versions of OpenSSL, but it affects all SSL connections.
705 Info("Disabling OpenSSL compression globally");
706 sk_SSL_COMP_zero(comp_methods);
707 #endif
708 return STAT_OK;
711 /* zlib compression in OpenSSL before version 0.9.8e-beta1 uses the libc's
712 * default malloc/free instead of the ones passed to OpenSSL. Should socat
713 * ever use custom malloc/free functions for OpenSSL, this must be taken
714 * into consideration. See OpenSSL bug #1468.
717 Error1("openssl-compress=\"%s\": unknown compression method", method);
718 return STAT_NORETRY;
720 #endif
723 #if HAVE_CTX_SSL_set_min_proto_version || defined(SSL_CTX_set_min_proto_version) || \
724 HAVE_SSL_CTX_set_max_proto_version || defined(SSL_CTX_set_max_proto_version)
725 #define XIO_OPENSSL_VERSIONGROUP_TLS 1
726 #define XIO_OPENSSL_VERSIONGROUP_DTLS 2
728 static struct wordent _xio_openssl_versions[] = {
729 #ifdef DTLS1_VERSION
730 { "DTLS1", (void *)DTLS1_VERSION },
731 { "DTLS1.0", (void *)DTLS1_VERSION },
732 #endif
733 #ifdef DTLS1_2_VERSION
734 { "DTLS1.2", (void *)DTLS1_2_VERSION },
735 #endif
736 #ifdef DTLS1_VERSION
737 { "DTLSv1", (void *)DTLS1_VERSION },
738 { "DTLSv1.0", (void *)DTLS1_VERSION },
739 #endif
740 #ifdef DTLS1_2_VERSION
741 { "DTLSv1.2", (void *)DTLS1_2_VERSION },
742 #endif
743 #ifdef SSL2_VERSION
744 { "SSL2", (void *)SSL2_VERSION },
745 #endif
746 #ifdef SSL3_VERSION
747 { "SSL3", (void *)SSL3_VERSION },
748 #endif
749 #ifdef SSL2_VERSION
750 { "SSLv2", (void *)SSL2_VERSION },
751 #endif
752 #ifdef SSL3_VERSION
753 { "SSLv3", (void *)SSL3_VERSION },
754 #endif
755 #ifdef TLS1_VERSION
756 { "TLS1", (void *)TLS1_VERSION },
757 { "TLS1.0", (void *)TLS1_VERSION },
758 #endif
759 #ifdef TLS1_1_VERSION
760 { "TLS1.1", (void *)TLS1_1_VERSION },
761 #endif
762 #ifdef TLS1_2_VERSION
763 { "TLS1.2", (void *)TLS1_2_VERSION },
764 #endif
765 #ifdef TLS1_3_VERSION
766 { "TLS1.3", (void *)TLS1_3_VERSION },
767 #endif
768 #ifdef TLS1_VERSION
769 { "TLSv1", (void *)TLS1_VERSION },
770 { "TLSv1.0", (void *)TLS1_VERSION },
771 #endif
772 #ifdef TLS1_1_VERSION
773 { "TLSv1.1", (void *)TLS1_1_VERSION },
774 #endif
775 #ifdef TLS1_2_VERSION
776 { "TLSv1.2", (void *)TLS1_2_VERSION },
777 #endif
778 #ifdef TLS1_3_VERSION
779 { "TLSv1.3", (void *)TLS1_3_VERSION },
780 #endif
783 static int _xio_openssl_parse_version(const char *verstring, int vergroups) {
784 int sslver;
785 const struct wordent *we;
786 we = keyw(_xio_openssl_versions, verstring,
787 sizeof(_xio_openssl_versions)/sizeof(struct wordent));
788 if (we == 0) {
789 Error1("Unknown SSL/TLS version \"%s\"", verstring);
790 return -1;
792 sslver = (size_t)we->desc;
793 switch (sslver) {
794 #ifdef SSL2_VERSION
795 case SSL2_VERSION:
796 #endif
797 #ifdef SSL3_VERSION
798 case SSL3_VERSION:
799 #endif
800 #ifdef TLS1_VERSION
801 case TLS1_VERSION:
802 #endif
803 #ifdef TLS1_1_VERSION
804 case TLS1_1_VERSION:
805 #endif
806 #ifdef TLS1_2_VERSION
807 case TLS1_2_VERSION:
808 #endif
809 #ifdef TLS1_3_VERSION
810 case TLS1_3_VERSION:
811 #endif
812 if (!(vergroups & XIO_OPENSSL_VERSIONGROUP_TLS)) {
813 Error1("Wrong type of TLS/DTLS version \"%s\"", verstring);
814 return -1;
816 #ifdef DTLS1_VERSION
817 case DTLS1_VERSION:
818 #endif
819 #ifdef DTLS1_2_VERSION
820 case DTLS1_2_VERSION:
821 #endif
822 if (!(vergroups & XIO_OPENSSL_VERSIONGROUP_DTLS)) {
823 Error1("Wrong type of TLS/DTLS version \"%s\"", verstring);
824 return -1;
826 break;
828 return sslver;
830 #endif /* defined(SSL_CTX_set_min_proto_version) || defined(SSL_CTX_set_max_proto_version) */
834 _xioopen_openssl_prepare(struct opt *opts,
835 struct single *xfd,/* a xio file descriptor
836 structure, already allocated
838 bool server, /* SSL client: false */
839 bool *opt_ver,
840 const char *opt_cert,
841 SSL_CTX **ctxp)
843 SSL_CTX *ctx;
844 bool opt_fips = false;
845 const SSL_METHOD *method = NULL;
846 char *me_str = NULL; /* method string */
847 char *ci_str = "HIGH:-NULL:-PSK:-aNULL"; /* cipher string */
848 char *opt_key = NULL; /* file name of client private key */
849 char *opt_dhparam = NULL; /* file name of DH params */
850 char *opt_cafile = NULL; /* certificate authority file */
851 char *opt_capath = NULL; /* certificate authority directory */
852 char *opt_egd = NULL; /* entropy gathering daemon socket path */
853 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
854 char *opt_compress = NULL; /* compression method */
855 #endif
856 bool opt_pseudo = false; /* use pseudo entropy if nothing else */
857 unsigned long err;
858 int result;
860 xfd->addr = &addr_openssl;
861 xfd->dtype = XIODATA_OPENSSL;
863 retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips);
864 retropt_string(opts, OPT_OPENSSL_METHOD, &me_str);
865 retropt_string(opts, OPT_OPENSSL_CIPHERLIST, &ci_str);
866 retropt_bool(opts, OPT_OPENSSL_VERIFY, opt_ver);
867 retropt_string(opts, OPT_OPENSSL_CAFILE, &opt_cafile);
868 retropt_string(opts, OPT_OPENSSL_CAPATH, &opt_capath);
869 retropt_string(opts, OPT_OPENSSL_KEY, &opt_key);
870 retropt_string(opts, OPT_OPENSSL_DHPARAM, &opt_dhparam);
871 retropt_string(opts, OPT_OPENSSL_EGD, &opt_egd);
872 retropt_bool(opts,OPT_OPENSSL_PSEUDO, &opt_pseudo);
873 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
874 retropt_string(opts, OPT_OPENSSL_COMPRESS, &opt_compress);
875 #endif
876 #if WITH_FIPS
877 if (opt_fips) {
878 if (!sycFIPS_mode_set(1)) {
879 ERR_load_crypto_strings();
880 ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE));
881 Error("Failed to set FIPS mode");
882 } else {
883 xio_openssl_fips = true;
886 #endif
888 openssl_delete_cert_info();
890 OpenSSL_add_all_algorithms();
891 OpenSSL_add_all_ciphers();
892 OpenSSL_add_all_digests();
893 sycSSL_load_error_strings();
895 /* OpenSSL preparation */
896 sycSSL_library_init();
898 /*! actions_to_seed_PRNG();*/
900 if (!server) {
901 if (me_str != NULL) {
902 if (false) {
903 ; /* for canonical reasons */
904 #if HAVE_SSLv2_client_method
905 } else if (!strcasecmp(me_str, "SSL2")) {
906 method = sycSSLv2_client_method();
907 #endif
908 #if HAVE_SSLv3_client_method
909 } else if (!strcasecmp(me_str, "SSL3")) {
910 method = sycSSLv3_client_method();
911 #endif
912 #if HAVE_SSLv23_client_method
913 } else if (!strcasecmp(me_str, "SSL23")) {
914 method = sycSSLv23_client_method();
915 #endif
916 #if HAVE_TLSv1_client_method
917 } else if (!strcasecmp(me_str, "TLS1") || !strcasecmp(me_str, "TLS1.0")) {
918 method = sycTLSv1_client_method();
919 #endif
920 #if HAVE_TLSv1_1_client_method
921 } else if (!strcasecmp(me_str, "TLS1.1")) {
922 method = sycTLSv1_1_client_method();
923 #endif
924 #if HAVE_TLSv1_2_client_method
925 } else if (!strcasecmp(me_str, "TLS1.2")) {
926 method = sycTLSv1_2_client_method();
927 #endif
928 #if HAVE_DTLSv1_client_method
929 } else if (!strcasecmp(me_str, "DTLS") || !strcasecmp(me_str, "DTLS1")) {
930 method = sycDTLSv1_client_method();
931 #endif
932 } else {
933 Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str);
935 } else {
936 #if HAVE_TLS_client_method
937 method = TLS_client_method();
938 #elif HAVE_SSLv23_client_method
939 method = sycSSLv23_client_method();
940 #elif HAVE_TLSv1_2_client_method
941 method = sycTLSv1_2_client_method();
942 #elif HAVE_TLSv1_1_client_method
943 method = sycTLSv1_1_client_method();
944 #elif HAVE_TLSv1_client_method
945 method = sycTLSv1_client_method();
946 #elif HAVE_SSLv3_client_method
947 method = sycSSLv3_client_method();
948 #elif HAVE_SSLv2_client_method
949 method = sycSSLv2_client_method();
950 #else
951 # error "OpenSSL does not seem to provide client methods"
952 #endif
954 } else /* server */ {
955 if (me_str != 0) {
956 if (false) {
957 ; /* for canonical reasons */
958 #if HAVE_SSLv2_server_method
959 } else if (!strcasecmp(me_str, "SSL2")) {
960 method = sycSSLv2_server_method();
961 #endif
962 #if HAVE_SSLv3_server_method
963 } else if (!strcasecmp(me_str, "SSL3")) {
964 method = sycSSLv3_server_method();
965 #endif
966 #if HAVE_SSLv23_server_method
967 } else if (!strcasecmp(me_str, "SSL23")) {
968 method = sycSSLv23_server_method();
969 #endif
970 #if HAVE_TLSv1_server_method
971 } else if (!strcasecmp(me_str, "TLS1") || !strcasecmp(me_str, "TLS1.0")) {
972 method = sycTLSv1_server_method();
973 #endif
974 #if HAVE_TLSv1_1_server_method
975 } else if (!strcasecmp(me_str, "TLS1.1")) {
976 method = sycTLSv1_1_server_method();
977 #endif
978 #if HAVE_TLSv1_2_server_method
979 } else if (!strcasecmp(me_str, "TLS1.2")) {
980 method = sycTLSv1_2_server_method();
981 #endif
982 #if HAVE_DTLSv1_server_method
983 } else if (!strcasecmp(me_str, "DTLS") || !strcasecmp(me_str, "DTLS1")) {
984 method = sycDTLSv1_server_method();
985 #endif
986 } else {
987 Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str);
989 } else {
990 #if HAVE_TLS_server_method
991 method = TLS_server_method();
992 #elif HAVE_SSLv23_server_method
993 method = sycSSLv23_server_method();
994 #elif HAVE_TLSv1_2_server_method
995 method = sycTLSv1_2_server_method();
996 #elif HAVE_TLSv1_1_server_method
997 method = sycTLSv1_1_server_method();
998 #elif HAVE_TLSv1_server_method
999 method = sycTLSv1_server_method();
1000 #elif HAVE_SSLv3_server_method
1001 method = sycSSLv3_server_method();
1002 #elif HAVE_SSLv2_server_method
1003 method = sycSSLv2_server_method();
1004 #else
1005 # error "OpenSSL does not seem to provide client methods"
1006 #endif
1010 if (opt_egd) {
1011 #if !defined(OPENSSL_NO_EGD) && HAVE_RAND_egd
1012 sycRAND_egd(opt_egd);
1013 #else
1014 Debug("RAND_egd() is not available by OpenSSL");
1015 #endif
1018 if (opt_pseudo) {
1019 long int randdata;
1020 /* initialize libc random from actual microseconds */
1021 struct timeval tv;
1022 struct timezone tz;
1023 tz.tz_minuteswest = 0;
1024 tz.tz_dsttime = 0;
1025 if ((result = Gettimeofday(&tv, &tz)) < 0) {
1026 Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
1028 srandom(tv.tv_sec*1000000+tv.tv_usec);
1030 while (!RAND_status()) {
1031 randdata = random();
1032 Debug2("RAND_seed(0x{%lx}, "F_Zu")",
1033 randdata, sizeof(randdata));
1034 RAND_seed(&randdata, sizeof(randdata));
1038 if ((ctx = sycSSL_CTX_new(method)) == NULL) {
1039 if (ERR_peek_error() == 0) Error("SSL_CTX_new()");
1040 while (err = ERR_get_error()) {
1041 Error1("SSL_CTX_new(): %s", ERR_error_string(err, NULL));
1044 /*ERR_clear_error;*/
1045 return STAT_RETRYLATER;
1047 xfd->para.openssl.ctx = ctx;
1048 *ctxp = ctx;
1050 #if HAVE_SSL_CTX_set_min_proto_version || defined(SSL_CTX_set_min_proto_version)
1051 if (xfd->para.openssl.min_proto_version != NULL) {
1052 int sslver, rc;
1053 sslver = _xio_openssl_parse_version(xfd->para.openssl.min_proto_version,
1054 XIO_OPENSSL_VERSIONGROUP_TLS|XIO_OPENSSL_VERSIONGROUP_DTLS);
1055 if (sslver < 0)
1056 return STAT_NORETRY;
1057 if ((rc = SSL_CTX_set_min_proto_version(ctx, sslver)) <= 0) {
1058 Debug1("version: %d", SSL_CTX_get_min_proto_version(ctx));
1059 Error3("_xioopen_openssl_prepare(): SSL_CTX_set_min_proto_version(\"%s\"->%d): failed (%d)",
1060 xfd->para.openssl.min_proto_version, sslver, rc);
1061 return STAT_NORETRY;
1063 Debug1("version: %d", SSL_CTX_get_min_proto_version(ctx));
1065 #endif /* HAVE_SSL_set_min_proto_version || defined(SSL_set_min_proto_version) */
1066 #if HAVE_SSL_CTX_set_max_proto_version || defined(SSL_CTX_set_max_proto_version)
1067 if (xfd->para.openssl.max_proto_version != NULL) {
1068 int sslver;
1069 sslver = _xio_openssl_parse_version(xfd->para.openssl.max_proto_version,
1070 XIO_OPENSSL_VERSIONGROUP_TLS|XIO_OPENSSL_VERSIONGROUP_DTLS);
1071 if (sslver < 0)
1072 return STAT_NORETRY;
1073 if (SSL_CTX_set_max_proto_version(ctx, sslver) <= 0) {
1074 Error2("_xioopen_openssl_prepare(): SSL_CTX_set_max_proto_version(\"%s\"->%d): failed",
1075 xfd->para.openssl.max_proto_version, sslver);
1076 return STAT_NORETRY;
1079 #endif /* HAVE_SSL_set_max_proto_version || defined(SSL_set_max_proto_version) */
1082 static unsigned char dh2048_p[] = {
1083 0x00,0xdc,0x21,0x64,0x56,0xbd,0x9c,0xb2,0xac,0xbe,0xc9,0x98,0xef,0x95,0x3e,
1084 0x26,0xfa,0xb5,0x57,0xbc,0xd9,0xe6,0x75,0xc0,0x43,0xa2,0x1c,0x7a,0x85,0xdf,
1085 0x34,0xab,0x57,0xa8,0xf6,0xbc,0xf6,0x84,0x7d,0x05,0x69,0x04,0x83,0x4c,0xd5,
1086 0x56,0xd3,0x85,0x09,0x0a,0x08,0xff,0xb5,0x37,0xa1,0xa3,0x8a,0x37,0x04,0x46,
1087 0xd2,0x93,0x31,0x96,0xf4,0xe4,0x0d,0x9f,0xbd,0x3e,0x7f,0x9e,0x4d,0xaf,0x08,
1088 0xe2,0xe8,0x03,0x94,0x73,0xc4,0xdc,0x06,0x87,0xbb,0x6d,0xae,0x66,0x2d,0x18,
1089 0x1f,0xd8,0x47,0x06,0x5c,0xcf,0x8a,0xb5,0x00,0x51,0x57,0x9b,0xea,0x1e,0xd8,
1090 0xdb,0x8e,0x3c,0x1f,0xd3,0x2f,0xba,0x1f,0x5f,0x3d,0x15,0xc1,0x3b,0x2c,0x82,
1091 0x42,0xc8,0x8c,0x87,0x79,0x5b,0x38,0x86,0x3a,0xeb,0xfd,0x81,0xa9,0xba,0xf7,
1092 0x26,0x5b,0x93,0xc5,0x3e,0x03,0x30,0x4b,0x00,0x5c,0xb6,0x23,0x3e,0xea,0x94,
1093 0xc3,0xb4,0x71,0xc7,0x6e,0x64,0x3b,0xf8,0x92,0x65,0xad,0x60,0x6c,0xd4,0x7b,
1094 0xa9,0x67,0x26,0x04,0xa8,0x0a,0xb2,0x06,0xeb,0xe0,0x7d,0x90,0xdd,0xdd,0xf5,
1095 0xcf,0xb4,0x11,0x7c,0xab,0xc1,0xa3,0x84,0xbe,0x27,0x77,0xc7,0xde,0x20,0x57,
1096 0x66,0x47,0xa7,0x35,0xfe,0x0d,0x6a,0x1c,0x52,0xb8,0x58,0xbf,0x26,0x33,0x81,
1097 0x5e,0xb7,0xa9,0xc0,0xee,0x58,0x11,0x74,0x86,0x19,0x08,0x89,0x1c,0x37,0x0d,
1098 0x52,0x47,0x70,0x75,0x8b,0xa8,0x8b,0x30,0x11,0x71,0x36,0x62,0xf0,0x73,0x41,
1099 0xee,0x34,0x9d,0x0a,0x2b,0x67,0x4e,0x6a,0xa3,0xe2,0x99,0x92,0x1b,0xf5,0x32,
1100 0x73,0x63
1102 static unsigned char dh2048_g[] = {
1103 0x02,
1105 DH *dh;
1106 BIGNUM *p = NULL, *g = NULL;
1107 unsigned long err;
1109 dh = DH_new();
1110 p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
1111 g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
1112 if (!dh || !p || !g) {
1113 if (dh)
1114 DH_free(dh);
1115 if (p)
1116 BN_free(p);
1117 if (g)
1118 BN_free(g);
1119 while (err = ERR_get_error()) {
1120 Warn1("dh2048 setup(): %s",
1121 ERR_error_string(err, NULL));
1123 Error("dh2048 setup failed");
1124 goto cont_out;
1126 #if HAVE_DH_set0_pqg
1127 if (!DH_set0_pqg(dh, p, NULL, g)) {
1128 DH_free(dh);
1129 BN_free(p);
1130 BN_free(g);
1131 goto cont_out;
1133 #else
1134 dh->p = p;
1135 dh->g = g;
1136 #endif /* HAVE_DH_set0_pqg */
1137 if (sycSSL_CTX_set_tmp_dh(ctx, dh) <= 0) {
1138 while (err = ERR_get_error()) {
1139 Warn3("SSL_CTX_set_tmp_dh(%p, %p): %s", ctx, dh,
1140 ERR_error_string(err, NULL));
1142 Error2("SSL_CTX_set_tmp_dh(%p, %p) failed", ctx, dh);
1144 /* p & g are freed by DH_free() once attached */
1145 DH_free(dh);
1146 cont_out:
1150 #if HAVE_TYPE_EC_KEY /* not on Openindiana 5.11 */
1152 /* see http://openssl.6102.n7.nabble.com/Problem-with-cipher-suite-ECDHE-ECDSA-AES256-SHA384-td42229.html */
1153 int nid;
1154 EC_KEY *ecdh;
1156 #if 0
1157 nid = OBJ_sn2nid(ECDHE_CURVE);
1158 if (nid == NID_undef) {
1159 Error("openssl: failed to set ECDHE parameters");
1160 return -1;
1162 #endif
1163 nid = NID_X9_62_prime256v1;
1164 ecdh = EC_KEY_new_by_curve_name(nid);
1165 if (NULL == ecdh) {
1166 Error("openssl: failed to set ECDHE parameters");
1167 return -1;
1170 SSL_CTX_set_tmp_ecdh(ctx, ecdh);
1172 #endif /* HAVE_TYPE_EC_KEY */
1174 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
1175 if (opt_compress) {
1176 int result;
1177 result = openssl_setup_compression(ctx, opt_compress);
1178 if (result != STAT_OK) {
1179 return result;
1182 #endif
1184 #if defined(HAVE_SSL_CTX_clear_mode) || defined(SSL_CTX_clear_mode)
1185 /* It seems that OpenSSL-1.1.1 presets the mode differently.
1186 Without correction socat might hang in SSL_read() */
1188 long mode = 0;
1189 mode = SSL_CTX_get_mode(ctx);
1190 if (mode & SSL_MODE_AUTO_RETRY) {
1191 Info("SSL_CTX mode has SSL_MODE_AUTO_RETRY set. Correcting..");
1192 Debug1("SSL_CTX_clean_mode(%p, SSL_MODE_AUTO_RETRY)", ctx);
1193 SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
1196 #endif /* defined(HAVE_SSL_CTX_clear_mode) || defined(SSL_CTX_clear_mode) */
1198 if (opt_cafile != NULL || opt_capath != NULL) {
1199 if (sycSSL_CTX_load_verify_locations(ctx, opt_cafile, opt_capath) != 1) {
1200 int result;
1202 if ((result =
1203 openssl_SSL_ERROR_SSL(E_ERROR, "SSL_CTX_load_verify_locations"))
1204 != STAT_OK) {
1205 /*! free ctx */
1206 return STAT_RETRYLATER;
1209 #ifdef HAVE_SSL_CTX_set_default_verify_paths
1210 } else {
1211 SSL_CTX_set_default_verify_paths(ctx);
1212 #endif
1215 if (opt_cert) {
1216 BIO *bio;
1217 DH *dh;
1219 if (sycSSL_CTX_use_certificate_chain_file(ctx, opt_cert) <= 0) {
1220 /*! trace functions */
1221 /*0 ERR_print_errors_fp(stderr);*/
1222 if (ERR_peek_error() == 0)
1223 Error2("SSL_CTX_use_certificate_file(%p, \"%s\", SSL_FILETYPE_PEM) failed",
1224 ctx, opt_cert);
1225 while (err = ERR_get_error()) {
1226 Error1("SSL_CTX_use_certificate_file(): %s",
1227 ERR_error_string(err, NULL));
1229 return STAT_RETRYLATER;
1232 if (sycSSL_CTX_use_PrivateKey_file(ctx, opt_key?opt_key:opt_cert, SSL_FILETYPE_PEM) <= 0) {
1233 /*ERR_print_errors_fp(stderr);*/
1234 openssl_SSL_ERROR_SSL(E_ERROR/*!*/, "SSL_CTX_use_PrivateKey_file");
1235 return STAT_RETRYLATER;
1238 if (opt_dhparam == NULL) {
1239 opt_dhparam = (char *)opt_cert;
1241 if ((bio = sycBIO_new_file(opt_dhparam, "r")) == NULL) {
1242 Warn2("BIO_new_file(\"%s\", \"r\"): %s",
1243 opt_dhparam, strerror(errno));
1244 } else {
1245 if ((dh = sycPEM_read_bio_DHparams(bio, NULL, NULL, NULL)) == NULL) {
1246 Info1("PEM_read_bio_DHparams(%p, NULL, NULL, NULL): error", bio);
1247 } else {
1248 BIO_free(bio);
1249 if (sycSSL_CTX_set_tmp_dh(ctx, dh) <= 0) {
1250 while (err = ERR_get_error()) {
1251 Warn3("SSL_CTX_set_tmp_dh(%p, %p): %s", ctx, dh,
1252 ERR_error_string(err, NULL));
1254 Error2("SSL_CTX_set_tmp_dh(%p, %p): error", ctx, dh);
1260 /* set pre openssl-connect options */
1261 /* SSL_CIPHERS */
1262 if (ci_str != NULL) {
1263 if (sycSSL_CTX_set_cipher_list(ctx, ci_str) <= 0) {
1264 if (ERR_peek_error() == 0)
1265 Error1("SSL_set_cipher_list(, \"%s\") failed", ci_str);
1266 while (err = ERR_get_error()) {
1267 Error2("SSL_set_cipher_list(, \"%s\"): %s",
1268 ci_str, ERR_error_string(err, NULL));
1270 /*Error("SSL_new()");*/
1271 return STAT_RETRYLATER;
1275 if (*opt_ver) {
1276 sycSSL_CTX_set_verify(ctx,
1277 SSL_VERIFY_PEER| SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1278 NULL);
1279 } else {
1280 sycSSL_CTX_set_verify(ctx,
1281 SSL_VERIFY_NONE,
1282 NULL);
1285 return STAT_OK;
1289 /* analyses an OpenSSL error condition, prints the appropriate messages with
1290 severity 'level' and returns one of STAT_OK, STAT_RETRYLATER, or
1291 STAT_NORETRY */
1292 static int openssl_SSL_ERROR_SSL(int level, const char *funcname) {
1293 unsigned long e;
1294 char buf[120]; /* this value demanded by "man ERR_error_string" */
1295 int stat = STAT_OK;
1297 while (e = ERR_get_error()) {
1298 Debug1("ERR_get_error(): %lx", e);
1301 #if defined(OPENSSL_IS_BORINGSSL)
1302 0 /* BoringSSL's RNG always succeeds. */
1303 #elif defined(HAVE_RAND_status)
1304 ERR_GET_LIB(e) == ERR_LIB_RAND && RAND_status() != 1
1305 #else
1306 e == ((ERR_LIB_RAND<<24)|
1307 #if defined(RAND_F_RAND_BYTES)
1308 (RAND_F_RAND_BYTES<<12)|
1309 #else
1310 (RAND_F_SSLEAY_RAND_BYTES<<12)|
1311 #endif
1312 (RAND_R_PRNG_NOT_SEEDED)) /*0x24064064*/
1313 #endif
1316 Error("too few entropy; use options \"egd\" or \"pseudo\"");
1317 stat = STAT_NORETRY;
1318 } else {
1319 Msg2(level, "%s(): %s", funcname, ERR_error_string(e, buf));
1320 stat = level==E_ERROR ? STAT_NORETRY : STAT_RETRYLATER;
1323 return stat;
1326 static const char *openssl_verify_messages[] = {
1327 /* 0 */ "ok",
1328 /* 1 */ NULL,
1329 /* 2 */ "unable to get issuer certificate",
1330 /* 3 */ "unable to get certificate CRL",
1331 /* 4 */ "unable to decrypt certificate's signature",
1332 /* 5 */ "unable to decrypt CRL's signature",
1333 /* 6 */ "unable to decode issuer public key",
1334 /* 7 */ "certificate signature failure",
1335 /* 8 */ "CRL signature failure",
1336 /* 9 */ "certificate is not yet valid",
1337 /* 10 */ "certificate has expired",
1338 /* 11 */ "CRL is not yet valid",
1339 /* 12 */ "CRL has expired",
1340 /* 13 */ "format error in certificate's notBefore field",
1341 /* 14 */ "format error in certificate's notAfter field",
1342 /* 15 */ "format error in CRL's lastUpdate field",
1343 /* 16 */ "format error in CRL's nextUpdate field",
1344 /* 17 */ "out of memory",
1345 /* 18 */ "self signed certificate",
1346 /* 19 */ "self signed certificate in certificate chain",
1347 /* 20 */ "unable to get local issuer certificate",
1348 /* 21 */ "unable to verify the first certificate",
1349 /* 22 */ "certificate chain too long",
1350 /* 23 */ "certificate revoked",
1351 /* 24 */ "invalid CA certificate",
1352 /* 25 */ "path length constraint exceeded",
1353 /* 26 */ "unsupported certificate purpose",
1354 /* 27 */ "certificate not trusted",
1355 /* 28 */ "certificate rejected",
1356 /* 29 */ "subject issuer mismatch",
1357 /* 30 */ "authority and subject key identifier mismatch",
1358 /* 31 */ "authority and issuer serial number mismatch",
1359 /* 32 */ "key usage does not include certificate signing",
1360 /* 33 */ NULL,
1361 /* 34 */ NULL,
1362 /* 35 */ NULL,
1363 /* 36 */ NULL,
1364 /* 37 */ NULL,
1365 /* 38 */ NULL,
1366 /* 39 */ NULL,
1367 /* 40 */ NULL,
1368 /* 41 */ NULL,
1369 /* 42 */ NULL,
1370 /* 43 */ NULL,
1371 /* 44 */ NULL,
1372 /* 45 */ NULL,
1373 /* 46 */ NULL,
1374 /* 47 */ NULL,
1375 /* 48 */ NULL,
1376 /* 49 */ NULL,
1377 /* 50 */ "application verification failure",
1381 /* delete all environment variables whose name begins with SOCAT_OPENSSL_
1382 resp. <progname>_OPENSSL_ */
1383 static int openssl_delete_cert_info(void) {
1384 # define XIO_ENVNAMELEN 256
1385 const char *progname;
1386 char envprefix[XIO_ENVNAMELEN];
1387 char envname[XIO_ENVNAMELEN];
1388 size_t i, l;
1389 const char **entry;
1391 progname = diag_get_string('p');
1392 envprefix[0] = '\0'; strncat(envprefix, progname, XIO_ENVNAMELEN-1);
1393 l = strlen(envprefix);
1394 for (i = 0; i < l; ++i) envprefix[i] = toupper(envprefix[i]);
1395 strncat(envprefix+l, "_OPENSSL_", XIO_ENVNAMELEN-l-1);
1397 #if HAVE_VAR_ENVIRON
1398 entry = (const char **)environ;
1399 while (*entry != NULL) {
1400 if (!strncmp(*entry, envprefix, strlen(envprefix))) {
1401 const char *eq = strchr(*entry, '=');
1402 if (eq == NULL) eq = *entry + strlen(*entry);
1403 envname[0] = '\0'; strncat(envname, *entry, eq-*entry);
1404 #if HAVE_UNSETENV
1405 Unsetenv(envname);
1406 #endif
1407 } else {
1408 ++entry;
1411 #endif /* HAVE_VAR_ENVIRON */
1412 return 0;
1415 /* read in the "name" information (from field "issuer" or "subject") and
1416 create environment variable with complete info, eg:
1417 SOCAT_OPENSSL_X509_SUBJECT */
1418 static int openssl_setenv_cert_name(const char *field, X509_NAME *name) {
1419 BIO *bio = BIO_new(BIO_s_mem());
1420 char *buf = NULL, *str;
1421 size_t len;
1422 X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE&~ASN1_STRFLGS_ESC_MSB); /* rc not documented */
1423 len = BIO_get_mem_data (bio, &buf);
1424 if ((str = Malloc(len+1)) == NULL) {
1425 BIO_free(bio);
1426 return -1;
1428 memcpy(str, buf, len);
1429 str[len] = '\0';
1430 Info2("SSL peer cert %s: \"%s\"", field, buf);
1431 xiosetenv2("OPENSSL_X509", field, str, 1, NULL);
1432 free(str);
1433 BIO_free(bio);
1434 return 0;
1437 /* read in the "name" information (from field "issuer" or "subject") and
1438 create environment variables with the fields, eg:
1439 SOCAT_OPENSSL_X509_COMMONNAME
1441 static int openssl_setenv_cert_fields(const char *field, X509_NAME *name) {
1442 int n, i;
1443 n = X509_NAME_entry_count(name);
1444 /* extract fields of cert name */
1445 for (i = 0; i < n; ++i) {
1446 X509_NAME_ENTRY *entry;
1447 ASN1_OBJECT *obj;
1448 ASN1_STRING *data;
1449 const unsigned char *text;
1450 int nid;
1451 entry = X509_NAME_get_entry(name, i);
1452 obj = X509_NAME_ENTRY_get_object(entry);
1453 data = X509_NAME_ENTRY_get_data(entry);
1454 nid = OBJ_obj2nid(obj);
1455 #if HAVE_ASN1_STRING_get0_data
1456 text = ASN1_STRING_get0_data(data);
1457 #else
1458 text = ASN1_STRING_data(data);
1459 #endif
1460 Debug3("SSL peer cert %s entry: %s=\"%s\"", (field[0]?field:"subject"), OBJ_nid2ln(nid), text);
1461 if (field != NULL && field[0] != '\0') {
1462 xiosetenv3("OPENSSL_X509", field, OBJ_nid2ln(nid), (const char *)text, 2, " // ");
1463 } else {
1464 xiosetenv2("OPENSSL_X509", OBJ_nid2ln(nid), (const char *)text, 2, " // ");
1467 return 0;
1470 /* compares the peername used/provided by the client to cn as extracted from
1471 the peer certificate.
1472 supports wildcard cn like *.domain which matches domain and
1473 host.domain
1474 returns true on match */
1475 static bool openssl_check_name(const char *cn, const char *peername) {
1476 const char *dotp;
1477 if (peername == NULL) {
1478 Info1("commonName \"%s\": no peername", cn);
1479 return false;
1480 } else if (peername[0] == '\0') {
1481 Info1("commonName \"%s\": matched by empty peername", cn);
1482 return true;
1484 if (! (cn[0] == '*' && cn[1] == '.')) {
1485 /* normal server name - this is simple */
1486 Debug1("commonName \"%s\" has no wildcard", cn);
1487 if (strcmp(cn, peername) == 0) {
1488 Debug2("commonName \"%s\" matches peername \"%s\"", cn, peername);
1489 return true;
1490 } else {
1491 Info2("commonName \"%s\" does not match peername \"%s\"", cn, peername);
1492 return false;
1495 /* wildcard cert */
1496 Debug1("commonName \"%s\" is a wildcard name", cn);
1497 /* case: just the base domain */
1498 if (strcmp(cn+2, peername) == 0) {
1499 Debug2("wildcard commonName \"%s\" matches base domain \"%s\"", cn, peername);
1500 return true;
1502 /* case: subdomain; only one level! */
1503 dotp = strchr(peername, '.');
1504 if (dotp == NULL) {
1505 Info2("peername \"%s\" is not a subdomain, thus is not matched by wildcard commonName \"%s\"",
1506 peername, cn);
1507 return false;
1509 if (strcmp(cn+1, dotp) != 0) {
1510 Info2("commonName \"%s\" does not match subdomain peername \"%s\"", cn, peername);
1511 return false;
1513 Debug2("commonName \"%s\" matches subdomain peername \"%s\"", cn, peername);
1514 return true;
1517 /* retrieves the commonName field and compares it to the peername
1518 returns true on match, false otherwise */
1519 static bool openssl_check_peername(X509_NAME *name, const char *peername) {
1520 int ind = -1;
1521 X509_NAME_ENTRY *entry;
1522 ASN1_STRING *data;
1523 const unsigned char *text;
1524 ind = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
1525 if (ind < 0) {
1526 Info("no COMMONNAME field in peer certificate");
1527 return false;
1529 entry = X509_NAME_get_entry(name, ind);
1530 data = X509_NAME_ENTRY_get_data(entry);
1531 #if HAVE_ASN1_STRING_get0_data
1532 text = ASN1_STRING_get0_data(data);
1533 #else
1534 text = ASN1_STRING_data(data);
1535 #endif
1536 return openssl_check_name((const char *)text, peername);
1539 /* retrieves certificate provided by peer, sets env vars containing
1540 certificates field values, and checks peername if provided by
1541 calling function */
1542 /* parts of this code were copied from Gene Spaffords C/C++ Secure Programming at Etutorials.org:
1543 http://etutorials.org/Programming/secure+programming/Chapter+10.+Public+Key+Infrastructure/10.8+Adding+Hostname+Checking+to+Certificate+Verification/
1544 The code examples in this tutorial do not seem to have explicit license restrictions.
1546 static int openssl_handle_peer_certificate(struct single *xfd,
1547 const char *peername,
1548 bool opt_ver, int level) {
1549 X509 *peer_cert;
1550 X509_NAME *subjectname, *issuername;
1551 /*ASN1_TIME not_before, not_after;*/
1552 int extcount, i, ok = 0;
1553 int status;
1555 if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) == NULL) {
1556 if (opt_ver) {
1557 Msg(level, "no peer certificate");
1558 status = STAT_RETRYLATER;
1559 } else {
1560 Notice("no peer certificate and no check");
1561 status = STAT_OK;
1563 return status;
1566 /* verify peer certificate (trust, signature, validity dates) */
1567 if (opt_ver) {
1568 long verify_result;
1569 if ((verify_result = sycSSL_get_verify_result(xfd->para.openssl.ssl)) != X509_V_OK) {
1570 const char *message = NULL;
1571 if (verify_result >= 0 &&
1572 (size_t)verify_result <
1573 sizeof(openssl_verify_messages)/sizeof(char*)) {
1574 message = openssl_verify_messages[verify_result];
1576 if (message) {
1577 Msg1(level, "%s", message);
1578 } else {
1579 Msg1(level, "rejected peer certificate with error %ld", verify_result);
1581 status = STAT_RETRYLATER;
1582 X509_free(peer_cert);
1583 return STAT_RETRYLATER;
1585 Info("peer certificate is trusted");
1588 /* set env vars from cert's subject and issuer values */
1589 if ((subjectname = X509_get_subject_name(peer_cert)) != NULL) {
1590 openssl_setenv_cert_name("subject", subjectname);
1591 openssl_setenv_cert_fields("", subjectname);
1592 /*! I'd like to provide dates too; see
1593 http://markmail.org/message/yi4vspp7aeu3xwtu#query:+page:1+mid:jhnl4wklif3pgzqf+state:results */
1595 if ((issuername = X509_get_issuer_name(peer_cert)) != NULL) {
1596 openssl_setenv_cert_name("issuer", issuername);
1599 /* check peername against cert's subjectAltName DNS entries */
1600 /* this code is based on example from Gerhard Gappmeier in
1601 http://openssl.6102.n7.nabble.com/How-to-extract-subjectAltName-td17236.html
1603 if ((extcount = X509_get_ext_count(peer_cert)) > 0) {
1604 for (i = 0; !ok && i < extcount; ++i) {
1605 const char *extstr;
1606 X509_EXTENSION *ext;
1607 const X509V3_EXT_METHOD *meth;
1608 ext = X509_get_ext(peer_cert, i);
1609 extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
1610 if (!strcasecmp(extstr, "subjectAltName")) {
1611 void *names;
1612 if (!(meth = X509V3_EXT_get(ext))) break;
1613 names = X509_get_ext_d2i(peer_cert, NID_subject_alt_name, NULL, NULL);
1614 if (names) {
1615 int numalts;
1616 int i;
1618 /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */
1619 numalts = sk_GENERAL_NAME_num ( names );
1620 /* loop through all alternatives */
1621 for ( i=0; ( i<numalts ); i++ ) {
1622 /* get a handle to alternative name number i */
1623 const GENERAL_NAME *pName = sk_GENERAL_NAME_value (names, i );
1624 unsigned char *pBuffer;
1625 switch ( pName->type ) {
1627 case GEN_DNS:
1628 ASN1_STRING_to_UTF8(&pBuffer,
1629 pName->d.ia5);
1630 xiosetenv("OPENSSL_X509V3_SUBJECTALTNAME_DNS", (char *)pBuffer, 2, " // ");
1631 if (peername != NULL &&
1632 openssl_check_name((char *)pBuffer, /*const char*/peername)) {
1633 ok = 1;
1635 OPENSSL_free(pBuffer);
1636 break;
1638 default: continue;
1646 if (!opt_ver) {
1647 Notice("option openssl-verify disabled, no check of certificate");
1648 X509_free(peer_cert);
1649 return STAT_OK;
1651 if (peername == NULL || peername[0] == '\0') {
1652 Notice("trusting certificate, no check of commonName");
1653 X509_free(peer_cert);
1654 return STAT_OK;
1656 if (ok) {
1657 Notice("trusting certificate, commonName matches");
1658 X509_free(peer_cert);
1659 return STAT_OK;
1662 /* here: all envs set; opt_ver, cert verified, no subjAltName match -> check subject CN */
1663 if (!openssl_check_peername(/*X509_NAME*/subjectname, /*const char*/peername)) {
1664 Error("certificate is valid but its commonName does not match hostname");
1665 status = STAT_NORETRY;
1666 } else {
1667 Notice("trusting certificate, commonName matches");
1668 status = STAT_OK;
1670 X509_free(peer_cert);
1671 return status;
1674 static int xioSSL_set_fd(struct single *xfd, int level) {
1675 unsigned long err;
1677 /* assign a network connection to the SSL object */
1678 if (sycSSL_set_fd(xfd->para.openssl.ssl, xfd->fd) <= 0) {
1679 Msg(level, "SSL_set_fd() failed");
1680 while (err = ERR_get_error()) {
1681 Msg2(level, "SSL_set_fd(, %d): %s",
1682 xfd->fd, ERR_error_string(err, NULL));
1684 return STAT_RETRYLATER;
1686 return STAT_OK;
1690 /* ...
1691 in case of an error condition, this function check forever and retry
1692 options and ev. sleeps an interval. It returns NORETRY when the caller
1693 should not retry for any reason. */
1694 static int xioSSL_connect(struct single *xfd, const char *opt_commonname,
1695 bool opt_ver, int level) {
1696 char error_string[120];
1697 int errint, status, ret;
1698 unsigned long err;
1700 /* connect via SSL by performing handshake */
1701 if ((ret = sycSSL_connect(xfd->para.openssl.ssl)) <= 0) {
1702 /*if (ERR_peek_error() == 0) Msg(level, "SSL_connect() failed");*/
1703 errint = SSL_get_error(xfd->para.openssl.ssl, ret);
1704 switch (errint) {
1705 case SSL_ERROR_NONE:
1706 /* this is not an error, but I dare not continue for security reasons*/
1707 Msg(level, "ok");
1708 status = STAT_RETRYLATER;
1709 case SSL_ERROR_ZERO_RETURN:
1710 Msg(level, "connection closed (wrong version number?)");
1711 status = STAT_RETRYLATER;
1712 break;
1713 case SSL_ERROR_WANT_READ:
1714 case SSL_ERROR_WANT_WRITE:
1715 case SSL_ERROR_WANT_CONNECT:
1716 case SSL_ERROR_WANT_X509_LOOKUP:
1717 Msg(level, "nonblocking operation did not complete");
1718 status = STAT_RETRYLATER;
1719 break; /*!*/
1720 case SSL_ERROR_SYSCALL:
1721 if (ERR_peek_error() == 0) {
1722 if (ret == 0) {
1723 Msg(level, "SSL_connect(): socket closed by peer");
1724 } else if (ret == -1) {
1725 Msg1(level, "SSL_connect(): %s", strerror(errno));
1727 } else {
1728 Msg(level, "I/O error"); /*!*/
1729 while (err = ERR_get_error()) {
1730 ERR_error_string_n(err, error_string, sizeof(error_string));
1731 Msg4(level, "SSL_connect(): %s / %s / %s / %s", error_string,
1732 ERR_lib_error_string(err), ERR_func_error_string(err),
1733 ERR_reason_error_string(err));
1736 status = STAT_RETRYLATER;
1737 break;
1738 case SSL_ERROR_SSL:
1739 status = openssl_SSL_ERROR_SSL(level, "SSL_connect");
1740 if (openssl_handle_peer_certificate(xfd, opt_commonname, opt_ver, level/*!*/) < 0) {
1741 return STAT_RETRYLATER;
1743 break;
1744 default:
1745 Msg(level, "unknown error");
1746 status = STAT_RETRYLATER;
1747 break;
1749 return status;
1751 return STAT_OK;
1754 /* on result < 0: errno is set (at least to EIO) */
1755 ssize_t xioread_openssl(struct single *pipe, void *buff, size_t bufsiz) {
1756 unsigned long err;
1757 char error_string[120];
1758 int _errno = EIO; /* if we have no better idea about nature of error */
1759 int errint, ret;
1761 ret = sycSSL_read(pipe->para.openssl.ssl, buff, bufsiz);
1762 if (ret < 0) {
1763 errint = SSL_get_error(pipe->para.openssl.ssl, ret);
1764 switch (errint) {
1765 case SSL_ERROR_NONE:
1766 /* this is not an error, but I dare not continue for security reasons*/
1767 Error("ok");
1768 break;
1769 case SSL_ERROR_ZERO_RETURN:
1770 Error("connection closed by peer");
1771 break;
1772 case SSL_ERROR_WANT_READ:
1773 case SSL_ERROR_WANT_WRITE:
1774 case SSL_ERROR_WANT_CONNECT:
1775 case SSL_ERROR_WANT_X509_LOOKUP:
1776 Info("nonblocking operation did not complete");
1777 errno = EAGAIN;
1778 return -1;
1779 case SSL_ERROR_SYSCALL:
1780 if (ERR_peek_error() == 0) {
1781 if (ret == 0) {
1782 Error("SSL_read(): socket closed by peer");
1783 } else if (ret == -1) {
1784 _errno = errno;
1785 Error1("SSL_read(): %s", strerror(errno));
1787 } else {
1788 Error("I/O error"); /*!*/
1789 while (err = ERR_get_error()) {
1790 ERR_error_string_n(err, error_string, sizeof(error_string));
1791 Error4("SSL_read(): %s / %s / %s / %s", error_string,
1792 ERR_lib_error_string(err), ERR_func_error_string(err),
1793 ERR_reason_error_string(err));
1796 break;
1797 case SSL_ERROR_SSL:
1798 openssl_SSL_ERROR_SSL(E_ERROR, "SSL_connect");
1799 break;
1800 default:
1801 Error("unknown error");
1802 break;
1804 errno = _errno;
1805 return -1;
1807 return ret;
1810 ssize_t xiopending_openssl(struct single *pipe) {
1811 int bytes = sycSSL_pending(pipe->para.openssl.ssl);
1812 return bytes;
1815 /* on result < 0: errno is set (at least to EIO) */
1816 ssize_t xiowrite_openssl(struct single *pipe, const void *buff, size_t bufsiz) {
1817 unsigned long err;
1818 char error_string[120];
1819 int _errno = EIO; /* if we have no better idea about nature of error */
1820 int errint, ret;
1822 ret = sycSSL_write(pipe->para.openssl.ssl, buff, bufsiz);
1823 if (ret < 0) {
1824 errint = SSL_get_error(pipe->para.openssl.ssl, ret);
1825 switch (errint) {
1826 case SSL_ERROR_NONE:
1827 /* this is not an error, but I dare not continue for security reasons*/
1828 Error("ok");
1829 case SSL_ERROR_ZERO_RETURN:
1830 Error("connection closed by peer");
1831 break;
1832 case SSL_ERROR_WANT_READ:
1833 case SSL_ERROR_WANT_WRITE:
1834 case SSL_ERROR_WANT_CONNECT:
1835 case SSL_ERROR_WANT_X509_LOOKUP:
1836 Error("nonblocking operation did not complete");
1837 break; /*!*/
1838 case SSL_ERROR_SYSCALL:
1839 if (ERR_peek_error() == 0) {
1840 if (ret == 0) {
1841 Error("SSL_write(): socket closed by peer");
1842 } else if (ret == -1) {
1843 _errno = errno;
1844 Error1("SSL_write(): %s", strerror(errno));
1846 } else {
1847 Error("I/O error"); /*!*/
1848 while (err = ERR_get_error()) {
1849 ERR_error_string_n(err, error_string, sizeof(error_string));
1850 Error4("SSL_write(): %s / %s / %s / %s", error_string,
1851 ERR_lib_error_string(err), ERR_func_error_string(err),
1852 ERR_reason_error_string(err));
1855 break;
1856 case SSL_ERROR_SSL:
1857 openssl_SSL_ERROR_SSL(E_ERROR, "SSL_connect");
1858 break;
1859 default:
1860 Error("unknown error");
1861 break;
1863 errno = _errno;
1864 return -1;
1866 return ret;
1870 #endif /* WITH_OPENSSL */