1 #include "uwsgi.h"
2 #include <openssl/rand.h>
3 #include <openssl/sha.h>
4 #include <openssl/md5.h>
5 
6 extern struct uwsgi_server uwsgi;
7 /*
8 
9 ssl additional datas are retrieved via indexes.
10 
11 You can create an index with SSL_CTX_get_ex_new_index and
12 set data in it with SSL_CTX_set_ex_data
13 
14 */
15 
uwsgi_ssl_init(void)16 void uwsgi_ssl_init(void) {
17 #if OPENSSL_VERSION_NUMBER < 0x10100000L
18         OPENSSL_config(NULL);
19 #endif
20         SSL_library_init();
21         SSL_load_error_strings();
22         OpenSSL_add_all_algorithms();
23         uwsgi.ssl_initialized = 1;
24 }
25 
26 #if OPENSSL_VERSION_NUMBER < 0x10100000L
uwsgi_ssl_info_cb(const SSL * ssl,int where,int ret)27 void uwsgi_ssl_info_cb(const SSL *ssl, int where, int ret) {
28         if (where & SSL_CB_HANDSHAKE_DONE) {
29                 if (ssl->s3) {
30                         ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
31                 }
32         }
33 }
34 #endif
35 
uwsgi_ssl_verify_callback(int ok,X509_STORE_CTX * x509_store)36 int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) {
37         if (!ok && uwsgi.ssl_verbose) {
38                 char buf[256];
39                 X509 *err_cert;
40                 int depth;
41                 int err;
42                 depth = X509_STORE_CTX_get_error_depth(x509_store);
43                 err_cert = X509_STORE_CTX_get_current_cert(x509_store);
44                 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
45                 err = X509_STORE_CTX_get_error(x509_store);
46                 uwsgi_log("[uwsgi-ssl] client certificate verify error: num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf);
47         }
48         return ok;
49 }
50 
51 #ifdef UWSGI_SSL_SESSION_CACHE
uwsgi_ssl_session_new_cb(SSL * ssl,SSL_SESSION * sess)52 int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) {
53         char session_blob[4096];
54         int len = i2d_SSL_SESSION(sess, NULL);
55         if (len > 4096) {
56                 if (uwsgi.ssl_verbose) {
57                         uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len);
58                 }
59                 return 0;
60         }
61 
62         unsigned char *p = (unsigned char *) session_blob;
63         i2d_SSL_SESSION(sess, &p);
64 
65         // ok let's write the value to the cache
66         uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
67         if (uwsgi_cache_set2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) {
68                 if (uwsgi.ssl_verbose) {
69                         uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len);
70                 }
71         }
72         uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
73         return 0;
74 }
75 
uwsgi_ssl_session_get_cb(SSL * ssl,unsigned char * key,int keylen,int * copy)76 SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) {
77 
78         uint64_t valsize = 0;
79 
80         *copy = 0;
81         uwsgi_rlock(uwsgi.ssl_sessions_cache->lock);
82         char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize);
83         if (!value) {
84                 uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
85                 if (uwsgi.ssl_verbose) {
86                         uwsgi_log("[uwsgi-ssl] cache miss\n");
87                 }
88                 return NULL;
89         }
90 #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
91         SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize);
92 #else
93         SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (unsigned char **)&value, valsize);
94 #endif
95         uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
96         return sess;
97 }
98 
uwsgi_ssl_session_remove_cb(SSL_CTX * ctx,SSL_SESSION * sess)99 void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
100         uwsgi_wlock(uwsgi.ssl_sessions_cache->lock);
101         if (uwsgi_cache_del2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, 0, 0)) {
102                 if (uwsgi.ssl_verbose) {
103                         uwsgi_log("[uwsgi-ssl] error removing cache item\n");
104                 }
105         }
106         uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock);
107 }
108 #endif
109 
110 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
uwsgi_sni_cb(SSL * ssl,int * ad,void * arg)111 static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) {
112         const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
113         if (!servername) return SSL_TLSEXT_ERR_NOACK;
114         size_t servername_len = strlen(servername);
115 	// reduce DOS attempts
116 	int count = 5;
117 
118 	while(count > 0) {
119         	struct uwsgi_string_list *usl = uwsgi.sni;
120         	while(usl) {
121                 	if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) {
122                         	SSL_set_SSL_CTX(ssl, (SSL_CTX *) usl->custom_ptr);
123 				// the following steps are taken from nginx
124 				SSL_set_verify(ssl, SSL_CTX_get_verify_mode((SSL_CTX *)usl->custom_ptr),
125 				SSL_CTX_get_verify_callback((SSL_CTX *)usl->custom_ptr));
126 				SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth((SSL_CTX *)usl->custom_ptr));
127 #ifdef SSL_CTRL_CLEAR_OPTIONS
128 				SSL_clear_options(ssl, SSL_get_options(ssl) & ~SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr));
129 #endif
130 				SSL_set_options(ssl, SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr));
131                         	return SSL_TLSEXT_ERR_OK;
132                 	}
133                 	usl = usl->next;
134         	}
135 		if (!uwsgi.subscription_dotsplit) break;
136 		char *next = memchr(servername+1, '.', servername_len-1);
137 		if (next) {
138 			servername_len -= next - servername;
139 			servername = next;
140 			count--;
141 			continue;
142 		}
143 		break;
144 	}
145 
146 	if (uwsgi.subscription_dotsplit) goto end;
147 
148 #ifdef UWSGI_PCRE
149         struct uwsgi_regexp_list *url = uwsgi.sni_regexp;
150         while(url) {
151                 if (uwsgi_regexp_match(url->pattern, url->pattern_extra, (char *)servername, servername_len) >= 0) {
152                         SSL_set_SSL_CTX(ssl, url->custom_ptr);
153                         return SSL_TLSEXT_ERR_OK;
154                 }
155                 url = url->next;
156         }
157 #endif
158 
159 	if (uwsgi.sni_dir) {
160 		size_t sni_dir_len = strlen(uwsgi.sni_dir);
161 		char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4);
162 		char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4);
163 		char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3);
164 		if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) {
165 			char *client_ca = NULL;
166 			if (uwsgi_file_exists(sni_dir_client_ca)) {
167 				client_ca = sni_dir_client_ca;
168 			}
169 			struct uwsgi_string_list *usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca);
170 			if (!usl) goto done;
171 			free(sni_dir_cert);
172 			free(sni_dir_key);
173 			free(sni_dir_client_ca);
174 			SSL_set_SSL_CTX(ssl, usl->custom_ptr);
175 			return SSL_TLSEXT_ERR_OK;
176 		}
177 done:
178 		free(sni_dir_cert);
179 		free(sni_dir_key);
180 		free(sni_dir_client_ca);
181 	}
182 end:
183         return SSL_TLSEXT_ERR_NOACK;
184 }
185 #endif
186 
uwsgi_write_pem_to_file(char * name,char * buf,size_t len,char * ext)187 char *uwsgi_write_pem_to_file(char *name, char *buf, size_t len, char *ext) {
188 	if (!uwsgi.ssl_tmp_dir) return NULL;
189 	char *filename = uwsgi_concat4(uwsgi.ssl_tmp_dir, "/", name, ext);
190 	int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR);
191 	if (fd < 0) {
192 		uwsgi_error_open(filename);
193 		free(filename);
194 		return NULL;
195 	}
196 
197 	if (write(fd, buf, len) != (ssize_t) len) {
198 		uwsgi_log("unable to write pem data in file %s\n", filename);
199 		uwsgi_error("uwsgi_write_pem_to_file()/write()");
200 		free(filename);
201 		close(fd);
202                 return NULL;
203 	}
204 
205 	close(fd);
206 	return filename;
207 }
208 
uwsgi_ssl_new_server_context(char * name,char * crt,char * key,char * ciphers,char * client_ca)209 SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
210 
211 	int crt_need_free = 0;
212 	int key_need_free = 0;
213 	int client_ca_need_free = 0;
214 
215         SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
216         if (!ctx) {
217                 uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name);
218                 return NULL;
219         }
220 
221         // this part is taken from nginx and stud, removing unneeded functionality
222         // stud (for me) has made the best choice on choosing DH approach
223 
224         long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
225 // disable compression (if possibile)
226 #ifdef SSL_OP_NO_COMPRESSION
227         ssloptions |= SSL_OP_NO_COMPRESSION;
228 #endif
229 
230 	if (!uwsgi.sslv3) {
231 		ssloptions |= SSL_OP_NO_SSLv3;
232 	}
233 
234 	if (!uwsgi.tlsv1) {
235 		ssloptions |= SSL_OP_NO_TLSv1;
236 	}
237 
238 // release/reuse buffers as soon as possibile
239 #ifdef SSL_MODE_RELEASE_BUFFERS
240         SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
241 #endif
242 
243 	/*
244 		we need to support both file-based certs and stream based
245 		as dealing with openssl memory bio for keys is really overkill,
246 		we store them in a tmp directory
247 	*/
248 
249 	if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(crt, strlen(crt), "-----BEGIN ", 11)) {
250 		crt = uwsgi_write_pem_to_file(name, crt, strlen(crt), ".crt");
251 		if (!crt) {
252 			SSL_CTX_free(ctx);
253                 	return NULL;
254 		}
255 		crt_need_free = 1;
256 	}
257 
258         if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) {
259                	uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name);
260                	SSL_CTX_free(ctx);
261 		if (crt_need_free) free(crt);
262                	return NULL;
263         }
264 
265 // this part is based from stud
266         BIO *bio = BIO_new_file(crt, "r");
267         if (bio) {
268                 DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
269                 BIO_free(bio);
270                 if (dh) {
271                         SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
272                         SSL_CTX_set_tmp_dh(ctx, dh);
273                         DH_free(dh);
274                 }
275         }
276 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
277 #ifndef OPENSSL_NO_ECDH
278 #ifdef NID_X9_62_prime256v1
279         EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
280         if (ecdh) {
281                 SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
282                 SSL_CTX_set_tmp_ecdh(ctx, ecdh);
283                 EC_KEY_free(ecdh);
284         }
285 #endif
286 #endif
287 #endif
288 
289 	if (crt_need_free) free(crt);
290 
291 	if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(key, strlen(key), "-----BEGIN ", 11)) {
292                 key = uwsgi_write_pem_to_file(name, key, strlen(key), ".key");
293                 if (!key) {
294                         SSL_CTX_free(ctx);
295                         return NULL;
296                 }
297                 key_need_free = 1;
298         }
299 
300         if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
301                 uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name);
302                 SSL_CTX_free(ctx);
303 		if (key_need_free) free(key);
304                 return NULL;
305         }
306 
307 	if (key_need_free) free(key);
308 
309 	// if ciphers are specified, prefer server ciphers
310         if (ciphers && strlen(ciphers) > 0) {
311                 if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
312                         uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name);
313                         SSL_CTX_free(ctx);
314                         return NULL;
315                 }
316 
317                 ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
318         }
319 
320         // set session context (if possibile), this is required for client certificate authentication
321         if (name) {
322                 SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name));
323         }
324 
325         if (client_ca) {
326                 if (client_ca[0] == '!') {
327                         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback);
328                         client_ca++;
329                 }
330                 else {
331                         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback);
332                 }
333                 SSL_CTX_set_verify_depth(ctx, uwsgi.ssl_verify_depth);
334 
335 		if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(client_ca, strlen(client_ca), "-----BEGIN ", 11)) {
336 			if (!name) {
337                         	SSL_CTX_free(ctx);
338                         	return NULL;
339 			}
340                 	client_ca = uwsgi_write_pem_to_file(name, client_ca, strlen(client_ca), ".ca");
341                 	if (!client_ca) {
342                         	SSL_CTX_free(ctx);
343                         	return NULL;
344                 	}
345                 	client_ca_need_free = 1;
346         	}
347 
348                 if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) {
349                         uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name);
350                         SSL_CTX_free(ctx);
351 			if (client_ca_need_free) free(client_ca);
352                         return NULL;
353                 }
354                 STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca);
355                 if (!list) {
356                         uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name);
357                         SSL_CTX_free(ctx);
358 			if (client_ca_need_free) free(client_ca);
359                         return NULL;
360                 }
361 
362                 SSL_CTX_set_client_CA_list(ctx, list);
363 
364 		if (client_ca_need_free) free(client_ca);
365         }
366 
367 
368 #if OPENSSL_VERSION_NUMBER < 0x10100000L
369         SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb);
370 #endif
371 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
372         SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb);
373 #endif
374 
375         // disable session caching by default
376         SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
377 
378 #ifdef UWSGI_SSL_SESSION_CACHE
379 	if (uwsgi.ssl_sessions_use_cache) {
380 
381 		// we need to early initialize locking and caching
382 		uwsgi_setup_locking();
383 		uwsgi_cache_create_all();
384 
385 		uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache);
386 		if (!uwsgi.ssl_sessions_cache) {
387 			// check for default cache
388 			if (!strcmp(uwsgi.ssl_sessions_use_cache, "true") && uwsgi.caches) {
389 				uwsgi.ssl_sessions_cache = uwsgi.caches;
390 			}
391 			else {
392 				uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default");
393 				exit(1);
394 			}
395 		}
396 
397                 if (!uwsgi.ssl_sessions_cache->max_items) {
398                         uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n");
399                         exit(1);
400                 }
401 
402                 if (uwsgi.ssl_sessions_cache->blocksize < 4096) {
403                         uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n");
404                         exit(1);
405                 }
406 
407                 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER|
408                         SSL_SESS_CACHE_NO_INTERNAL|
409                         SSL_SESS_CACHE_NO_AUTO_CLEAR);
410 
411 #ifdef SSL_OP_NO_TICKET
412                 ssloptions |= SSL_OP_NO_TICKET;
413 #endif
414 
415                 // just for fun
416                 SSL_CTX_sess_set_cache_size(ctx, 0);
417 
418                 // set the callback for ssl sessions
419                 SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb);
420                 SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb);
421                 SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb);
422         }
423 #endif
424 
425         SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout);
426 
427 	struct uwsgi_string_list *usl = NULL;
428 	uwsgi_foreach(usl, uwsgi.ssl_options) {
429 		ssloptions |= atoi(usl->value);
430 	}
431 
432         SSL_CTX_set_options(ctx, ssloptions);
433 
434 
435         return ctx;
436 }
437 
438 
uwsgi_rsa_sign(char * algo_key,char * message,size_t message_len,unsigned int * s_len)439 char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) {
440 
441         // openssl could not be initialized
442         if (!uwsgi.ssl_initialized) {
443                 uwsgi_ssl_init();
444         }
445 
446         *s_len = 0;
447         EVP_PKEY *pk = NULL;
448 
449         char *algo = uwsgi_str(algo_key);
450         char *colon = strchr(algo, ':');
451         if (!colon) {
452                 uwsgi_log("invalid RSA signature syntax, must be: <digest>:<pemfile>\n");
453                 free(algo);
454                 return NULL;
455         }
456 
457         *colon = 0;
458         char *keyfile = colon + 1;
459         char *signature = NULL;
460 
461         FILE *kf = fopen(keyfile, "r");
462         if (!kf) {
463                 uwsgi_error_open(keyfile);
464                 free(algo);
465                 return NULL;
466         }
467 
468         if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) {
469                 uwsgi_log("unable to load private key: %s\n", keyfile);
470                 free(algo);
471                 fclose(kf);
472                 return NULL;
473         }
474 
475         fclose(kf);
476 
477         EVP_MD_CTX *ctx = EVP_MD_CTX_create();
478         if (!ctx) {
479                 free(algo);
480                 EVP_PKEY_free(pk);
481                 return NULL;
482         }
483 
484         const EVP_MD *md = EVP_get_digestbyname(algo);
485         if (!md) {
486                 uwsgi_log("unknown digest algo: %s\n", algo);
487                 free(algo);
488                 EVP_PKEY_free(pk);
489                 EVP_MD_CTX_destroy(ctx);
490                 return NULL;
491         }
492 
493         *s_len = EVP_PKEY_size(pk);
494         signature = uwsgi_malloc(*s_len);
495 
496 	if (EVP_SignInit_ex(ctx, md, NULL) == 0) {
497                 ERR_print_errors_fp(stderr);
498                 free(signature);
499                 signature = NULL;
500                 *s_len = 0;
501                 goto clear;
502         }
503 
504         if (EVP_SignUpdate(ctx, message, message_len) == 0) {
505                 ERR_print_errors_fp(stderr);
506                 free(signature);
507                 signature = NULL;
508                 *s_len = 0;
509                 goto clear;
510         }
511 
512 
513         if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) {
514                 ERR_print_errors_fp(stderr);
515                 free(signature);
516                 signature = NULL;
517                 *s_len = 0;
518                 goto clear;
519         }
520 
521 clear:
522         free(algo);
523         EVP_PKEY_free(pk);
524         EVP_MD_CTX_destroy(ctx);
525         return signature;
526 
527 }
528 
uwsgi_sanitize_cert_filename(char * base,char * key,uint16_t keylen)529 char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) {
530         uint16_t i;
531         char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5);
532 
533         for (i = strlen(base) + 1; i < (strlen(base) + 1) + keylen; i++) {
534                 if (filename[i] >= '0' && filename[i] <= '9')
535                         continue;
536                 if (filename[i] >= 'A' && filename[i] <= 'Z')
537                         continue;
538                 if (filename[i] >= 'a' && filename[i] <= 'z')
539                         continue;
540                 if (filename[i] == '.')
541                         continue;
542                 if (filename[i] == '-')
543                         continue;
544                 if (filename[i] == '_')
545                         continue;
546                 filename[i] = '_';
547         }
548 
549         return filename;
550 }
551 
uwsgi_ssl_rand(size_t len)552 char *uwsgi_ssl_rand(size_t len) {
553 	unsigned char *buf = uwsgi_calloc(len);
554 	if (RAND_bytes(buf, len) <= 0) {
555 		free(buf);
556 		return NULL;
557 	}
558 	return (char *) buf;
559 }
560 
uwsgi_sha1(char * src,size_t len,char * dst)561 char *uwsgi_sha1(char *src, size_t len, char *dst) {
562         SHA_CTX sha;
563         SHA1_Init(&sha);
564         SHA1_Update(&sha, src, len);
565         SHA1_Final((unsigned char *)dst, &sha);
566 	return dst;
567 }
568 
uwsgi_md5(char * src,size_t len,char * dst)569 char *uwsgi_md5(char *src, size_t len, char *dst) {
570 	MD5_CTX md5;
571 	MD5_Init(&md5);
572 	MD5_Update(&md5, src, len);
573 	MD5_Final((unsigned char *)dst, &md5);
574 	return dst;
575 }
576 
uwsgi_sha1_2n(char * s1,size_t len1,char * s2,size_t len2,char * dst)577 char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) {
578         SHA_CTX sha;
579         SHA1_Init(&sha);
580         SHA1_Update(&sha, s1, len1);
581         SHA1_Update(&sha, s2, len2);
582         SHA1_Final((unsigned char *)dst, &sha);
583         return dst;
584 }
585 
uwsgi_opt_sni(char * opt,char * value,void * foobar)586 void uwsgi_opt_sni(char *opt, char *value, void *foobar) {
587         char *client_ca = NULL;
588         char *v = uwsgi_str(value);
589 
590         char *space = strchr(v, ' ');
591         if (!space) {
592                 uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
593                 exit(1);
594         }
595         *space = 0;
596         char *crt = space+1;
597         char *key = strchr(crt, ',');
598         if (!key) {
599                 uwsgi_log("invalid %s syntax, must be sni_key<space>crt,key[,ciphers,client_ca]\n", opt);
600                 exit(1);
601         }
602         *key = '\0'; key++;
603 
604         char *ciphers = strchr(key, ',');
605         if (ciphers) {
606                 *ciphers = '\0'; ciphers++;
607                 client_ca = strchr(ciphers, ',');
608                 if (client_ca) {
609                         *client_ca = '\0'; client_ca++;
610                 }
611         }
612 
613         if (!uwsgi.ssl_initialized) {
614                 uwsgi_ssl_init();
615         }
616 
617         SSL_CTX *ctx = uwsgi_ssl_new_server_context(v, crt, key, ciphers, client_ca);
618         if (!ctx) {
619                 uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", v);
620                 free(v);
621                 return;
622         }
623 
624 #ifdef UWSGI_PCRE
625         if (!strcmp(opt, "sni-regexp")) {
626                 struct uwsgi_regexp_list *url = uwsgi_regexp_new_list(&uwsgi.sni_regexp, v);
627                 url->custom_ptr = ctx;
628         }
629         else {
630 #endif
631                 struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, v);
632                 usl->custom_ptr = ctx;
633 #ifdef UWSGI_PCRE
634         }
635 #endif
636 
637 }
638 
uwsgi_ssl_add_sni_item(char * name,char * crt,char * key,char * ciphers,char * client_ca)639 struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *key, char *ciphers, char *client_ca) {
640 	if (!uwsgi.ssl_initialized) {
641                 uwsgi_ssl_init();
642         }
643 	SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca);
644         if (!ctx) {
645                 uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name);
646 		free(name);
647 		return NULL;
648 	}
649 
650 	struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name);
651 	usl->custom_ptr = ctx;
652 	// mark it as dynamic
653 	usl->custom = 1;
654 	uwsgi_log_verbose("[uwsgi-sni for pid %d] added SSL context for %s\n", (int) getpid(), name);
655 	return usl;
656 }
657 
uwsgi_ssl_del_sni_item(char * name,uint16_t name_len)658 void uwsgi_ssl_del_sni_item(char *name, uint16_t name_len) {
659 	struct uwsgi_string_list *usl = NULL, *last_sni = NULL, *sni_item = NULL;
660 	uwsgi_foreach(usl, uwsgi.sni) {
661 		if (!uwsgi_strncmp(usl->value, usl->len, name, name_len) && usl->custom) {
662 			sni_item = usl;
663 			break;
664 		}
665 		last_sni = usl;
666 	}
667 
668 	if (!sni_item) return;
669 
670 	if (last_sni) {
671 		last_sni->next = sni_item->next;
672 	}
673 	else {
674 		uwsgi.sni = sni_item->next;
675 	}
676 
677 	// we are free to destroy it as no more clients are using it
678 	SSL_CTX_free((SSL_CTX *) sni_item->custom_ptr);
679 	free(sni_item->value);
680 	free(sni_item);
681 
682 	uwsgi_log_verbose("[uwsgi-sni for pid %d] destroyed SSL context for %s\n",(int) getpid(), name);
683 }
684