"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