]> jfr.im git - irc/rqf/shadowircd.git/blame - libratbox/src/openssl.c
Cope with OPENSSL_VERSION_NUMBER not being a long.
[irc/rqf/shadowircd.git] / libratbox / src / openssl.c
CommitLineData
b57f37fb
WP
1/*
2 * libratbox: a library used by ircd-ratbox and other things
3 * openssl.c: openssl related code
4 *
5 * Copyright (C) 2007-2008 ircd-ratbox development team
6 * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 *
b57f37fb
WP
23 */
24
25#include <libratbox_config.h>
26#include <ratbox_lib.h>
27
28#ifdef HAVE_OPENSSL
29
30#include <commio-int.h>
31#include <commio-ssl.h>
32#include <openssl/ssl.h>
33#include <openssl/dh.h>
34#include <openssl/err.h>
35#include <openssl/rand.h>
36
37static SSL_CTX *ssl_server_ctx;
38static SSL_CTX *ssl_client_ctx;
033be687 39static int libratbox_index = -1;
b57f37fb 40
94b4fbf9
VY
41static unsigned long
42get_last_err(void)
b57f37fb
WP
43{
44 unsigned long t_err, err = 0;
45 err = ERR_get_error();
46 if(err == 0)
47 return 0;
94b4fbf9 48
b57f37fb
WP
49 while((t_err = ERR_get_error()) > 0)
50 err = t_err;
51
52 return err;
53}
54
55void
94b4fbf9 56rb_ssl_shutdown(rb_fde_t *F)
b57f37fb
WP
57{
58 int i;
59 if(F == NULL || F->ssl == NULL)
60 return;
61 SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN);
62
94b4fbf9 63 for(i = 0; i < 4; i++)
b57f37fb
WP
64 {
65 if(SSL_shutdown((SSL *) F->ssl))
66 break;
67 }
68 get_last_err();
69 SSL_free((SSL *) F->ssl);
70}
71
033be687
VY
72unsigned int
73rb_ssl_handshake_count(rb_fde_t *F)
74{
75 return F->handshake_count;
76}
77
78void
79rb_ssl_clear_handshake_count(rb_fde_t *F)
80{
81 F->handshake_count = 0;
82}
83
b57f37fb 84static void
94b4fbf9 85rb_ssl_timeout(rb_fde_t *F, void *notused)
b57f37fb 86{
8f40f4bb
VY
87 lrb_assert(F->accept != NULL);
88 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
b57f37fb
WP
89}
90
91
94b4fbf9
VY
92static void
93rb_ssl_info_callback(SSL * ssl, int where, int ret)
033be687
VY
94{
95 if(where & SSL_CB_HANDSHAKE_START)
96 {
97 rb_fde_t *F = SSL_get_ex_data(ssl, libratbox_index);
98 if(F == NULL)
99 return;
100 F->handshake_count++;
94b4fbf9 101 }
033be687
VY
102}
103
104static void
105rb_setup_ssl_cb(rb_fde_t *F)
106{
107 SSL_set_ex_data(F->ssl, libratbox_index, (char *)F);
94b4fbf9 108 SSL_set_info_callback((SSL *) F->ssl, (void (*)(const SSL *,int,int))rb_ssl_info_callback);
033be687
VY
109}
110
b57f37fb 111static void
94b4fbf9 112rb_ssl_tryaccept(rb_fde_t *F, void *data)
b57f37fb
WP
113{
114 int ssl_err;
115 lrb_assert(F->accept != NULL);
8f40f4bb 116 int flags;
b68b0b2c 117 struct acceptdata *ad;
b57f37fb
WP
118
119 if(!SSL_is_init_finished((SSL *) F->ssl))
120 {
121 if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0)
122 {
123 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
124 {
b57f37fb
WP
125 case SSL_ERROR_WANT_READ:
126 case SSL_ERROR_WANT_WRITE:
8f40f4bb
VY
127 if(ssl_err == SSL_ERROR_WANT_WRITE)
128 flags = RB_SELECT_WRITE;
129 else
130 flags = RB_SELECT_READ;
131 F->ssl_errno = get_last_err();
132 rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
133 break;
134 case SSL_ERROR_SYSCALL:
135 F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data);
136 break;
b57f37fb
WP
137 default:
138 F->ssl_errno = get_last_err();
139 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
140 break;
141 }
142 return;
143 }
144 }
145 rb_settimeout(F, 0, NULL, NULL);
146 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
94b4fbf9 147
b68b0b2c 148 ad = F->accept;
b57f37fb 149 F->accept = NULL;
94b4fbf9 150 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
b68b0b2c 151 rb_free(ad);
b57f37fb
WP
152
153}
154
033be687
VY
155
156static void
157rb_ssl_accept_common(rb_fde_t *new_F)
b57f37fb
WP
158{
159 int ssl_err;
b57f37fb
WP
160 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
161 {
162 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
163 {
164 case SSL_ERROR_SYSCALL:
165 if(rb_ignore_errno(errno))
166 case SSL_ERROR_WANT_READ:
167 case SSL_ERROR_WANT_WRITE:
168 {
169 new_F->ssl_errno = get_last_err();
170 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
171 rb_ssl_tryaccept, NULL);
172 return;
173 }
174 default:
175 new_F->ssl_errno = get_last_err();
176 new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
177 return;
178 }
179 }
180 else
181 {
182 rb_ssl_tryaccept(new_F, NULL);
183 }
184}
185
033be687 186void
94b4fbf9 187rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout)
033be687
VY
188{
189 new_F->type |= RB_FD_SSL;
190 new_F->ssl = SSL_new(ssl_server_ctx);
191 new_F->accept = rb_malloc(sizeof(struct acceptdata));
192
193 new_F->accept->callback = cb;
194 new_F->accept->data = data;
195 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
196
197 new_F->accept->addrlen = 0;
198 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
199 rb_setup_ssl_cb(new_F);
200 rb_ssl_accept_common(new_F);
201}
202
b57f37fb
WP
203
204
205
206void
94b4fbf9 207rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
b57f37fb 208{
b57f37fb
WP
209 new_F->type |= RB_FD_SSL;
210 new_F->ssl = SSL_new(ssl_server_ctx);
211 new_F->accept = rb_malloc(sizeof(struct acceptdata));
212
213 new_F->accept->callback = F->accept->callback;
214 new_F->accept->data = F->accept->data;
215 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
216 memcpy(&new_F->accept->S, st, addrlen);
217 new_F->accept->addrlen = addrlen;
218
4414eb3c 219 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
033be687
VY
220 rb_setup_ssl_cb(new_F);
221 rb_ssl_accept_common(new_F);
b57f37fb
WP
222}
223
224static ssize_t
94b4fbf9 225rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
b57f37fb
WP
226{
227 ssize_t ret;
228 unsigned long err;
229 SSL *ssl = F->ssl;
230
231 if(r_or_w == 0)
94b4fbf9 232 ret = (ssize_t) SSL_read(ssl, rbuf, (int)count);
b57f37fb 233 else
94b4fbf9 234 ret = (ssize_t) SSL_write(ssl, wbuf, (int)count);
b57f37fb
WP
235
236 if(ret < 0)
237 {
238 switch (SSL_get_error(ssl, ret))
239 {
240 case SSL_ERROR_WANT_READ:
241 errno = EAGAIN;
242 return RB_RW_SSL_NEED_READ;
243 case SSL_ERROR_WANT_WRITE:
244 errno = EAGAIN;
245 return RB_RW_SSL_NEED_WRITE;
246 case SSL_ERROR_ZERO_RETURN:
247 return 0;
248 case SSL_ERROR_SYSCALL:
249 err = get_last_err();
250 if(err == 0)
251 {
252 F->ssl_errno = 0;
253 return RB_RW_IO_ERROR;
254 }
255 break;
256 default:
257 err = get_last_err();
258 break;
259 }
260 F->ssl_errno = err;
261 if(err > 0)
262 {
263 errno = EIO; /* not great but... */
264 return RB_RW_SSL_ERROR;
265 }
266 return RB_RW_IO_ERROR;
267 }
268 return ret;
269}
270
271ssize_t
94b4fbf9 272rb_ssl_read(rb_fde_t *F, void *buf, size_t count)
b57f37fb
WP
273{
274 return rb_ssl_read_or_write(0, F, buf, NULL, count);
275}
276
277ssize_t
94b4fbf9 278rb_ssl_write(rb_fde_t *F, const void *buf, size_t count)
b57f37fb
WP
279{
280 return rb_ssl_read_or_write(1, F, NULL, buf, count);
281}
282
a099270d
JT
283static int
284verify_accept_all_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
285{
286 return 1;
287}
288
57fe1cf1
JT
289static const char *
290get_ssl_error(unsigned long err)
291{
292 static char buf[512];
293
294 ERR_error_string_n(err, buf, sizeof buf);
295 return buf;
296}
297
b57f37fb
WP
298int
299rb_init_ssl(void)
300{
301 int ret = 1;
033be687 302 char libratbox_data[] = "libratbox data";
b57f37fb
WP
303 SSL_load_error_strings();
304 SSL_library_init();
033be687 305 libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL);
b57f37fb
WP
306 ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
307 if(ssl_server_ctx == NULL)
308 {
309 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
57fe1cf1 310 get_ssl_error(ERR_get_error()));
b57f37fb
WP
311 ret = 0;
312 }
313 /* Disable SSLv2, make the client use our settings */
314 SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
a099270d 315 SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
94b4fbf9 316
b57f37fb
WP
317 ssl_client_ctx = SSL_CTX_new(TLSv1_client_method());
318
319 if(ssl_client_ctx == NULL)
320 {
321 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
57fe1cf1 322 get_ssl_error(ERR_get_error()));
b57f37fb
WP
323 ret = 0;
324 }
325 return ret;
326}
327
328
329int
330rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
331{
b57f37fb
WP
332 DH *dh;
333 unsigned long err;
334 if(cert == NULL)
335 {
336 rb_lib_log("rb_setup_ssl_server: No certificate file");
337 return 0;
338 }
6ec1ddab 339 if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx, cert) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx, cert))
b57f37fb
WP
340 {
341 err = ERR_get_error();
342 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
57fe1cf1 343 get_ssl_error(err));
b57f37fb
WP
344 return 0;
345 }
346
347 if(keyfile == NULL)
348 {
349 rb_lib_log("rb_setup_ssl_server: No key file");
350 return 0;
351 }
352
353
6ec1ddab 354 if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile, SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(ssl_client_ctx, keyfile, SSL_FILETYPE_PEM))
b57f37fb
WP
355 {
356 err = ERR_get_error();
357 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
57fe1cf1 358 get_ssl_error(err));
b57f37fb
WP
359 return 0;
360 }
361
362 if(dhfile != NULL)
363 {
364 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
94b4fbf9
VY
365 BIO *bio = BIO_new_file(dhfile, "r");
366 if(bio != NULL)
b57f37fb 367 {
94b4fbf9 368 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
b57f37fb
WP
369 if(dh == NULL)
370 {
371 err = ERR_get_error();
372 rb_lib_log
373 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
57fe1cf1 374 dhfile, get_ssl_error(err));
94b4fbf9 375 BIO_free(bio);
b57f37fb
WP
376 return 0;
377 }
94b4fbf9 378 BIO_free(bio);
b57f37fb 379 SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
94b4fbf9
VY
380 }
381 else
382 {
383 err = ERR_get_error();
384 rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
57fe1cf1 385 dhfile, get_ssl_error(err));
b57f37fb
WP
386 }
387 }
388 return 1;
389}
390
391int
94b4fbf9 392rb_ssl_listen(rb_fde_t *F, int backlog)
b57f37fb
WP
393{
394 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
395 return listen(F->fd, backlog);
396}
397
398struct ssl_connect
399{
400 CNCB *callback;
401 void *data;
402 int timeout;
403};
404
405static void
94b4fbf9 406rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn)
b57f37fb
WP
407{
408 F->connect->callback = sconn->callback;
409 F->connect->data = sconn->data;
410 rb_free(sconn);
411 rb_connect_callback(F, status);
412}
413
414static void
94b4fbf9 415rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data)
b57f37fb
WP
416{
417 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
418}
419
420static void
94b4fbf9 421rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
b57f37fb
WP
422{
423 struct ssl_connect *sconn = data;
424 int ssl_err;
425 if(!SSL_is_init_finished((SSL *) F->ssl))
426 {
427 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
428 {
429 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
430 {
431 case SSL_ERROR_SYSCALL:
432 if(rb_ignore_errno(errno))
433 case SSL_ERROR_WANT_READ:
434 case SSL_ERROR_WANT_WRITE:
435 {
436 F->ssl_errno = get_last_err();
437 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
438 rb_ssl_tryconn_cb, sconn);
439 return;
440 }
441 default:
442 F->ssl_errno = get_last_err();
443 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
444 return;
445 }
446 }
447 else
448 {
449 rb_ssl_connect_realcb(F, RB_OK, sconn);
450 }
451 }
452}
453
454static void
94b4fbf9 455rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
b57f37fb
WP
456{
457 struct ssl_connect *sconn = data;
458 int ssl_err;
459 if(status != RB_OK)
460 {
461 rb_ssl_connect_realcb(F, status, sconn);
462 return;
463 }
464
465 F->type |= RB_FD_SSL;
466 F->ssl = SSL_new(ssl_client_ctx);
467 SSL_set_fd((SSL *) F->ssl, F->fd);
033be687 468 rb_setup_ssl_cb(F);
b57f37fb
WP
469 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
470 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
471 {
472 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
473 {
474 case SSL_ERROR_SYSCALL:
475 if(rb_ignore_errno(errno))
476 case SSL_ERROR_WANT_READ:
477 case SSL_ERROR_WANT_WRITE:
478 {
479 F->ssl_errno = get_last_err();
480 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
481 rb_ssl_tryconn_cb, sconn);
482 return;
483 }
484 default:
485 F->ssl_errno = get_last_err();
486 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
487 return;
488 }
489 }
490 else
491 {
492 rb_ssl_connect_realcb(F, RB_OK, sconn);
493 }
494}
495
496void
94b4fbf9 497rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
b57f37fb
WP
498 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
499{
500 struct ssl_connect *sconn;
501 if(F == NULL)
502 return;
503
504 sconn = rb_malloc(sizeof(struct ssl_connect));
505 sconn->data = data;
506 sconn->callback = callback;
507 sconn->timeout = timeout;
508 rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
509
510}
511
512void
94b4fbf9 513rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
b57f37fb
WP
514{
515 struct ssl_connect *sconn;
516 int ssl_err;
517 if(F == NULL)
518 return;
519
520 sconn = rb_malloc(sizeof(struct ssl_connect));
521 sconn->data = data;
522 sconn->callback = callback;
523 sconn->timeout = timeout;
524 F->connect = rb_malloc(sizeof(struct conndata));
525 F->connect->callback = callback;
526 F->connect->data = data;
527 F->type |= RB_FD_SSL;
528 F->ssl = SSL_new(ssl_client_ctx);
94b4fbf9 529
b57f37fb 530 SSL_set_fd((SSL *) F->ssl, F->fd);
033be687 531 rb_setup_ssl_cb(F);
b57f37fb
WP
532 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
533 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
534 {
535 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
536 {
537 case SSL_ERROR_SYSCALL:
538 if(rb_ignore_errno(errno))
539 case SSL_ERROR_WANT_READ:
540 case SSL_ERROR_WANT_WRITE:
541 {
542 F->ssl_errno = get_last_err();
543 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
544 rb_ssl_tryconn_cb, sconn);
545 return;
546 }
547 default:
548 F->ssl_errno = get_last_err();
549 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
550 return;
551 }
552 }
553 else
554 {
555 rb_ssl_connect_realcb(F, RB_OK, sconn);
556 }
557}
558
559int
560rb_init_prng(const char *path, prng_seed_t seed_type)
561{
562 if(seed_type == RB_PRNG_DEFAULT)
563 {
94b4fbf9 564#ifdef _WIN32
b57f37fb
WP
565 RAND_screen();
566#endif
567 return RAND_status();
568 }
569 if(path == NULL)
570 return RAND_status();
571
572 switch (seed_type)
573 {
574 case RB_PRNG_EGD:
575 if(RAND_egd(path) == -1)
576 return -1;
577 break;
578 case RB_PRNG_FILE:
579 if(RAND_load_file(path, -1) == -1)
580 return -1;
581 break;
94b4fbf9 582#ifdef _WIN32
b57f37fb
WP
583 case RB_PRNGWIN32:
584 RAND_screen();
585 break;
586#endif
587 default:
588 return -1;
589 }
590
591 return RAND_status();
592}
593
594int
595rb_get_random(void *buf, size_t length)
596{
4414eb3c 597 int ret;
94b4fbf9 598
4414eb3c 599 if((ret = RAND_bytes(buf, length)) == 0)
b57f37fb 600 {
4414eb3c 601 /* remove the error from the queue */
94b4fbf9 602 ERR_get_error();
b57f37fb 603 }
4414eb3c 604 return ret;
b57f37fb
WP
605}
606
4414eb3c
VY
607int
608rb_get_pseudo_random(void *buf, size_t length)
609{
610 int ret;
611 ret = RAND_pseudo_bytes(buf, length);
612 if(ret < 0)
613 return 0;
614 return 1;
615}
b57f37fb
WP
616
617const char *
94b4fbf9 618rb_get_ssl_strerror(rb_fde_t *F)
b57f37fb 619{
57fe1cf1 620 return get_ssl_error(F->ssl_errno);
b57f37fb
WP
621}
622
a099270d
JT
623int
624rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN])
625{
626 X509 *cert;
627 int res;
628
629 if (F->ssl == NULL)
630 return 0;
631
632 cert = SSL_get_peer_certificate((SSL *) F->ssl);
633 if(cert != NULL)
634 {
635 res = SSL_get_verify_result((SSL *) F->ssl);
636 if(res == X509_V_OK ||
637 res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
638 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
639 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
640 {
641 memcpy(certfp, cert->sha1_hash, RB_SSL_CERTFP_LEN);
642 return 1;
643 }
6af7e4fa 644 X509_free(cert);
a099270d
JT
645 }
646
647 return 0;
648}
649
b57f37fb
WP
650int
651rb_supports_ssl(void)
652{
653 return 1;
654}
655
f030cae8
VY
656void
657rb_get_ssl_info(char *buf, size_t len)
658{
659 rb_snprintf(buf, len, "Using SSL: %s compiled: 0x%lx, library 0x%lx",
8d5df4cb
JT
660 SSLeay_version(SSLEAY_VERSION),
661 (long)OPENSSL_VERSION_NUMBER, SSLeay());
f030cae8
VY
662}
663
664
b57f37fb 665#endif /* HAVE_OPESSL */