"Fossies" - the Fresh Open Source Software Archive

Member "memcached-1.6.15/tls.c" (21 Feb 2022, 8552 Bytes) of package /linux/www/memcached-1.6.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tls.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.6.12_vs_1.6.13.

    1 #include "memcached.h"
    2 
    3 #ifdef TLS
    4 
    5 #include "tls.h"
    6 #include <string.h>
    7 #include <sysexits.h>
    8 #include <sys/param.h>
    9 #include <openssl/err.h>
   10 
   11 #ifndef MAXPATHLEN
   12 #define MAXPATHLEN 4096
   13 #endif
   14 
   15 static pthread_mutex_t ssl_ctx_lock = PTHREAD_MUTEX_INITIALIZER;
   16 
   17 const unsigned ERROR_MSG_SIZE = 64;
   18 const size_t SSL_ERROR_MSG_SIZE = 256;
   19 
   20 void SSL_LOCK() {
   21     pthread_mutex_lock(&(ssl_ctx_lock));
   22 }
   23 
   24 void SSL_UNLOCK(void) {
   25     pthread_mutex_unlock(&(ssl_ctx_lock));
   26 }
   27 
   28 /*
   29  * Reads decrypted data from the underlying BIO read buffers,
   30  * which reads from the socket.
   31  */
   32 ssize_t ssl_read(conn *c, void *buf, size_t count) {
   33     assert (c != NULL);
   34     /* TODO : document the state machine interactions for SSL_read with
   35         non-blocking sockets/ SSL re-negotiations
   36     */
   37     return SSL_read(c->ssl, buf, count);
   38 }
   39 
   40 /*
   41  * SSL sendmsg implementation. Perform a SSL_write.
   42  */
   43 ssize_t ssl_sendmsg(conn *c, struct msghdr *msg, int flags) {
   44     assert (c != NULL);
   45     size_t buf_remain = settings.ssl_wbuf_size;
   46     size_t bytes = 0;
   47     size_t to_copy;
   48     int i;
   49 
   50     // ssl_wbuf is pointing to the buffer allocated in the worker thread.
   51     assert(c->ssl_wbuf);
   52     // TODO: allocate a fix buffer in crawler/logger if they start using
   53     // the sendmsg method. Also, set c->ssl_wbuf  when the side thread
   54     // start owning the connection and reset the pointer in
   55     // conn_worker_readd.
   56     // Currently this connection would not be served by a different thread
   57     // than the one it's assigned.
   58     assert(pthread_equal(c->thread->thread_id, pthread_self()) != 0);
   59 
   60     char *bp = c->ssl_wbuf;
   61     for (i = 0; i < msg->msg_iovlen; i++) {
   62         size_t len = msg->msg_iov[i].iov_len;
   63         to_copy = len < buf_remain ? len : buf_remain;
   64 
   65         memcpy(bp + bytes, (void*)msg->msg_iov[i].iov_base, to_copy);
   66         buf_remain -= to_copy;
   67         bytes += to_copy;
   68         if (buf_remain == 0)
   69             break;
   70     }
   71     /* TODO : document the state machine interactions for SSL_write with
   72         non-blocking sockets/ SSL re-negotiations
   73     */
   74     return SSL_write(c->ssl, c->ssl_wbuf, bytes);
   75 }
   76 
   77 /*
   78  * Writes data to the underlying BIO write buffers,
   79  * which encrypt and write them to the socket.
   80  */
   81 ssize_t ssl_write(conn *c, void *buf, size_t count) {
   82     assert (c != NULL);
   83     return SSL_write(c->ssl, buf, count);
   84 }
   85 
   86 /*
   87  * Prints an SSL error into the buff, if there's any.
   88  */
   89 static void print_ssl_error(char *buff, size_t len) {
   90     unsigned long err;
   91     if ((err = ERR_get_error()) != 0) {
   92         ERR_error_string_n(err, buff, len);
   93     }
   94 }
   95 
   96 /*
   97  * Loads server certificates to the SSL context and validate them.
   98  * @return whether certificates are successfully loaded and verified or not.
   99  * @param error_msg contains the error when unsuccessful.
  100  */
  101 static bool load_server_certificates(char **errmsg) {
  102     bool success = false;
  103 
  104     const size_t CRLF_NULLCHAR_LEN = 3;
  105     char *error_msg = malloc(MAXPATHLEN + ERROR_MSG_SIZE +
  106         SSL_ERROR_MSG_SIZE);
  107     size_t errmax = MAXPATHLEN + ERROR_MSG_SIZE + SSL_ERROR_MSG_SIZE -
  108         CRLF_NULLCHAR_LEN;
  109 
  110     if (error_msg == NULL) {
  111         *errmsg = NULL;
  112         return false;
  113     }
  114 
  115     if (settings.ssl_ctx == NULL) {
  116         snprintf(error_msg, errmax, "Error TLS not enabled\r\n");
  117         *errmsg = error_msg;
  118         return false;
  119     }
  120 
  121     char *ssl_err_msg = malloc(SSL_ERROR_MSG_SIZE);
  122     if (ssl_err_msg == NULL) {
  123         free(error_msg);
  124         *errmsg = NULL;
  125         return false;
  126     }
  127     bzero(ssl_err_msg, SSL_ERROR_MSG_SIZE);
  128     size_t err_msg_size = 0;
  129 
  130     SSL_LOCK();
  131     if (!SSL_CTX_use_certificate_chain_file(settings.ssl_ctx,
  132         settings.ssl_chain_cert)) {
  133         print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
  134         err_msg_size = snprintf(error_msg, errmax, "Error loading the certificate chain: "
  135             "%s : %s", settings.ssl_chain_cert, ssl_err_msg);
  136     } else if (!SSL_CTX_use_PrivateKey_file(settings.ssl_ctx, settings.ssl_key,
  137                                         settings.ssl_keyformat)) {
  138         print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
  139         err_msg_size = snprintf(error_msg, errmax, "Error loading the key: %s : %s",
  140             settings.ssl_key, ssl_err_msg);
  141     } else if (!SSL_CTX_check_private_key(settings.ssl_ctx)) {
  142         print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
  143         err_msg_size = snprintf(error_msg, errmax, "Error validating the certificate: %s",
  144             ssl_err_msg);
  145     } else if (settings.ssl_ca_cert) {
  146         if (!SSL_CTX_load_verify_locations(settings.ssl_ctx,
  147           settings.ssl_ca_cert, NULL)) {
  148             print_ssl_error(ssl_err_msg, SSL_ERROR_MSG_SIZE);
  149             err_msg_size = snprintf(error_msg, errmax,
  150               "Error loading the CA certificate: %s : %s",
  151               settings.ssl_ca_cert, ssl_err_msg);
  152         } else {
  153             SSL_CTX_set_client_CA_list(settings.ssl_ctx,
  154               SSL_load_client_CA_file(settings.ssl_ca_cert));
  155             success = true;
  156         }
  157     } else {
  158         success = true;
  159     }
  160     SSL_UNLOCK();
  161     free(ssl_err_msg);
  162     if (success) {
  163         settings.ssl_last_cert_refresh_time = current_time;
  164         free(error_msg);
  165     } else {
  166         *errmsg = error_msg;
  167         error_msg += (err_msg_size >= errmax ? errmax - 1: err_msg_size);
  168         snprintf(error_msg, CRLF_NULLCHAR_LEN, "\r\n");
  169         // Print if there are more errors and drain the queue.
  170         ERR_print_errors_fp(stderr);
  171     }
  172     return success;
  173 }
  174 
  175 /*
  176  * Verify SSL settings and initiates the SSL context.
  177  */
  178 int ssl_init(void) {
  179     assert(settings.ssl_enabled);
  180 
  181     // SSL context for the process. All connections will share one
  182     // process level context.
  183     settings.ssl_ctx = SSL_CTX_new(TLS_server_method());
  184 
  185     SSL_CTX_set_min_proto_version(settings.ssl_ctx, settings.ssl_min_version);
  186 
  187     // The server certificate, private key and validations.
  188     char *error_msg;
  189     if (!load_server_certificates(&error_msg)) {
  190         fprintf(stderr, "%s", error_msg);
  191         free(error_msg);
  192         exit(EX_USAGE);
  193     }
  194 
  195     // The verification mode of client certificate, default is SSL_VERIFY_PEER.
  196     SSL_CTX_set_verify(settings.ssl_ctx, settings.ssl_verify_mode, NULL);
  197     if (settings.ssl_ciphers && !SSL_CTX_set_cipher_list(settings.ssl_ctx,
  198                                                     settings.ssl_ciphers)) {
  199         fprintf(stderr, "Error setting the provided cipher(s): %s\n",
  200                 settings.ssl_ciphers);
  201         exit(EX_USAGE);
  202     }
  203 
  204     // Optional session caching; default disabled.
  205     if (settings.ssl_session_cache) {
  206         SSL_CTX_sess_set_new_cb(settings.ssl_ctx, ssl_new_session_callback);
  207         SSL_CTX_set_session_cache_mode(settings.ssl_ctx, SSL_SESS_CACHE_SERVER);
  208         SSL_CTX_set_session_id_context(settings.ssl_ctx,
  209                                        (const unsigned char *) SESSION_ID_CONTEXT,
  210                                        strlen(SESSION_ID_CONTEXT));
  211     } else {
  212         SSL_CTX_set_session_cache_mode(settings.ssl_ctx, SSL_SESS_CACHE_OFF);
  213     }
  214 
  215     return 0;
  216 }
  217 
  218 /*
  219  * This method is registered with each SSL connection and abort the SSL session
  220  * if a client initiates a renegotiation.
  221  * TODO : Proper way to do this is to set SSL_OP_NO_RENEGOTIATION
  222  *       using the SSL_CTX_set_options but that option only available in
  223  *       openssl 1.1.0h or above.
  224  */
  225 void ssl_callback(const SSL *s, int where, int ret) {
  226     SSL* ssl = (SSL*)s;
  227     if (SSL_in_before(ssl)) {
  228         fprintf(stderr, "%d: SSL renegotiation is not supported, "
  229                 "closing the connection\n", SSL_get_fd(ssl));
  230         SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
  231         return;
  232     }
  233 }
  234 
  235 /*
  236  * This method is invoked with every new successfully negotiated SSL session,
  237  * when server-side session caching is enabled. Note that this method is not
  238  * invoked when a session is reused.
  239  */
  240 int ssl_new_session_callback(SSL *s, SSL_SESSION *sess) {
  241     STATS_LOCK();
  242     stats.ssl_new_sessions++;
  243     STATS_UNLOCK();
  244 
  245     return 0;
  246 }
  247 
  248 bool refresh_certs(char **errmsg) {
  249     return load_server_certificates(errmsg);
  250 }
  251 
  252 const char *ssl_proto_text(int version) {
  253     switch (version) {
  254         case TLS1_VERSION:
  255             return "tlsv1.0";
  256         case TLS1_1_VERSION:
  257             return "tlsv1.1";
  258         case TLS1_2_VERSION:
  259             return "tlsv1.2";
  260 #if defined(TLS1_3_VERSION)
  261         case TLS1_3_VERSION:
  262             return "tlsv1.3";
  263 #endif
  264         default:
  265             return "unknown";
  266     }
  267 }
  268 #endif