2727
2828#include < openssl/bio.h>
2929#include < openssl/dh.h>
30+ #include < openssl/x509v3.h>
3031
3132#ifdef WIN32
3233#include " winsock.h"
@@ -157,6 +158,8 @@ String Ssl::generate_cert(const String& key, String cn, String ca_cert, String c
157158 { // Read CA from string
158159 BIO* bio = BIO_new_mem_buf (const_cast <char *>(ca_cert.c_str ()), ca_cert.length ());
159160 if (!PEM_read_bio_X509 (bio, &x509_ca, NULL , NULL )) {
161+ X509_free (x509);
162+ X509_REQ_free (x509_req);
160163 BIO_free (bio);
161164 return " " ;
162165 }
@@ -169,6 +172,9 @@ String Ssl::generate_cert(const String& key, String cn, String ca_cert, String c
169172 BIO* bio = BIO_new_mem_buf (const_cast <char *>(ca_key.c_str ()), ca_key.length ());
170173 if (!PEM_read_bio_PrivateKey (bio, &pkey_ca, NULL , NULL )) {
171174 BIO_free (bio);
175+ X509_free (x509);
176+ X509_free (x509_ca);
177+ X509_REQ_free (x509_req);
172178 return " " ;
173179 }
174180 BIO_free (bio);
@@ -178,6 +184,21 @@ String Ssl::generate_cert(const String& key, String cn, String ca_cert, String c
178184 X509_free (x509_ca);
179185 EVP_PKEY_free (pkey_ca);
180186 } else {
187+ if (cn == " CA" ) { // Set the purpose as a CA certificate.
188+ X509_EXTENSION* x509_ex;
189+ X509V3_CTX x509v3_ctx;
190+ X509V3_set_ctx_nodb (&x509v3_ctx);
191+ X509V3_set_ctx (&x509v3_ctx, x509, x509, NULL , NULL , 0 );
192+ x509_ex = X509V3_EXT_conf_nid (NULL , &x509v3_ctx, NID_basic_constraints,
193+ const_cast <char *>(" critical,CA:TRUE" ));
194+ if (!x509_ex) {
195+ X509_free (x509);
196+ X509_EXTENSION_free (x509_ex);
197+ return " " ;
198+ }
199+ X509_add_ext (x509, x509_ex, -1 );
200+ X509_EXTENSION_free (x509_ex);
201+ }
181202 X509_NAME* name = X509_get_subject_name (x509);
182203 X509_NAME_add_entry_by_txt (name, " C" , MBSTRING_ASC,
183204 reinterpret_cast <const unsigned char *>(" US" ), -1 , -1 , 0 );
@@ -214,6 +235,18 @@ static void print_ssl_error() {
214235 fprintf (stderr, " %s\n " , buf);
215236}
216237
238+ static X509* load_cert (const String& cert) {
239+ X509* x509 = NULL ;
240+ BIO* bio = BIO_new_mem_buf (const_cast <char *>(cert.c_str ()), cert.length ());
241+ if (PEM_read_bio_X509 (bio, &x509, NULL , NULL ) == NULL ) {
242+ print_ssl_error ();
243+ BIO_free (bio);
244+ return NULL ;
245+ }
246+ BIO_free (bio);
247+ return x509;
248+ }
249+
217250struct WriteReq {
218251 WriteReq (const char * data, size_t len, ClientConnection* connection)
219252 : data(data, len)
@@ -450,8 +483,8 @@ uv_loop_t* ServerConnection::loop() {
450483}
451484
452485bool ServerConnection::use_ssl (const String& key, const String& cert,
453- const String& password /* = ""*/ ,
454- const String& client_cert /* = "" */ ) {
486+ const String& ca_cert /* = ""*/ ,
487+ bool require_client_cert /* = false */ ) {
455488 if (ssl_context_) {
456489 SSL_CTX_free (ssl_context_);
457490 }
@@ -461,31 +494,43 @@ bool ServerConnection::use_ssl(const String& key, const String& cert,
461494 return false ;
462495 }
463496
464- SSL_CTX_set_default_passwd_cb_userdata (ssl_context_, (void *)password. c_str () );
497+ SSL_CTX_set_default_passwd_cb_userdata (ssl_context_, (void *)" " );
465498 SSL_CTX_set_default_passwd_cb (ssl_context_, on_password);
499+ SSL_CTX_set_verify (ssl_context_, SSL_VERIFY_NONE, NULL );
466500
467- X509* x509 = NULL ;
468- { // Read cert from string
469- BIO* bio = BIO_new_mem_buf ( const_cast < char *>(cert. c_str ()), cert. length ()) ;
470- if (PEM_read_bio_X509 (bio, & x509, NULL , NULL ) == NULL ) {
501+ { // Load server certificate
502+ X509* x509 = load_cert (cert);
503+ if (!x509) return false ;
504+ if (SSL_CTX_use_certificate (ssl_context_, x509) <= 0 ) {
471505 print_ssl_error ();
472- BIO_free (bio );
506+ X509_free (x509 );
473507 return false ;
474508 }
475- BIO_free (bio );
509+ X509_free (x509 );
476510 }
477511
478- if (SSL_CTX_use_certificate (ssl_context_, x509) <= 0 ) {
479- print_ssl_error ();
480- X509_free (x509);
481- return false ;
512+ if (!ca_cert.empty ()) { // Load CA certificate
513+ X509* x509 = load_cert (ca_cert);
514+ if (!x509) return false ;
515+ if (SSL_CTX_add_extra_chain_cert (ssl_context_, x509) <= 0 ) { // Certificate freed by function
516+ print_ssl_error ();
517+ X509_free (x509);
518+ return false ;
519+ }
520+ if (require_client_cert) {
521+ X509_STORE* cert_store = SSL_CTX_get_cert_store (ssl_context_);
522+ if (X509_STORE_add_cert (cert_store, x509) <= 0 ) {
523+ print_ssl_error ();
524+ return false ;
525+ }
526+ SSL_CTX_set_verify (ssl_context_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL );
527+ }
482528 }
483- X509_free (x509);
484529
485530 EVP_PKEY* pkey = NULL ;
486531 { // Read key from string
487532 BIO* bio = BIO_new_mem_buf (const_cast <char *>(key.c_str ()), key.length ());
488- if (PEM_read_bio_PrivateKey (bio, &pkey, on_password, (void *)password. c_str () ) == NULL ) {
533+ if (PEM_read_bio_PrivateKey (bio, &pkey, on_password, (void *)" " ) == NULL ) {
489534 print_ssl_error ();
490535 BIO_free (bio);
491536 return false ;
@@ -508,43 +553,6 @@ bool ServerConnection::use_ssl(const String& key, const String& cert,
508553 }
509554 DH_free (dh);
510555
511- if (!client_cert.empty ()) {
512- X509_STORE* trust_store = SSL_CTX_get_cert_store (static_cast <const SSL_CTX*>(ssl_context_));
513- STACK_OF (X509_INFO) * stack_info;
514-
515- { // Read cert from string
516- BIO* bio = BIO_new_mem_buf (const_cast <char *>(client_cert.c_str ()), client_cert.size ());
517- if ((stack_info = PEM_X509_INFO_read_bio (bio, NULL , NULL , NULL )) == NULL ) {
518- print_ssl_error ();
519- BIO_free (bio);
520- return false ;
521- }
522- BIO_free (bio);
523- }
524-
525- if (stack_info) {
526- for (int i = 0 ; i < sk_X509_INFO_num (stack_info); i++) {
527- X509_INFO* info = sk_X509_INFO_value (stack_info, i);
528- if (info->x509 ) {
529- if (X509_STORE_add_cert (trust_store, info->x509 ) <= 0 ) {
530- print_ssl_error ();
531- return false ;
532- }
533- }
534- if (info->crl ) {
535- if (X509_STORE_add_crl (trust_store, info->crl ) <= -0 ) {
536- print_ssl_error ();
537- return false ;
538- }
539- }
540- }
541- }
542-
543- sk_X509_INFO_pop_free (stack_info, X509_INFO_free);
544- }
545-
546- SSL_CTX_set_verify (ssl_context_, SSL_VERIFY_NONE, 0 );
547-
548556 return true ;
549557}
550558
0 commit comments