@@ -502,6 +502,86 @@ static gboolean openssl_options_set_string(long *options, GString *s) {
502502
503503static int openssl_verify_any_cb (int ok , X509_STORE_CTX * ctx ) { UNUSED (ok ); UNUSED (ctx ); return 1 ; }
504504
505+ static gboolean creds_add_pemfile (liServer * srv , openssl_context * ctx , liValue * pemfile ) {
506+ const char * keyfile = NULL ;
507+ const char * certfile = NULL ;
508+
509+ if (LI_VALUE_STRING == li_value_type (pemfile )) {
510+ keyfile = pemfile -> data .string -> str ;
511+ certfile = pemfile -> data .string -> str ;
512+ } else if (li_value_list_len (pemfile ) >= 2 ) {
513+ if (NULL == (pemfile = li_value_to_key_value_list (pemfile ))) {
514+ ERROR (srv , "%s" , "openssl expects a hash/key-value list or a string as pemfile parameter" );
515+ return FALSE;
516+ }
517+
518+ LI_VALUE_FOREACH (entry , pemfile )
519+ liValue * entryKey = li_value_list_at (entry , 0 );
520+ liValue * entryValue = li_value_list_at (entry , 1 );
521+ GString * entryKeyStr ;
522+
523+ if (LI_VALUE_STRING != li_value_type (entryKey )) {
524+ ERROR (srv , "%s" , "openssl pemfile doesn't take default keys" );
525+ return FALSE;
526+ }
527+ entryKeyStr = entryKey -> data .string ; /* keys are either NONE or STRING */
528+
529+ if (g_str_equal (entryKeyStr -> str , "key" )) {
530+ if (LI_VALUE_STRING != li_value_type (entryValue )) {
531+ ERROR (srv , "%s" , "openssl pemfile.key expects a string as parameter" );
532+ return FALSE;
533+ }
534+ if (NULL != keyfile ) {
535+ ERROR (srv , "openssl unexpected duplicate parameter pemfile %s" , entryKeyStr -> str );
536+ return FALSE;
537+ }
538+ keyfile = entryValue -> data .string -> str ;
539+ } else if (g_str_equal (entryKeyStr -> str , "cert" )) {
540+ if (LI_VALUE_STRING != li_value_type (entryValue )) {
541+ ERROR (srv , "%s" , "openssl pemfile.cert expects a string as parameter" );
542+ return FALSE;
543+ }
544+ if (NULL != certfile ) {
545+ ERROR (srv , "openssl unexpected duplicate parameter pemfile %s" , entryKeyStr -> str );
546+ return FALSE;
547+ }
548+ certfile = entryValue -> data .string -> str ;
549+ } else {
550+ ERROR (srv , "invalid parameter for openssl: pemfile %s" , entryKeyStr -> str );
551+ return FALSE;
552+ }
553+ LI_VALUE_END_FOREACH ()
554+ } else {
555+ ERROR (srv , "%s" , "openssl expects a hash/key-value list (with at least \"key\" and \"cert\" entries) or a string as pemfile parameter" );
556+ return FALSE;
557+ }
558+
559+ if (NULL == keyfile || NULL == certfile ) {
560+ ERROR (srv , "%s" , "openssl: missing key or cert in pemfile parameter" );
561+ return FALSE;
562+ }
563+
564+ if (SSL_CTX_use_certificate_chain_file (ctx -> ssl_ctx , certfile ) < 0 ) {
565+ ERROR (srv , "SSL_CTX_use_certificate_chain_file('%s'): %s" , certfile ,
566+ ERR_error_string (ERR_get_error (), NULL ));
567+ return FALSE;
568+ }
569+
570+ if (SSL_CTX_use_PrivateKey_file (ctx -> ssl_ctx , keyfile , SSL_FILETYPE_PEM ) < 0 ) {
571+ ERROR (srv , "SSL_CTX_use_PrivateKey_file('%s'): %s" , keyfile ,
572+ ERR_error_string (ERR_get_error (), NULL ));
573+ return FALSE;
574+ }
575+
576+ if (SSL_CTX_check_private_key (ctx -> ssl_ctx ) != 1 ) {
577+ ERROR (srv , "SSL: Private key '%s' does not match the certificate public key '%s', reason: %s" , keyfile , certfile ,
578+ ERR_error_string (ERR_get_error (), NULL ));
579+ return FALSE;
580+ }
581+
582+ return TRUE;
583+ }
584+
505585static gboolean openssl_setup (liServer * srv , liPlugin * p , liValue * val , gpointer userdata ) {
506586 openssl_context * ctx ;
507587 STACK_OF (X509_NAME ) * client_ca_list ;
@@ -515,9 +595,10 @@ static gboolean openssl_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
515595 have_verify_parameter = FALSE,
516596 have_verify_depth_parameter = FALSE,
517597 have_verify_any_parameter = FALSE,
518- have_verify_require_parameter = FALSE;
598+ have_verify_require_parameter = FALSE,
599+ have_pemfile_parameter = FALSE;
519600 const char
520- * ciphers = NULL , * pemfile = NULL , * ca_file = NULL , * client_ca_file = NULL , * dh_params_file = NULL , * ecdh_curve = NULL ;
601+ * ciphers = NULL , * ca_file = NULL , * client_ca_file = NULL , * dh_params_file = NULL , * ecdh_curve = NULL ;
521602 long
522603 options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE
523604#ifdef SSL_OP_NO_COMPRESSION
@@ -559,15 +640,7 @@ static gboolean openssl_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
559640 }
560641 have_listen_parameter = TRUE;
561642 } else if (g_str_equal (entryKeyStr -> str , "pemfile" )) {
562- if (LI_VALUE_STRING != li_value_type (entryValue )) {
563- ERROR (srv , "%s" , "openssl pemfile expects a string as parameter" );
564- return FALSE;
565- }
566- if (NULL != pemfile ) {
567- ERROR (srv , "openssl unexpected duplicate parameter %s" , entryKeyStr -> str );
568- return FALSE;
569- }
570- pemfile = entryValue -> data .string -> str ;
643+ have_pemfile_parameter = TRUE;
571644 } else if (g_str_equal (entryKeyStr -> str , "ca-file" )) {
572645 if (LI_VALUE_STRING != li_value_type (entryValue )) {
573646 ERROR (srv , "%s" , "openssl ca-file expects a string as parameter" );
@@ -698,7 +771,7 @@ static gboolean openssl_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
698771 return FALSE;
699772 }
700773
701- if (NULL == pemfile ) {
774+ if (! have_pemfile_parameter ) {
702775 ERROR (srv , "%s" , "openssl needs a pemfile" );
703776 return FALSE;
704777 }
@@ -736,23 +809,20 @@ static gboolean openssl_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
736809 }
737810 }
738811
739- if (SSL_CTX_use_certificate_file (ctx -> ssl_ctx , pemfile , SSL_FILETYPE_PEM ) < 0 ) {
740- ERROR (srv , "SSL_CTX_use_certificate_file('%s'): %s" , pemfile ,
741- ERR_error_string (ERR_get_error (), NULL ));
742- goto error_free_socket ;
743- }
812+ LI_VALUE_FOREACH (entry , val )
813+ liValue * entryKey = li_value_list_at (entry , 0 );
814+ liValue * entryValue = li_value_list_at (entry , 1 );
815+ GString * entryKeyStr ;
744816
745- if (SSL_CTX_use_PrivateKey_file (ctx -> ssl_ctx , pemfile , SSL_FILETYPE_PEM ) < 0 ) {
746- ERROR (srv , "SSL_CTX_use_PrivateKey_file('%s'): %s" , pemfile ,
747- ERR_error_string (ERR_get_error (), NULL ));
748- goto error_free_socket ;
749- }
817+ if (LI_VALUE_STRING != li_value_type (entryKey )) continue ;
818+ entryKeyStr = entryKey -> data .string ; /* keys are either NONE or STRING */
750819
751- if (SSL_CTX_check_private_key (ctx -> ssl_ctx ) != 1 ) {
752- ERROR (srv , "SSL: Private key '%s' does not match the certificate public key, reason: %s" , pemfile ,
753- ERR_error_string (ERR_get_error (), NULL ));
754- goto error_free_socket ;
755- }
820+ if (g_str_equal (entryKeyStr -> str , "pemfile" )) {
821+ if (!creds_add_pemfile (srv , ctx , entryValue )) {
822+ goto error_free_socket ;
823+ }
824+ }
825+ LI_VALUE_END_FOREACH ()
756826
757827 if (SSL_CTX_set_session_id_context (ctx -> ssl_ctx , CONST_USTR_LEN ("lighttpd" )) != 1 ) {
758828 ERROR (srv , "SSL_CTX_set_session_id_context(): %s" , ERR_error_string (ERR_get_error (), NULL ));
0 commit comments