Compiling fix for OpenSSL 0.9.7 and older.
1 /* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
10 #include "ssl-proxy.h"
18 #include <openssl/crypto.h>
19 #include <openssl/x509.h>
20 #include <openssl/pem.h>
21 #include <openssl/ssl.h>
22 #include <openssl/err.h>
23 #include <openssl/rand.h>
25 #define DOVECOT_SSL_DEFAULT_CIPHER_LIST "ALL:!LOW:!SSLv2"
26 /* Check every 30 minutes if parameters file has been updated */
27 #define SSL_PARAMFILE_CHECK_INTERVAL (60*30)
38 struct ssl_proxy *prev, *next;
44 struct io *io_ssl_read, *io_ssl_write, *io_plain_read, *io_plain_write;
46 unsigned char plainout_buf[1024];
47 unsigned int plainout_size;
49 unsigned char sslout_buf[1024];
50 unsigned int sslout_size;
52 ssl_handshake_callback_t *handshake_callback;
53 void *handshake_context;
56 unsigned int handshaked:1;
57 unsigned int destroyed:1;
58 unsigned int cert_received:1;
59 unsigned int cert_broken:1;
60 unsigned int client:1;
63 struct ssl_parameters {
65 time_t last_mtime, last_check;
71 static int extdata_index;
72 static SSL_CTX *ssl_server_ctx;
73 static SSL_CTX *ssl_client_ctx;
74 static unsigned int ssl_proxy_count;
75 static struct ssl_proxy *ssl_proxies;
76 static struct ssl_parameters ssl_params;
77 static int ssl_username_nid;
79 static void plain_read(struct ssl_proxy *proxy);
80 static void ssl_read(struct ssl_proxy *proxy);
81 static void ssl_write(struct ssl_proxy *proxy);
82 static void ssl_step(struct ssl_proxy *proxy);
83 static void ssl_proxy_destroy(struct ssl_proxy *proxy);
84 static void ssl_proxy_unref(struct ssl_proxy *proxy);
86 static void ssl_params_corrupted(const char *path)
88 i_fatal("Corrupted SSL parameters file: %s/%s "
89 "(delete it and also the one in %s)",
90 getenv("LOGIN_DIR"), path, PKG_STATEDIR);
93 static void read_next(struct ssl_parameters *params, void *data, size_t size)
97 if ((ret = read_full(params->fd, data, size)) < 0)
98 i_fatal("read(%s) failed: %m", params->fname);
100 ssl_params_corrupted(params->fname);
103 static bool read_dh_parameters_next(struct ssl_parameters *params)
106 const unsigned char *cbuf;
110 /* read bit size. 0 ends the DH parameters list. */
111 read_next(params, &bits, sizeof(bits));
116 /* read data size. */
117 read_next(params, &len, sizeof(len));
118 if (len > 1024*100) /* should be enough? */
119 ssl_params_corrupted(params->fname);
122 read_next(params, buf, len);
127 params->dh_512 = d2i_DHparams(NULL, &cbuf, len);
130 params->dh_1024 = d2i_DHparams(NULL, &cbuf, len);
133 ssl_params_corrupted(params->fname);
140 static void ssl_free_parameters(struct ssl_parameters *params)
142 if (params->dh_512 != NULL) {
143 DH_free(params->dh_512);
144 params->dh_512 = NULL;
146 if (params->dh_1024 != NULL) {
147 DH_free(params->dh_1024);
148 params->dh_1024 = NULL;
152 static void ssl_read_parameters(struct ssl_parameters *params)
159 /* we'll wait until parameter file exists */
161 params->fd = open(params->fname, O_RDONLY);
162 if (params->fd != -1)
165 if (errno != ENOENT) {
166 i_fatal("Can't open SSL parameter file %s: %m",
171 i_warning("Waiting for SSL parameter file %s",
178 if (fstat(params->fd, &st) < 0)
179 i_error("fstat(%s) failed: %m", params->fname);
181 params->last_mtime = st.st_mtime;
183 ssl_free_parameters(params);
184 while (read_dh_parameters_next(params)) ;
186 if ((ret = read_full(params->fd, &c, 1)) < 0)
187 i_fatal("read(%s) failed: %m", params->fname);
189 /* more data than expected */
190 ssl_params_corrupted(params->fname);
193 if (close(params->fd) < 0)
194 i_error("close() failed: %m");
198 static void ssl_refresh_parameters(struct ssl_parameters *params)
202 if (params->last_check > ioloop_time - SSL_PARAMFILE_CHECK_INTERVAL)
204 params->last_check = ioloop_time;
206 if (params->last_mtime == 0)
207 ssl_read_parameters(params);
209 if (stat(params->fname, &st) < 0)
210 i_error("stat(%s) failed: %m", params->fname);
211 else if (st.st_mtime != params->last_mtime)
212 ssl_read_parameters(params);
216 static void ssl_set_io(struct ssl_proxy *proxy, enum ssl_io_action action)
220 if (proxy->io_ssl_read != NULL)
222 proxy->io_ssl_read = io_add(proxy->fd_ssl, IO_READ,
225 case SSL_REMOVE_INPUT:
226 if (proxy->io_ssl_read != NULL)
227 io_remove(&proxy->io_ssl_read);
230 if (proxy->io_ssl_write != NULL)
232 proxy->io_ssl_write = io_add(proxy->fd_ssl, IO_WRITE,
235 case SSL_REMOVE_OUTPUT:
236 if (proxy->io_ssl_write != NULL)
237 io_remove(&proxy->io_ssl_write);
242 static void plain_block_input(struct ssl_proxy *proxy, bool block)
245 if (proxy->io_plain_read != NULL)
246 io_remove(&proxy->io_plain_read);
248 if (proxy->io_plain_read == NULL) {
249 proxy->io_plain_read = io_add(proxy->fd_plain, IO_READ,
255 static void plain_read(struct ssl_proxy *proxy)
260 if (proxy->sslout_size == sizeof(proxy->sslout_buf)) {
261 /* buffer full, block input until it's written */
262 plain_block_input(proxy, TRUE);
268 while (proxy->sslout_size < sizeof(proxy->sslout_buf) &&
270 ret = net_receive(proxy->fd_plain,
271 proxy->sslout_buf + proxy->sslout_size,
272 sizeof(proxy->sslout_buf) -
276 ssl_proxy_destroy(proxy);
279 proxy->sslout_size += ret;
281 net_set_cork(proxy->fd_ssl, TRUE);
289 net_set_cork(proxy->fd_ssl, FALSE);
291 ssl_proxy_unref(proxy);
294 static void plain_write(struct ssl_proxy *proxy)
300 ret = net_transmit(proxy->fd_plain, proxy->plainout_buf,
301 proxy->plainout_size);
303 ssl_proxy_destroy(proxy);
305 proxy->plainout_size -= ret;
306 memmove(proxy->plainout_buf, proxy->plainout_buf + ret,
307 proxy->plainout_size);
309 if (proxy->plainout_size > 0) {
310 if (proxy->io_plain_write == NULL) {
311 proxy->io_plain_write =
312 io_add(proxy->fd_plain, IO_WRITE,
316 if (proxy->io_plain_write != NULL)
317 io_remove(&proxy->io_plain_write);
320 ssl_set_io(proxy, SSL_ADD_INPUT);
321 if (SSL_pending(proxy->ssl) > 0)
325 ssl_proxy_unref(proxy);
328 static const char *ssl_last_error(void)
332 size_t err_size = 256;
334 err = ERR_get_error();
337 return strerror(errno);
338 return "Unknown error";
341 buf = t_malloc(err_size);
342 buf[err_size-1] = '\0';
343 ERR_error_string_n(err, buf, err_size-1);
347 static void ssl_handle_error(struct ssl_proxy *proxy, int ret,
348 const char *func_name)
350 const char *errstr = NULL;
355 i_free_and_null(proxy->last_error);
356 err = SSL_get_error(proxy->ssl, ret);
359 case SSL_ERROR_WANT_READ:
360 ssl_set_io(proxy, SSL_ADD_INPUT);
362 case SSL_ERROR_WANT_WRITE:
363 ssl_set_io(proxy, SSL_ADD_OUTPUT);
365 case SSL_ERROR_SYSCALL:
366 /* eat up the error queue */
367 if (ERR_peek_error() != 0)
368 errstr = ssl_last_error();
370 errstr = strerror(errno);
373 errstr = "Disconnected";
376 errstr = t_strdup_printf("%s syscall failed: %s",
379 case SSL_ERROR_ZERO_RETURN:
380 /* clean connection closing */
381 ssl_proxy_destroy(proxy);
384 if (ERR_GET_REASON(ERR_peek_error()) == ERR_R_MALLOC_FAILURE) {
385 i_error("OpenSSL malloc() failed. "
386 "You may need to increase login_process_size");
388 errstr = t_strdup_printf("%s failed: %s",
389 func_name, ssl_last_error());
392 errstr = t_strdup_printf("%s failed: unknown failure %d (%s)",
393 func_name, err, ssl_last_error());
397 if (errstr != NULL) {
398 proxy->last_error = i_strdup(errstr);
399 ssl_proxy_destroy(proxy);
401 ssl_proxy_unref(proxy);
404 static void ssl_handshake(struct ssl_proxy *proxy)
409 ret = SSL_connect(proxy->ssl);
411 ssl_handle_error(proxy, ret, "SSL_connect()");
415 ret = SSL_accept(proxy->ssl);
417 ssl_handle_error(proxy, ret, "SSL_accept()");
421 i_free_and_null(proxy->last_error);
422 proxy->handshaked = TRUE;
424 ssl_set_io(proxy, SSL_ADD_INPUT);
425 plain_block_input(proxy, FALSE);
427 if (proxy->handshake_callback != NULL) {
428 if (proxy->handshake_callback(proxy->handshake_context) < 0)
429 ssl_proxy_destroy(proxy);
433 static void ssl_read(struct ssl_proxy *proxy)
437 while (proxy->plainout_size < sizeof(proxy->plainout_buf) &&
439 ret = SSL_read(proxy->ssl,
440 proxy->plainout_buf + proxy->plainout_size,
441 sizeof(proxy->plainout_buf) -
442 proxy->plainout_size);
444 ssl_handle_error(proxy, ret, "SSL_read()");
447 i_free_and_null(proxy->last_error);
448 proxy->plainout_size += ret;
454 static void ssl_write(struct ssl_proxy *proxy)
458 ret = SSL_write(proxy->ssl, proxy->sslout_buf, proxy->sslout_size);
460 ssl_handle_error(proxy, ret, "SSL_write()");
462 i_free_and_null(proxy->last_error);
463 proxy->sslout_size -= ret;
464 memmove(proxy->sslout_buf, proxy->sslout_buf + ret,
467 ssl_set_io(proxy, proxy->sslout_size > 0 ?
468 SSL_ADD_OUTPUT : SSL_REMOVE_OUTPUT);
469 plain_block_input(proxy, FALSE);
473 static void ssl_step(struct ssl_proxy *proxy)
477 if (!proxy->handshaked)
478 ssl_handshake(proxy);
480 if (proxy->handshaked) {
481 if (proxy->plainout_size == sizeof(proxy->plainout_buf))
482 ssl_set_io(proxy, SSL_REMOVE_INPUT);
486 if (proxy->sslout_size == 0)
487 ssl_set_io(proxy, SSL_REMOVE_OUTPUT);
489 net_set_cork(proxy->fd_ssl, TRUE);
491 net_set_cork(proxy->fd_ssl, FALSE);
495 ssl_proxy_unref(proxy);
498 static int ssl_proxy_new_common(SSL_CTX *ssl_ctx, int fd, struct ip_addr *ip,
499 struct ssl_proxy **proxy_r)
501 struct ssl_proxy *proxy;
509 if (!ssl_initialized) {
510 i_error("SSL support not enabled in configuration");
514 ssl_refresh_parameters(&ssl_params);
516 ssl = SSL_new(ssl_ctx);
518 i_error("SSL_new() failed: %s", ssl_last_error());
522 if (SSL_set_fd(ssl, fd) != 1) {
523 i_error("SSL_set_fd() failed: %s", ssl_last_error());
528 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0) {
529 i_error("socketpair() failed: %m");
534 net_set_nonblock(sfd[0], TRUE);
535 net_set_nonblock(sfd[1], TRUE);
536 net_set_nonblock(fd, TRUE);
538 proxy = i_new(struct ssl_proxy, 1);
542 proxy->fd_plain = sfd[0];
544 SSL_set_ex_data(ssl, extdata_index, proxy);
547 DLLIST_PREPEND(&ssl_proxies, proxy);
555 int ssl_proxy_new(int fd, struct ip_addr *ip, struct ssl_proxy **proxy_r)
559 if ((ret = ssl_proxy_new_common(ssl_server_ctx, fd, ip, proxy_r)) < 0)
566 int ssl_proxy_client_new(int fd, struct ip_addr *ip,
567 ssl_handshake_callback_t *callback, void *context,
568 struct ssl_proxy **proxy_r)
572 if ((ret = ssl_proxy_new_common(ssl_client_ctx, fd, ip, proxy_r)) < 0)
575 (*proxy_r)->handshake_callback = callback;
576 (*proxy_r)->handshake_context = context;
577 (*proxy_r)->client = TRUE;
582 bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy)
584 return proxy->cert_received && !proxy->cert_broken;
587 bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy)
589 return proxy->cert_received && proxy->cert_broken;
592 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy)
598 if (!ssl_proxy_has_valid_client_cert(proxy))
601 x509 = SSL_get_peer_certificate(proxy->ssl);
603 return NULL; /* we should have had it.. */
605 len = X509_NAME_get_text_by_NID(X509_get_subject_name(x509),
606 ssl_username_nid, NULL, 0);
610 name = t_malloc(len + 1);
611 if (X509_NAME_get_text_by_NID(X509_get_subject_name(x509),
612 ssl_username_nid, name, len + 1) < 0)
614 else if (strlen(name) != (size_t)len) {
615 /* NUL characters in name. Someone's trying to fake
616 being another user? Don't allow it. */
622 return *name == '\0' ? NULL : name;
625 bool ssl_proxy_is_handshaked(const struct ssl_proxy *proxy)
627 return proxy->handshaked;
630 const char *ssl_proxy_get_last_error(const struct ssl_proxy *proxy)
632 return proxy->last_error;
635 const char *ssl_proxy_get_security_string(struct ssl_proxy *proxy)
638 #ifdef HAVE_SSL_COMPRESSION
639 const COMP_METHOD *comp;
642 const char *comp_str;
644 if (!proxy->handshaked)
647 cipher = SSL_get_current_cipher(proxy->ssl);
648 bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
649 #ifdef HAVE_SSL_COMPRESSION
650 comp = SSL_get_current_compression(proxy->ssl);
651 comp_str = comp == NULL ? "" :
652 t_strconcat(" ", SSL_COMP_get_name(comp), NULL);
656 return t_strdup_printf("%s with cipher %s (%d/%d bits)%s",
657 SSL_get_version(proxy->ssl),
658 SSL_CIPHER_get_name(cipher),
659 bits, alg_bits, comp_str);
662 void ssl_proxy_free(struct ssl_proxy *proxy)
664 ssl_proxy_unref(proxy);
667 static void ssl_proxy_unref(struct ssl_proxy *proxy)
669 if (--proxy->refcount > 0)
671 i_assert(proxy->refcount == 0);
673 SSL_free(proxy->ssl);
679 static void ssl_proxy_destroy(struct ssl_proxy *proxy)
681 if (proxy->destroyed)
683 proxy->destroyed = TRUE;
686 DLLIST_REMOVE(&ssl_proxies, proxy);
688 if (proxy->io_ssl_read != NULL)
689 io_remove(&proxy->io_ssl_read);
690 if (proxy->io_ssl_write != NULL)
691 io_remove(&proxy->io_ssl_write);
692 if (proxy->io_plain_read != NULL)
693 io_remove(&proxy->io_plain_read);
694 if (proxy->io_plain_write != NULL)
695 io_remove(&proxy->io_plain_write);
697 (void)SSL_shutdown(proxy->ssl);
699 (void)net_disconnect(proxy->fd_ssl);
700 (void)net_disconnect(proxy->fd_plain);
702 ssl_proxy_unref(proxy);
707 static RSA *ssl_gen_rsa_key(SSL *ssl ATTR_UNUSED,
708 int is_export ATTR_UNUSED, int keylength)
710 return RSA_generate_key(keylength, RSA_F4, NULL, NULL);
713 static DH *ssl_tmp_dh_callback(SSL *ssl ATTR_UNUSED,
714 int is_export, int keylength)
716 /* Well, I'm not exactly sure why the logic in here is this.
717 It's the same as in Postfix, so it can't be too wrong. */
718 if (is_export && keylength == 512 && ssl_params.dh_512 != NULL)
719 return ssl_params.dh_512;
721 return ssl_params.dh_1024;
724 static void ssl_info_callback(const SSL *ssl, int where, int ret)
726 struct ssl_proxy *proxy;
728 proxy = SSL_get_ex_data(ssl, extdata_index);
730 if ((where & SSL_CB_ALERT) != 0) {
731 i_warning("SSL alert: where=0x%x, ret=%d: %s %s [%s]",
732 where, ret, SSL_alert_type_string_long(ret),
733 SSL_alert_desc_string_long(ret),
734 net_ip2addr(&proxy->ip));
736 i_warning("SSL BIO failed: where=0x%x, ret=%d: %s [%s]",
737 where, ret, SSL_state_string_long(ssl),
738 net_ip2addr(&proxy->ip));
742 static int ssl_verify_client_cert(int preverify_ok, X509_STORE_CTX *ctx)
745 struct ssl_proxy *proxy;
747 ssl = X509_STORE_CTX_get_ex_data(ctx,
748 SSL_get_ex_data_X509_STORE_CTX_idx());
749 proxy = SSL_get_ex_data(ssl, extdata_index);
750 proxy->cert_received = TRUE;
752 if (verbose_ssl || (verbose_auth && !preverify_ok)) {
756 subject = X509_get_subject_name(ctx->current_cert);
757 (void)X509_NAME_oneline(subject, buf, sizeof(buf));
758 buf[sizeof(buf)-1] = '\0'; /* just in case.. */
760 i_info("Invalid certificate: %s: %s", X509_verify_cert_error_string(ctx->error),buf);
762 i_info("Valid certificate: %s", buf);
765 proxy->cert_broken = TRUE;
767 /* Return success anyway, because if ssl_require_client_cert=no we
768 could still allow authentication. */
773 pem_password_callback(char *buf, int size, int rwflag ATTR_UNUSED,
776 if (userdata == NULL) {
777 i_error("SSL private key file is password protected, "
778 "but password isn't given");
782 if (i_strocpy(buf, userdata, size) < 0)
787 unsigned int ssl_proxy_get_count(void)
789 return ssl_proxy_count;
792 static bool is_pem_key_file(const char *path)
797 /* this code is used only for giving a better error message,
798 so it needs to catch only the normal key files */
799 fd = open(path, O_RDONLY);
802 ret = read(fd, buf, sizeof(buf)-1);
807 return strstr(buf, "PRIVATE KEY---") != NULL;
810 static void ssl_proxy_ctx_init(SSL_CTX *ssl_ctx)
814 SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
816 cafile = getenv("SSL_CA_FILE");
817 if (cafile != NULL) {
818 if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, NULL) != 1) {
819 i_fatal("Can't load CA file %s: %s",
820 cafile, ssl_last_error());
824 SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback);
825 if (SSL_CTX_need_tmp_RSA(ssl_ctx))
826 SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
827 SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
830 static void ssl_proxy_ctx_verify_client(SSL_CTX *ssl_ctx)
833 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
836 store = SSL_CTX_get_cert_store(ssl_ctx);
837 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
838 X509_V_FLAG_CRL_CHECK_ALL);
840 cafile = getenv("SSL_CA_FILE");
841 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
842 ssl_verify_client_cert);
843 SSL_CTX_set_client_CA_list(ssl_ctx, SSL_load_client_CA_file(cafile));
846 static void ssl_proxy_init_server(const char *certfile, const char *keyfile)
848 const char *cipher_list, *username_field;
852 password = getenv("SSL_KEY_PASSWORD");
854 if ((ssl_server_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL)
855 i_fatal("SSL_CTX_new() failed");
856 ssl_proxy_ctx_init(ssl_server_ctx);
858 cipher_list = getenv("SSL_CIPHER_LIST");
859 if (cipher_list == NULL)
860 cipher_list = DOVECOT_SSL_DEFAULT_CIPHER_LIST;
861 if (SSL_CTX_set_cipher_list(ssl_server_ctx, cipher_list) != 1) {
862 i_fatal("Can't set cipher list to '%s': %s",
863 cipher_list, ssl_last_error());
866 if (SSL_CTX_use_certificate_chain_file(ssl_server_ctx, certfile) != 1) {
867 err = ERR_peek_error();
868 if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
869 ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
870 i_fatal("Can't load certificate file %s: %s",
871 certfile, ssl_last_error());
872 } else if (is_pem_key_file(certfile)) {
873 i_fatal("Can't load certificate file %s: "
874 "The file contains a private key "
875 "(you've mixed ssl_cert_file and ssl_key_file settings)",
878 i_fatal("Can't load certificate file %s: "
879 "The file doesn't contain a certificate.",
884 SSL_CTX_set_default_passwd_cb(ssl_server_ctx, pem_password_callback);
885 SSL_CTX_set_default_passwd_cb_userdata(ssl_server_ctx, password);
886 if (SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile,
887 SSL_FILETYPE_PEM) != 1) {
888 err = ERR_peek_error();
889 if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
890 ERR_GET_REASON(err) == X509_R_KEY_VALUES_MISMATCH) {
891 i_fatal("Can't load private key file %s: "
892 "Key is for a different cert than %s",
895 i_fatal("Can't load private key file %s: %s",
896 keyfile, ssl_last_error());
900 if (getenv("SSL_VERIFY_CLIENT_CERT") != NULL)
901 ssl_proxy_ctx_verify_client(ssl_server_ctx);
903 username_field = getenv("SSL_CERT_USERNAME_FIELD");
904 if (username_field == NULL)
905 ssl_username_nid = NID_commonName;
907 ssl_username_nid = OBJ_txt2nid(username_field);
908 if (ssl_username_nid == NID_undef) {
909 i_fatal("Invalid ssl_cert_username_field: %s",
915 static void ssl_proxy_init_client(void)
917 if ((ssl_client_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
918 i_fatal("SSL_CTX_new() failed");
919 ssl_proxy_ctx_init(ssl_client_ctx);
920 ssl_proxy_ctx_verify_client(ssl_client_ctx);
923 void ssl_proxy_init(void)
925 static char dovecot[] = "dovecot";
926 const char *certfile, *keyfile;
929 memset(&ssl_params, 0, sizeof(ssl_params));
931 certfile = getenv("SSL_CERT_FILE");
932 keyfile = getenv("SSL_KEY_FILE");
933 ssl_params.fname = getenv("SSL_PARAM_FILE");
935 if (certfile == NULL || keyfile == NULL || ssl_params.fname == NULL) {
936 /* SSL support is disabled */
941 SSL_load_error_strings();
943 extdata_index = SSL_get_ex_new_index(0, dovecot, NULL, NULL, NULL);
944 ssl_proxy_init_server(certfile, keyfile);
945 ssl_proxy_init_client();
947 /* PRNG initialization might want to use /dev/urandom, make sure it
948 does it before chrooting. We might not have enough entropy at
949 the first try, so this function may fail. It's still been
950 initialized though. */
951 (void)RAND_bytes(&buf, 1);
955 ssl_initialized = TRUE;
958 void ssl_proxy_deinit(void)
960 if (!ssl_initialized)
963 while (ssl_proxies != NULL)
964 ssl_proxy_destroy(ssl_proxies);
966 ssl_free_parameters(&ssl_params);
967 SSL_CTX_free(ssl_server_ctx);
968 SSL_CTX_free(ssl_client_ctx);