@@ -126,21 +126,63 @@ static int ap_array_same_str_set(apr_array_header_t *s1, apr_array_header_t *s2)
126126 return 1 ;
127127}
128128
129- static int ssl_pk_server_compatible (modssl_pk_server_t * pks1 ,
130- modssl_pk_server_t * pks2 )
129+ #ifdef HAVE_SSL_CONF_CMD
130+ static int array_contains_ssl_param (apr_array_header_t * a ,
131+ const char * name , const char * value )
131132{
132- if (!pks1 || !pks2 ) {
133+ int n ;
134+
135+ for (n = 0 ; n < a -> nelts ; n ++ ) {
136+ ssl_ctx_param_t * p = & APR_ARRAY_IDX (a , n , ssl_ctx_param_t );
137+
138+ if (strcmp (p -> name , name ) == 0 && strcmp (p -> value , value ) == 0 )
139+ return 1 ;
140+ }
141+
142+ return 0 ;
143+ }
144+
145+ /* Return non-zero if the two ssl_ctx_param arrays match exactly, else
146+ * zero. */
147+ static int array_cmp_ssl_ctx_params (apr_array_header_t * a1 ,
148+ apr_array_header_t * a2 )
149+ {
150+ int n ;
151+
152+ if (a1 == a2 )
153+ return 1 ;
154+ if (a1 -> nelts != a2 -> nelts )
133155 return 0 ;
156+
157+ for (n = 0 ; n < a1 -> nelts ; n ++ ) {
158+ ssl_ctx_param_t * p = & APR_ARRAY_IDX (a1 , n , ssl_ctx_param_t );
159+
160+ if (!array_contains_ssl_param (a2 , p -> name , p -> value ))
161+ return 0 ;
134162 }
135- /* both have the same certificates? */
136- if ((pks1 -> ca_name_path != pks2 -> ca_name_path )
137- && (!pks1 -> ca_name_path || !pks2 -> ca_name_path
138- || strcmp (pks1 -> ca_name_path , pks2 -> ca_name_path ))) {
163+
164+ return 1 ;
165+ }
166+ #endif
167+
168+ #define MATCH_STR_CONFIG (a_ , b_ ) ((a_ != b_) && (!a_ || !b_ || strcmp(a_, b_)))
169+
170+ static int ssl_pk_server_compatible (SSLSrvConfigRec * sc1 ,
171+ SSLSrvConfigRec * sc2 )
172+ {
173+ modssl_pk_server_t * pks1 = sc1 -> server -> pks , * pks2 = sc2 -> server -> pks ;
174+ modssl_auth_ctx_t * a1 = & sc1 -> server -> auth , * a2 = & sc2 -> server -> auth ;
175+
176+ if (sc1 -> server -> protocol != sc2 -> server -> protocol )
177+ return 0 ;
178+
179+ /* Check both TLS<1.3 and TLS/1.3 cipher config matches */
180+ if (MATCH_STR_CONFIG (a1 -> cipher_suite , a2 -> cipher_suite )
181+ || MATCH_STR_CONFIG (a1 -> tls13_ciphers , a2 -> tls13_ciphers )) {
139182 return 0 ;
140183 }
141- if ((pks1 -> ca_name_file != pks2 -> ca_name_file )
142- && (!pks1 -> ca_name_file || !pks2 -> ca_name_file
143- || strcmp (pks1 -> ca_name_file , pks2 -> ca_name_file ))) {
184+
185+ if (!pks1 || !pks2 ) {
144186 return 0 ;
145187 }
146188 if (!ap_array_same_str_set (pks1 -> cert_files , pks2 -> cert_files )
@@ -150,67 +192,72 @@ static int ssl_pk_server_compatible(modssl_pk_server_t *pks1,
150192 return 1 ;
151193}
152194
153- static int ssl_auth_compatible (modssl_auth_ctx_t * a1 ,
154- modssl_auth_ctx_t * a2 )
195+ static int ssl_auth_compatible (SSLSrvConfigRec * sc1 , SSLSrvConfigRec * sc2 )
155196{
156- if (!a1 || !a2 ) {
157- return 0 ;
158- }
197+ modssl_ctx_t * ctx1 = sc1 -> server , * ctx2 = sc2 -> server ;
198+ modssl_pk_server_t * pks1 = ctx1 -> pks , * pks2 = ctx2 -> pks ;
199+ modssl_auth_ctx_t * a1 = & ctx1 -> auth , * a2 = & ctx2 -> auth ;
200+
159201 /* both have the same verification */
160202 if ((a1 -> verify_depth != a2 -> verify_depth )
161203 || (a1 -> verify_mode != a2 -> verify_mode )) {
162204 return 0 ;
163205 }
164- /* both have the same ca path/file */
165- if ((a1 -> ca_cert_path != a2 -> ca_cert_path )
166- && (!a1 -> ca_cert_path || !a2 -> ca_cert_path
167- || strcmp (a1 -> ca_cert_path , a2 -> ca_cert_path ))) {
168- return 0 ;
169- }
170- if ((a1 -> ca_cert_file != a2 -> ca_cert_file )
171- && (!a1 -> ca_cert_file || !a2 -> ca_cert_file
172- || strcmp (a1 -> ca_cert_file , a2 -> ca_cert_file ))) {
173- return 0 ;
174- }
175- /* both have the same ca cipher suite string */
176- if ((a1 -> cipher_suite != a2 -> cipher_suite )
177- && (!a1 -> cipher_suite || !a2 -> cipher_suite
178- || strcmp (a1 -> cipher_suite , a2 -> cipher_suite ))) {
206+
207+ /* Check that CA, CRL and OCSP settings match. */
208+ if (MATCH_STR_CONFIG (pks1 -> ca_name_path , pks2 -> ca_name_path )
209+ || MATCH_STR_CONFIG (pks1 -> ca_name_file , pks2 -> ca_name_file )
210+ || MATCH_STR_CONFIG (a1 -> ca_cert_path , a2 -> ca_cert_path )
211+ || MATCH_STR_CONFIG (a1 -> ca_cert_file , a2 -> ca_cert_file )
212+ || MATCH_STR_CONFIG (ctx1 -> crl_path , ctx2 -> crl_path )
213+ || MATCH_STR_CONFIG (ctx1 -> crl_file , ctx2 -> crl_file )
214+ || ctx1 -> crl_check_mask != ctx2 -> crl_check_mask
215+ || ctx1 -> ocsp_mask != ctx2 -> ocsp_mask
216+ || ctx1 -> ocsp_force_default != ctx2 -> ocsp_force_default
217+ || MATCH_STR_CONFIG (ctx1 -> ocsp_responder , ctx2 -> ocsp_responder )) {
179218 return 0 ;
180219 }
181- /* both have the same ca cipher suite string */
182- if ((a1 -> tls13_ciphers != a2 -> tls13_ciphers )
183- && (!a1 -> tls13_ciphers || !a2 -> tls13_ciphers
184- || strcmp (a1 -> tls13_ciphers , a2 -> tls13_ciphers ))) {
220+
221+ #ifdef HAVE_SRP
222+ if (MATCH_STR_CONFIG (ctx1 -> srp_vfile , ctx2 -> srp_vfile ))
185223 return 0 ;
186- }
187- return 1 ;
188- }
224+ #endif
189225
190- static int ssl_ctx_compatible (modssl_ctx_t * ctx1 ,
191- modssl_ctx_t * ctx2 )
192- {
193- if (!ctx1 || !ctx2
194- || (ctx1 -> protocol != ctx2 -> protocol )
195- || !ssl_auth_compatible (& ctx1 -> auth , & ctx2 -> auth )
196- || !ssl_pk_server_compatible (ctx1 -> pks , ctx2 -> pks )) {
226+ #ifdef HAVE_SSL_CONF_CMD
227+ /* Without validating (and understanding) each specific
228+ * SSLOpenSSLConfCmd command, assume any difference is
229+ * relevant to authentication. */
230+ if (!array_cmp_ssl_ctx_params (ctx1 -> ssl_ctx_param , ctx2 -> ssl_ctx_param ))
197231 return 0 ;
198- }
232+ #endif
233+
199234 return 1 ;
200235}
201236
202- static int ssl_server_compatible (server_rec * s1 , server_rec * s2 )
237+ /* Check whether a transition from vhost sc1 to sc2 via SNI is
238+ * permitted according to the SSLVHostSNIPolicy setting. Returns 1 if
239+ * the policy treats the vhosts as compatible, else 0. */
240+ static int ssl_check_vhost_sni_policy (SSLSrvConfigRec * sc1 ,
241+ SSLSrvConfigRec * sc2 )
203242{
204- SSLSrvConfigRec * sc1 = s1 ? mySrvConfig (s1 ) : NULL ;
205- SSLSrvConfigRec * sc2 = s2 ? mySrvConfig (s2 ) : NULL ;
243+ modssl_snivhpolicy_t policy = sc1 -> mc -> snivh_policy ;
206244
207- /* both use the same TLS protocol? */
208- if (!sc1 || !sc2
209- || !ssl_ctx_compatible (sc1 -> server , sc2 -> server )) {
210- return 0 ;
211- }
245+ /* Policy: insecure => allow everything. */
246+ if (policy == MODSSL_SNIVH_INSECURE )
247+ return 1 ;
212248
213- return 1 ;
249+ /* Policy: strict => fail for any vhost transition. */
250+ if (policy == MODSSL_SNIVH_STRICT && sc1 != sc2 )
251+ return 0 ;
252+
253+ /* Policy: secure => fail for any difference in definition of
254+ * SSLProtocol/Cipher, certs or keys. */
255+ if (policy == MODSSL_SNIVH_SECURE && !ssl_pk_server_compatible (sc1 , sc2 ))
256+ return 0 ;
257+
258+ /* Policy: authonly or secure => fail for any differences in
259+ * authentication/trust setting. */
260+ return ssl_auth_compatible (sc1 , sc2 );
214261}
215262#endif
216263
@@ -279,6 +326,8 @@ int ssl_hook_ReadReq(request_rec *r)
279326 server_rec * handshakeserver = sslconn -> server ;
280327 SSLSrvConfigRec * hssc = mySrvConfig (handshakeserver );
281328
329+ AP_DEBUG_ASSERT (hssc );
330+
282331 if ((servername = SSL_get_servername (ssl , TLSEXT_NAMETYPE_host_name ))) {
283332 /*
284333 * The SNI extension supplied a hostname. So don't accept requests
@@ -319,19 +368,14 @@ int ssl_hook_ReadReq(request_rec *r)
319368 "which is required to access this server.<br />\n" );
320369 return HTTP_FORBIDDEN ;
321370 }
322- if (r -> server != handshakeserver
323- && !ssl_server_compatible (sslconn -> server , r -> server )) {
324- /*
325- * The request does not select the virtual host that was
326- * selected for handshaking and its SSL parameters are different
327- */
328-
371+ /* Enforce SSL SNI vhost compatibility policy. */
372+ if (!ssl_check_vhost_sni_policy (sc , hssc )) {
329373 ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (02032 )
330- "Hostname %s %s and hostname %s provided"
331- " via HTTP have no compatible SSL setup" ,
374+ "Hostname %s %s and hostname %s provided"
375+ " via HTTP have no compatible SSL setup for policy '%s' " ,
332376 servername ? servername : handshakeserver -> server_hostname ,
333377 servername ? "provided via SNI" : "(default host as no SNI was provided)" ,
334- r -> hostname );
378+ r -> hostname , MODSSL_SNIVH_NAME ( sc -> mc -> snivh_policy ) );
335379 return HTTP_MISDIRECTED_REQUEST ;
336380 }
337381 }
0 commit comments