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