@@ -138,6 +138,8 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p)
138138 mctx -> auth .cipher_suite = NULL ;
139139 mctx -> auth .verify_depth = UNSET ;
140140 mctx -> auth .verify_mode = SSL_CVERIFY_UNSET ;
141+ mctx -> auth .verify_error_mask = 0 ;
142+ mctx -> auth .verify_error_mask_set = FALSE;
141143 mctx -> auth .tls13_ciphers = NULL ;
142144
143145 mctx -> ocsp_mask = UNSET ;
@@ -284,6 +286,14 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p,
284286 cfgMergeString (auth .cipher_suite );
285287 cfgMergeInt (auth .verify_depth );
286288 cfgMerge (auth .verify_mode , SSL_CVERIFY_UNSET );
289+ if (add -> auth .verify_error_mask_set ) {
290+ mrg -> auth .verify_error_mask = add -> auth .verify_error_mask ;
291+ mrg -> auth .verify_error_mask_set = TRUE;
292+ }
293+ else {
294+ mrg -> auth .verify_error_mask = base -> auth .verify_error_mask ;
295+ mrg -> auth .verify_error_mask_set = base -> auth .verify_error_mask_set ;
296+ }
287297 cfgMergeString (auth .tls13_ciphers );
288298
289299 cfgMergeInt (ocsp_mask );
@@ -405,6 +415,8 @@ void *ssl_config_perdir_create(apr_pool_t *p, char *dir)
405415
406416 dc -> szCipherSuite = NULL ;
407417 dc -> nVerifyClient = SSL_CVERIFY_UNSET ;
418+ dc -> nVerifyClientErrorMask = 0 ;
419+ dc -> nVerifyClientErrorMaskSet = FALSE;
408420 dc -> nVerifyDepth = UNSET ;
409421
410422 dc -> szUserName = NULL ;
@@ -461,6 +473,14 @@ void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv)
461473
462474 cfgMergeString (szCipherSuite );
463475 cfgMerge (nVerifyClient , SSL_CVERIFY_UNSET );
476+ if (add -> nVerifyClientErrorMaskSet ) {
477+ mrg -> nVerifyClientErrorMask = add -> nVerifyClientErrorMask ;
478+ mrg -> nVerifyClientErrorMaskSet = TRUE;
479+ }
480+ else {
481+ mrg -> nVerifyClientErrorMask = base -> nVerifyClientErrorMask ;
482+ mrg -> nVerifyClientErrorMaskSet = base -> nVerifyClientErrorMaskSet ;
483+ }
464484 cfgMergeInt (nVerifyDepth );
465485
466486 cfgMergeString (szUserName );
@@ -1298,24 +1318,136 @@ static const char *ssl_cmd_verify_parse(cmd_parms *parms,
12981318 return NULL ;
12991319}
13001320
1321+ #define SSL_VERIFY_CLIENT_OPTIONAL_NO_CA_ERRORS \
1322+ (ACCEPT_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT \
1323+ | ACCEPT_X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN \
1324+ | ACCEPT_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY \
1325+ | ACCEPT_X509_V_ERR_CERT_UNTRUSTED \
1326+ | ACCEPT_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE \
1327+ | ACCEPT_X509_V_ERR_CERT_HAS_EXPIRED)
1328+
1329+ static const char * ssl_cmd_verify_error_mask_add (cmd_parms * parms ,
1330+ const char * token ,
1331+ unsigned int * mask )
1332+ {
1333+ if (strcEQ (token , "self-signed" )) {
1334+ * mask |= ACCEPT_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
1335+ | ACCEPT_X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ;
1336+ }
1337+ else if (strcEQ (token , "untrusted-cert" )) {
1338+ * mask |= ACCEPT_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
1339+ | ACCEPT_X509_V_ERR_CERT_UNTRUSTED ;
1340+ }
1341+ else if (strcEQ (token , "invalid-signature" )) {
1342+ * mask |= ACCEPT_X509_V_ERR_CERT_SIGNATURE_FAILURE
1343+ | ACCEPT_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ;
1344+ }
1345+ else if (strcEQ (token , "expired-cert" )) {
1346+ * mask |= ACCEPT_X509_V_ERR_CERT_HAS_EXPIRED ;
1347+ }
1348+ else if (strcEQ (token , "purpose-mismatch" ) || strcEQ (token , "X509_V_ERR_INVALID_PURPOSE" )) {
1349+ * mask |= ACCEPT_X509_V_ERR_INVALID_PURPOSE ;
1350+ }
1351+ else if (strcEQ (token , "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT" )) {
1352+ * mask |= ACCEPT_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ;
1353+ }
1354+ else if (strcEQ (token , "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN" )) {
1355+ * mask |= ACCEPT_X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ;
1356+ }
1357+ else if (strcEQ (token , "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY" )) {
1358+ * mask |= ACCEPT_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ;
1359+ }
1360+ else if (strcEQ (token , "X509_V_ERR_CERT_UNTRUSTED" )) {
1361+ * mask |= ACCEPT_X509_V_ERR_CERT_UNTRUSTED ;
1362+ }
1363+ else if (strcEQ (token , "X509_V_ERR_CERT_SIGNATURE_FAILURE" )) {
1364+ * mask |= ACCEPT_X509_V_ERR_CERT_SIGNATURE_FAILURE ;
1365+ }
1366+ else if (strcEQ (token , "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE" )) {
1367+ * mask |= ACCEPT_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ;
1368+ }
1369+ else if (strcEQ (token , "X509_V_ERR_CERT_HAS_EXPIRED" )) {
1370+ * mask |= ACCEPT_X509_V_ERR_CERT_HAS_EXPIRED ;
1371+ }
1372+ else if (strcEQ (token , "X509_V_ERR_CERT_NOT_YET_VALID" )) {
1373+ * mask |= ACCEPT_X509_V_ERR_CERT_NOT_YET_VALID ;
1374+ }
1375+ else {
1376+ return apr_pstrcat (parms -> temp_pool , parms -> cmd -> name ,
1377+ ": Invalid accepted-errors value '" , token , "'" ,
1378+ NULL );
1379+ }
1380+
1381+ return NULL ;
1382+ }
1383+
1384+ static const char * ssl_cmd_verify_error_mask_parse (cmd_parms * parms ,
1385+ const char * arg ,
1386+ unsigned int * mask )
1387+ {
1388+ const char * token ;
1389+ char * list ;
1390+ const char * list_cursor ;
1391+ const char * err ;
1392+
1393+ * mask = 0 ;
1394+ list = apr_pstrdup (parms -> temp_pool , arg );
1395+ list_cursor = list ;
1396+
1397+ while (* list_cursor ) {
1398+ token = ap_getword (parms -> temp_pool , & list_cursor , ',' );
1399+ if (!* token ) {
1400+ return apr_pstrcat (parms -> temp_pool , parms -> cmd -> name ,
1401+ ": Invalid accepted-errors list" ,
1402+ NULL );
1403+ }
1404+ if ((err = ssl_cmd_verify_error_mask_add (parms , token , mask ))) {
1405+ return err ;
1406+ }
1407+ }
1408+
1409+ return NULL ;
1410+ }
1411+
13011412const char * ssl_cmd_SSLVerifyClient (cmd_parms * cmd ,
13021413 void * dcfg ,
1303- const char * arg )
1414+ const char * arg1 ,
1415+ const char * arg2 )
13041416{
13051417 SSLDirConfigRec * dc = (SSLDirConfigRec * )dcfg ;
13061418 SSLSrvConfigRec * sc = mySrvConfig (cmd -> server );
13071419 ssl_verify_t mode = SSL_CVERIFY_NONE ;
1420+ unsigned int error_mask = 0 ;
13081421 const char * err ;
13091422
1310- if ((err = ssl_cmd_verify_parse (cmd , arg , & mode ))) {
1423+ if ((err = ssl_cmd_verify_parse (cmd , arg1 , & mode ))) {
13111424 return err ;
13121425 }
13131426
1427+ if (arg2 != NULL ) {
1428+ if (mode == SSL_CVERIFY_NONE ) {
1429+ return apr_pstrcat (cmd -> temp_pool , cmd -> cmd -> name ,
1430+ ": accepted-errors is not allowed when level is 'none'" ,
1431+ NULL );
1432+ }
1433+
1434+ if ((err = ssl_cmd_verify_error_mask_parse (cmd , arg2 , & error_mask ))) {
1435+ return err ;
1436+ }
1437+ }
1438+ else if (mode == SSL_CVERIFY_OPTIONAL_NO_CA ) {
1439+ error_mask = SSL_VERIFY_CLIENT_OPTIONAL_NO_CA_ERRORS ;
1440+ }
1441+
13141442 if (cmd -> path ) {
13151443 dc -> nVerifyClient = mode ;
1444+ dc -> nVerifyClientErrorMask = error_mask ;
1445+ dc -> nVerifyClientErrorMaskSet = TRUE;
13161446 }
13171447 else {
13181448 sc -> server -> auth .verify_mode = mode ;
1449+ sc -> server -> auth .verify_error_mask = error_mask ;
1450+ sc -> server -> auth .verify_error_mask_set = TRUE;
13191451 }
13201452
13211453 return NULL ;
0 commit comments