X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Ftls.c;h=f5f0623a3cd1bebbf598c3e068bc08d5ac00180c;hb=5450f5e38d6dd94600c7c35fedf7f9ccea3e7adb;hp=01045b78bb86e104dcbf05410599b969cd62775c;hpb=c7e72b21fa421f7a05cc0f308053d1870e2e95c4;p=bacula%2Fbacula diff --git a/bacula/src/lib/tls.c b/bacula/src/lib/tls.c index 01045b78bb..f5f0623a3c 100644 --- a/bacula/src/lib/tls.c +++ b/bacula/src/lib/tls.c @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2005-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ /* * tls.c TLS support functions * @@ -5,8 +32,6 @@ * * Version $Id$ * - * Copyright (C) 2005 Kern Sibbald - * * This file was contributed to the Bacula project by Landon Fuller * and Three Rings Design, Inc. * @@ -21,28 +46,11 @@ * under an alternate open source license please contact * Landon Fuller . */ -/* - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, - MA 02111-1307, USA. - */ #include "bacula.h" #include -extern time_t watchdog_time; #ifdef HAVE_TLS /* Is TLS enabled? */ @@ -51,42 +59,19 @@ extern time_t watchdog_time; /* No anonymous ciphers, no <128 bit ciphers, no export ciphers, no MD5 ciphers */ #define TLS_DEFAULT_CIPHERS "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" -/* Array of mutexes for use with OpenSSL static locking */ -static pthread_mutex_t *mutexes; - -/* OpenSSL dynamic locking structure */ -struct CRYPTO_dynlock_value { - pthread_mutex_t mutex; -}; - -/* Are we initialized? */ -static int tls_initialized = false; - /* TLS Context Structure */ struct TLS_Context { SSL_CTX *openssl; - TLS_PEM_PASSWD_CB *pem_callback; + CRYPTO_PEM_PASSWD_CB *pem_callback; const void *pem_userdata; + bool tls_enable; + bool tls_require; }; struct TLS_Connection { SSL *openssl; }; -/* post all per-thread openssl errors */ -static void openssl_post_errors(int code, const char *errstring) -{ - char buf[512]; - unsigned long sslerr; - - /* Pop errors off of the per-thread queue */ - while((sslerr = ERR_get_error()) != 0) { - /* Acquire the human readable string */ - ERR_error_string_n(sslerr, (char *) &buf, sizeof(buf)); - Emsg2(M_ERROR, 0, "%s: ERR=%s\n", errstring, buf); - } -} - /* * OpenSSL certificate verification callback. * OpenSSL has already performed internal certificate verification. @@ -94,7 +79,6 @@ static void openssl_post_errors(int code, const char *errstring) */ static int openssl_verify_peer(int ok, X509_STORE_CTX *store) { - if (!ok) { X509 *cert = X509_STORE_CTX_get_current_cert(store); int depth = X509_STORE_CTX_get_error_depth(store); @@ -105,29 +89,19 @@ static int openssl_verify_peer(int ok, X509_STORE_CTX *store) X509_NAME_oneline(X509_get_issuer_name(cert), issuer, 256); X509_NAME_oneline(X509_get_subject_name(cert), subject, 256); - Emsg5(M_ERROR, 0, _("Error with certificate at depth: %d, issuer = %s," - " subject = %s, ERR=%d:%s\n"), depth, issuer, - subject, err, X509_verify_cert_error_string(err)); + Jmsg5(NULL, M_ERROR, 0, _("Error with certificate at depth: %d, issuer = %s," + " subject = %s, ERR=%d:%s\n"), depth, issuer, + subject, err, X509_verify_cert_error_string(err)); } return ok; } -/* - * Default PEM encryption passphrase callback. - * Returns an empty password. - */ -static int tls_default_pem_callback(char *buf, int size, const void *userdata) -{ - bstrncpy(buf, "", size); - return (strlen(buf)); -} - /* Dispatch user PEM encryption callbacks */ -static int openssl_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata) +static int tls_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata) { - TLS_CONTEXT *ctx = (TLS_CONTEXT *) userdata; + TLS_CONTEXT *ctx = (TLS_CONTEXT *)userdata; return (ctx->pem_callback(buf, size, ctx->pem_userdata)); } @@ -138,7 +112,7 @@ static int openssl_pem_callback_dispatch (char *buf, int size, int rwflag, void */ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir, const char *certfile, const char *keyfile, - TLS_PEM_PASSWD_CB *pem_callback, + CRYPTO_PEM_PASSWD_CB *pem_callback, const void *pem_userdata, const char *dhfile, bool verify_peer) { @@ -146,7 +120,7 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir, BIO *bio; DH *dh; - ctx = (TLS_CONTEXT *) malloc(sizeof(TLS_CONTEXT)); + ctx = (TLS_CONTEXT *)malloc(sizeof(TLS_CONTEXT)); /* Allocate our OpenSSL TLSv1 Context */ ctx->openssl = SSL_CTX_new(TLSv1_method()); @@ -161,10 +135,10 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir, ctx->pem_callback = pem_callback; ctx->pem_userdata = pem_userdata; } else { - ctx->pem_callback = tls_default_pem_callback; + ctx->pem_callback = crypto_default_pem_callback; ctx->pem_userdata = NULL; } - SSL_CTX_set_default_passwd_cb(ctx->openssl, openssl_pem_callback_dispatch); + SSL_CTX_set_default_passwd_cb(ctx->openssl, tls_pem_callback_dispatch); SSL_CTX_set_default_passwd_cb_userdata(ctx->openssl, (void *) ctx); /* @@ -178,7 +152,7 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir, } } else if (verify_peer) { /* At least one CA is required for peer verification */ - Emsg0(M_ERROR, 0, _("Either a certificate file or a directory must be" + Jmsg0(NULL, M_ERROR, 0, _("Either a certificate file or a directory must be" " specified as a verification store\n")); goto err; } @@ -224,16 +198,17 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir, } if (SSL_CTX_set_cipher_list(ctx->openssl, TLS_DEFAULT_CIPHERS) != 1) { - Emsg0(M_ERROR, 0, _("Error setting cipher list, no valid ciphers available\n")); + Jmsg0(NULL, M_ERROR, 0, + _("Error setting cipher list, no valid ciphers available\n")); goto err; } /* Verify Peer Certificate */ if (verify_peer) { - /* SSL_VERIFY_FAIL_IF_NO_PEER_CERT has no effect in client mode */ - SSL_CTX_set_verify(ctx->openssl, - SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - openssl_verify_peer); + /* SSL_VERIFY_FAIL_IF_NO_PEER_CERT has no effect in client mode */ + SSL_CTX_set_verify(ctx->openssl, + SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + openssl_verify_peer); } return ctx; @@ -256,23 +231,34 @@ void free_tls_context(TLS_CONTEXT *ctx) free(ctx); } +bool get_tls_require(TLS_CONTEXT *ctx) +{ + return ctx->tls_require; +} + +bool get_tls_enable(TLS_CONTEXT *ctx) +{ + return ctx->tls_enable; +} + + /* * Verifies a list of common names against the certificate * commonName attribute. * Returns: true on success * false on failure */ -bool tls_postconnect_verify_cn(TLS_CONNECTION *tls, alist *verify_list) +bool tls_postconnect_verify_cn(JCR *jcr, TLS_CONNECTION *tls, alist *verify_list) { SSL *ssl = tls->openssl; X509 *cert; X509_NAME *subject; - int auth_success = false; + bool auth_success = false; char data[256]; /* Check if peer provided a certificate */ if (!(cert = SSL_get_peer_certificate(ssl))) { - Emsg0(M_ERROR, 0, _("Peer failed to present a TLS certificate\n")); + Qmsg0(jcr, M_ERROR, 0, _("Peer failed to present a TLS certificate\n")); return false; } @@ -301,12 +287,12 @@ bool tls_postconnect_verify_cn(TLS_CONNECTION *tls, alist *verify_list) * Returns: true on success * false on failure */ -bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host) +bool tls_postconnect_verify_host(JCR *jcr, TLS_CONNECTION *tls, const char *host) { SSL *ssl = tls->openssl; X509 *cert; X509_NAME *subject; - int auth_success = false; + bool auth_success = false; int extensions; char data[256]; int i, j; @@ -314,7 +300,8 @@ bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host) /* Check if peer provided a certificate */ if (!(cert = SSL_get_peer_certificate(ssl))) { - Emsg1(M_ERROR, 0, _("Peer %s failed to present a TLS certificate\n"), host); + Qmsg1(jcr, M_ERROR, 0, + _("Peer %s failed to present a TLS certificate\n"), host); return false; } @@ -331,32 +318,36 @@ bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host) X509V3_EXT_METHOD *method; STACK_OF(CONF_VALUE) *val; CONF_VALUE *nval; - unsigned char *data; void *extstr = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL) + const unsigned char *ext_value_data; +#else + unsigned char *ext_value_data; +#endif /* Get x509 extension method structure */ if (!(method = X509V3_EXT_get(ext))) { break; } - data = ext->value->data; + ext_value_data = ext->value->data; #if (OPENSSL_VERSION_NUMBER > 0x00907000L) if (method->it) { /* New style ASN1 */ /* Decode ASN1 item in data */ - extstr = ASN1_item_d2i(NULL, &data, ext->value->length, + extstr = ASN1_item_d2i(NULL, &ext_value_data, ext->value->length, ASN1_ITEM_ptr(method->it)); } else { /* Old style ASN1 */ /* Decode ASN1 item in data */ - extstr = method->d2i(NULL, &data, ext->value->length); + extstr = method->d2i(NULL, &ext_value_data, ext->value->length); } #else - extstr = method->d2i(NULL, &data, ext->value->length); + extstr = method->d2i(NULL, &ext_value_data, ext->value->length); #endif /* Iterate through to find the dNSName field(s) */ @@ -366,7 +357,7 @@ bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host) for (j = 0; j < sk_CONF_VALUE_num(val); j++) { nval = sk_CONF_VALUE_value(val, j); if (strcmp(nval->name, "DNS") == 0) { - if (strcasecmp(nval->name, host) == 0) { + if (strcasecmp(nval->value, host) == 0) { auth_success = true; goto success; } @@ -389,7 +380,6 @@ bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host) } } - success: X509_free(cert); @@ -402,7 +392,7 @@ success: * Returns: Pointer to TLS_CONNECTION instance on success * NULL on failure; */ -TLS_CONNECTION *new_tls_connection (TLS_CONTEXT *ctx, int fd) +TLS_CONNECTION *new_tls_connection(TLS_CONTEXT *ctx, int fd) { BIO *bio; @@ -413,18 +403,18 @@ TLS_CONNECTION *new_tls_connection (TLS_CONTEXT *ctx, int fd) bio = BIO_new(BIO_s_socket()); if (!bio) { /* Not likely, but never say never */ - openssl_post_errors(M_ERROR, "Error creating file descriptor-based BIO"); + openssl_post_errors(M_ERROR, _("Error creating file descriptor-based BIO")); return NULL; /* Nothing allocated, nothing to clean up */ } BIO_set_fd(bio, fd, BIO_NOCLOSE); /* Allocate our new tls connection */ - TLS_CONNECTION *tls = (TLS_CONNECTION *) malloc(sizeof(TLS_CONNECTION)); + TLS_CONNECTION *tls = (TLS_CONNECTION *)malloc(sizeof(TLS_CONNECTION)); /* Create the SSL object and attach the socket BIO */ if ((tls->openssl = SSL_new(ctx->openssl)) == NULL) { /* Not likely, but never say never */ - openssl_post_errors(M_ERROR, "Error creating new SSL object"); + openssl_post_errors(M_ERROR, _("Error creating new SSL object")); goto err; } @@ -433,21 +423,20 @@ TLS_CONNECTION *new_tls_connection (TLS_CONTEXT *ctx, int fd) /* Non-blocking partial writes */ SSL_set_mode(tls->openssl, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - return (tls); + return tls; err: /* Clean up */ BIO_free(bio); SSL_free(tls->openssl); free(tls); - return NULL; } /* * Free TLS_CONNECTION instance */ -void free_tls_connection (TLS_CONNECTION *tls) +void free_tls_connection(TLS_CONNECTION *tls) { SSL_free(tls->openssl); free(tls); @@ -465,16 +454,14 @@ static inline bool openssl_bsock_session_start(BSOCK *bsock, bool server) /* Zero the fdset, we'll set our fd prior to each invocation of select() */ FD_ZERO(&fdset); - tv.tv_sec = 10; - tv.tv_usec = 0; - fdmax = bsock->fd + 1; + fdmax = bsock->m_fd + 1; /* Ensure that socket is non-blocking */ - flags = bnet_set_nonblocking(bsock); + flags = bsock->set_nonblocking(); /* start timer */ bsock->timer_start = watchdog_time; - bsock->timed_out = 0; + bsock->clear_timed_out(); for (;;) { if (server) { @@ -485,41 +472,47 @@ static inline bool openssl_bsock_session_start(BSOCK *bsock, bool server) /* Handle errors */ switch (SSL_get_error(tls->openssl, err)) { - case SSL_ERROR_NONE: - stat = true; - goto cleanup; - case SSL_ERROR_ZERO_RETURN: - /* TLS connection was cleanly shut down */ - openssl_post_errors(M_ERROR, "Connect failure"); - stat = false; - goto cleanup; - case SSL_ERROR_WANT_READ: - /* If we timeout of a select, this will be unset */ - FD_SET((unsigned) bsock->fd, &fdset); - /* Block until we can read */ - select(fdmax, &fdset, NULL, &fdset, &tv); - break; - case SSL_ERROR_WANT_WRITE: - /* If we timeout of a select, this will be unset */ - FD_SET((unsigned) bsock->fd, &fdset); - /* Block until we can write */ - select(fdmax, NULL, &fdset, &fdset, &tv); - break; - default: - /* Socket Error Occured */ - openssl_post_errors(M_ERROR, "Connect failure"); - stat = false; - goto cleanup; + case SSL_ERROR_NONE: + stat = true; + goto cleanup; + case SSL_ERROR_ZERO_RETURN: + /* TLS connection was cleanly shut down */ + openssl_post_errors(M_ERROR, _("Connect failure")); + stat = false; + goto cleanup; + case SSL_ERROR_WANT_READ: + /* If we timeout of a select, this will be unset */ + FD_SET((unsigned) bsock->m_fd, &fdset); + /* Set our timeout */ + tv.tv_sec = 10; + tv.tv_usec = 0; + /* Block until we can read */ + select(fdmax, &fdset, NULL, NULL, &tv); + break; + case SSL_ERROR_WANT_WRITE: + /* If we timeout of a select, this will be unset */ + FD_SET((unsigned) bsock->m_fd, &fdset); + /* Set our timeout */ + tv.tv_sec = 10; + tv.tv_usec = 0; + /* Block until we can write */ + select(fdmax, NULL, &fdset, NULL, &tv); + break; + default: + /* Socket Error Occurred */ + openssl_post_errors(M_ERROR, _("Connect failure")); + stat = false; + goto cleanup; } - if (bsock->timed_out) { + if (bsock->is_timed_out()) { goto cleanup; } } cleanup: /* Restore saved flags */ - bnet_restore_blocking(bsock, flags); + bsock->restore_blocking(flags); /* Clear timer */ bsock->timer_start = 0; @@ -534,7 +527,7 @@ cleanup: bool tls_bsock_connect(BSOCK *bsock) { /* SSL_connect(bsock->tls) */ - return (openssl_bsock_session_start(bsock, false)); + return openssl_bsock_session_start(bsock, false); } /* @@ -545,55 +538,47 @@ bool tls_bsock_connect(BSOCK *bsock) bool tls_bsock_accept(BSOCK *bsock) { /* SSL_accept(bsock->tls) */ - return (openssl_bsock_session_start(bsock, true)); + return openssl_bsock_session_start(bsock, true); } /* * Shutdown TLS_CONNECTION instance */ -void tls_bsock_shutdown (BSOCK *bsock) +void tls_bsock_shutdown(BSOCK *bsock) { /* * SSL_shutdown must be called twice to fully complete the process - * The first time to initiate the shutdown handshake, and the second to * receive the peer's reply. * - * However, it is valid to close the SSL connection after the initial - * shutdown notification is sent to the peer, without waiting for the - * peer's reply, as long as you do not plan to re-use that particular - * SSL connection object. - * - * Because we do not re-use SSL connection objects, I do not bother - * calling SSL_shutdown a second time. - * * In addition, if the underlying socket is blocking, SSL_shutdown() * will not return until the current stage of the shutdown process has * completed or an error has occured. By setting the socket blocking * we can avoid the ugly for()/switch()/select() loop. */ int err; - int flags; /* Set socket blocking for shutdown */ - flags = bnet_set_blocking(bsock); + bsock->set_blocking(); err = SSL_shutdown(bsock->tls->openssl); + if (err == 0) { + /* Complete shutdown */ + err = SSL_shutdown(bsock->tls->openssl); + } switch (SSL_get_error(bsock->tls->openssl, err)) { - case SSL_ERROR_NONE: - break; - case SSL_ERROR_ZERO_RETURN: - /* TLS connection was shut down on us via a TLS protocol-level closure */ - openssl_post_errors(M_ERROR, _("TLS shutdown failure.")); - break; - default: - /* Socket Error Occured */ - openssl_post_errors(M_ERROR, _("TLS shutdown failure.")); - break; + case SSL_ERROR_NONE: + break; + case SSL_ERROR_ZERO_RETURN: + /* TLS connection was shut down on us via a TLS protocol-level closure */ + openssl_post_errors(M_ERROR, _("TLS shutdown failure.")); + break; + default: + /* Socket Error Occurred */ + openssl_post_errors(M_ERROR, _("TLS shutdown failure.")); + break; } - - /* Restore saved flags */ - bnet_restore_blocking(bsock, flags); } /* Does all the manual labor for tls_bsock_readn() and tls_bsock_writen() */ @@ -608,21 +593,18 @@ static inline int openssl_bsock_readwrite(BSOCK *bsock, char *ptr, int nbytes, b /* Zero the fdset, we'll set our fd prior to each invocation of select() */ FD_ZERO(&fdset); - tv.tv_sec = 10; - tv.tv_usec = 0; - fdmax = bsock->fd + 1; + fdmax = bsock->m_fd + 1; /* Ensure that socket is non-blocking */ - flags = bnet_set_nonblocking(bsock); + flags = bsock->set_nonblocking(); /* start timer */ bsock->timer_start = watchdog_time; - bsock->timed_out = 0; + bsock->clear_timed_out(); nleft = nbytes; while (nleft > 0) { - if (write) { nwritten = SSL_write(tls->openssl, ptr, nleft); } else { @@ -631,32 +613,38 @@ static inline int openssl_bsock_readwrite(BSOCK *bsock, char *ptr, int nbytes, b /* Handle errors */ switch (SSL_get_error(tls->openssl, nwritten)) { - case SSL_ERROR_NONE: - nleft -= nwritten; - if (nleft) { - ptr += nwritten; - } - break; - case SSL_ERROR_ZERO_RETURN: - /* TLS connection was cleanly shut down */ - openssl_post_errors(M_ERROR, _("TLS read/write failure.")); - goto cleanup; - case SSL_ERROR_WANT_READ: - /* If we timeout of a select, this will be unset */ - FD_SET((unsigned) bsock->fd, &fdset); - /* Block until we can read */ - select(fdmax, &fdset, NULL, &fdset, &tv); - break; - case SSL_ERROR_WANT_WRITE: - /* If we timeout of a select, this will be unset */ - FD_SET((unsigned) bsock->fd, &fdset); - /* Block until we can write */ - select(fdmax, NULL, &fdset, &fdset, &tv); - break; - default: - /* Socket Error Occured */ - openssl_post_errors(M_ERROR, _("TLS read/write failure.")); - goto cleanup; + case SSL_ERROR_NONE: + nleft -= nwritten; + if (nleft) { + ptr += nwritten; + } + break; + + case SSL_ERROR_WANT_READ: + /* If we timeout on a select, this will be unset */ + FD_SET((unsigned)bsock->m_fd, &fdset); + tv.tv_sec = 10; + tv.tv_usec = 0; + /* Block until we can read */ + select(fdmax, &fdset, NULL, NULL, &tv); + break; + + case SSL_ERROR_WANT_WRITE: + /* If we timeout on a select, this will be unset */ + FD_SET((unsigned)bsock->m_fd, &fdset); + tv.tv_sec = 10; + tv.tv_usec = 0; + /* Block until we can write */ + select(fdmax, NULL, &fdset, NULL, &tv); + break; + + case SSL_ERROR_ZERO_RETURN: + /* TLS connection was cleanly shut down */ + /* Fall through wanted */ + default: + /* Socket Error Occured */ + openssl_post_errors(M_ERROR, _("TLS read/write failure.")); + goto cleanup; } /* Everything done? */ @@ -665,267 +653,64 @@ static inline int openssl_bsock_readwrite(BSOCK *bsock, char *ptr, int nbytes, b } /* Timeout/Termination, let's take what we can get */ - if (bsock->timed_out || bsock->terminated) { + if (bsock->is_timed_out() || bsock->is_terminated()) { goto cleanup; } } cleanup: /* Restore saved flags */ - bnet_restore_blocking(bsock, flags); + bsock->restore_blocking(flags); /* Clear timer */ bsock->timer_start = 0; - return nbytes - nleft; } -int tls_bsock_writen(BSOCK *bsock, char *ptr, int32_t nbytes) { - /* SSL_write(bsock->tls->openssl, ptr, nbytes) */ - return (openssl_bsock_readwrite(bsock, ptr, nbytes, true)); -} - -int tls_bsock_readn(BSOCK *bsock, char *ptr, int32_t nbytes) { - /* SSL_read(bsock->tls->openssl, ptr, nbytes) */ - return (openssl_bsock_readwrite(bsock, ptr, nbytes, false)); -} - -/* - * Return an OpenSSL thread ID - * Returns: thread ID - * - */ -static unsigned long get_openssl_thread_id (void) -{ - /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */ - return ((unsigned long) pthread_self()); -} - -/* - * Allocate a dynamic OpenSSL mutex - */ -static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line) -{ - struct CRYPTO_dynlock_value *dynlock; - int stat; - - dynlock = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value)); - - if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) { - Emsg1(M_ABORT, 0, "Unable to init mutex: ERR=%s\n", strerror(stat)); - } - - return dynlock; -} - -static void openssl_update_dynamic_mutex (int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line) +int tls_bsock_writen(BSOCK *bsock, char *ptr, int32_t nbytes) { - if (mode & CRYPTO_LOCK) { - P(dynlock->mutex); - } else { - V(dynlock->mutex); - } -} - -static void openssl_destroy_dynamic_mutex (struct CRYPTO_dynlock_value *dynlock, const char *file, int line) -{ - int stat; - - if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) { - Emsg1(M_ABORT, 0, "Unable to destroy mutex: ERR=%s\n", strerror(stat)); - } - - free(dynlock); + /* SSL_write(bsock->tls->openssl, ptr, nbytes) */ + return openssl_bsock_readwrite(bsock, ptr, nbytes, true); } -/* - * (Un)Lock a static OpenSSL mutex - */ -static void openssl_update_static_mutex (int mode, int i, const char *file, int line) +int tls_bsock_readn(BSOCK *bsock, char *ptr, int32_t nbytes) { - if (mode & CRYPTO_LOCK) { - P(mutexes[i]); - } else { - V(mutexes[i]); - } + /* SSL_read(bsock->tls->openssl, ptr, nbytes) */ + return openssl_bsock_readwrite(bsock, ptr, nbytes, false); } -/* - * Initialize OpenSSL thread support - * Returns: 0 on success - * errno on failure - */ -static int openssl_init_threads (void) -{ - int i, numlocks; - int stat; - - - /* Set thread ID callback */ - CRYPTO_set_id_callback(get_openssl_thread_id); - - /* Initialize static locking */ - numlocks = CRYPTO_num_locks(); - mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t)); - for (i = 0; i < numlocks; i++) { - if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) { - Emsg1(M_ERROR, 0, "Unable to init mutex: ERR=%s\n", strerror(stat)); - return stat; - } - } +#else /* HAVE_OPENSSL */ +# error No TLS implementation available. +#endif /* !HAVE_OPENSSL */ - /* Set static locking callback */ - CRYPTO_set_locking_callback(openssl_update_static_mutex); - /* Initialize dyanmic locking */ - CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex); - CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex); - CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex); +#else /* TLS NOT enabled, dummy routines substituted */ - return 0; -} -/* - * Clean up OpenSSL threading support - */ -static void openssl_cleanup_threads (void) +/* Dummy routines */ +TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir, + const char *certfile, const char *keyfile, + CRYPTO_PEM_PASSWD_CB *pem_callback, + const void *pem_userdata, const char *dhfile, + bool verify_peer) { - int i, numlocks; - int stat; - - /* Unset thread ID callback */ - CRYPTO_set_id_callback(NULL); - - /* Deallocate static lock mutexes */ - numlocks = CRYPTO_num_locks(); - for (i = 0; i < numlocks; i++) { - if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) { - /* We don't halt execution, reporting the error should be sufficient */ - Emsg1(M_ERROR, 0, "Unable to destroy mutex: ERR=%s\n", strerror(stat)); - } - } - - /* Unset static locking callback */ - CRYPTO_set_locking_callback(NULL); - - /* Free static lock array */ - free(mutexes); - - /* Unset dynamic locking callbacks */ - CRYPTO_set_dynlock_create_callback(NULL); - CRYPTO_set_dynlock_lock_callback(NULL); - CRYPTO_set_dynlock_destroy_callback(NULL); + return NULL; } +void free_tls_context(TLS_CONTEXT *ctx) { } +void tls_bsock_shutdown(BSOCK *bsock) { } -/* - * Seed TLS PRNG - * Returns: 1 on success - * 0 on failure - */ -static int seed_tls_prng (void) -{ - const char *names[] = { "/dev/urandom", "/dev/random", NULL }; - int i; - - // ***FIXME*** - // Win32 Support - // Read saved entropy? +void free_tls_connection(TLS_CONNECTION *tls) { } - for (i = 0; names[i]; i++) { - if (RAND_load_file(names[i], 1024) != -1) { - /* Success */ - return 1; - } - } - - /* Fail */ - return 0; -} - -/* - * Save TLS Entropy - * Returns: 1 on success - * 0 on failure - */ -static int save_tls_prng (void) +bool get_tls_require(TLS_CONTEXT *ctx) { - // ***FIXME*** - // Implement PRNG state save - return 1; + return false; } -/* - * Perform global initialization of TLS - * This function is not thread safe. - * Returns: 0 on success - * errno on failure - */ -int init_tls (void) +bool get_tls_enable(TLS_CONTEXT *ctx) { - int stat; - - if ((stat = openssl_init_threads()) != 0) { - Emsg1(M_ABORT, 0, "Unable to init OpenSSL threading: ERR=%s\n", strerror(stat)); - } - - /* Load libssl and libcrypto human-readable error strings */ - SSL_load_error_strings(); - - /* Register OpenSSL ciphers */ - SSL_library_init(); - - if (!seed_tls_prng()) { - Emsg0(M_ERROR_TERM, 0, _("Failed to seed OpenSSL PRNG\n")); - } - - tls_initialized = true; - - return stat; + return false; } -/* - * Perform global cleanup of TLS - * All TLS connections must be closed before calling this function. - * This function is not thread safe. - * Returns: 0 on success - * errno on failure - */ -int cleanup_tls (void) -{ - /* - * Ensure that we've actually been initialized; Doing this here decreases the - * complexity of client's termination/cleanup code. - */ - if (!tls_initialized) { - return 0; - } - - if (!save_tls_prng()) { - Emsg0(M_ERROR, 0, _("Failed to save OpenSSL PRNG\n")); - } - - openssl_cleanup_threads(); - - /* Free libssl and libcrypto error strings */ - ERR_free_strings(); - - /* Free memory used by PRNG */ - RAND_cleanup(); - - tls_initialized = false; - - return 0; -} - -#else /* HAVE_OPENSSL */ -# error No TLS implementation available. -#endif /* !HAVE_OPENSSL */ - -#else - -int init_tls(void) { return 0; } - - #endif /* HAVE_TLS */