21
21
PSSParameterMismatch ,
22
22
RevokedError ,
23
23
)
24
+ from pyhanko_certvalidator .ltv .poe import POEManager
24
25
from pyhanko_certvalidator .ltv .types import ValidationTimingParams
25
26
from pyhanko_certvalidator .path import ValidationPath
26
27
from pyhanko_certvalidator .policy_decl import CertRevTrustPolicy
@@ -729,7 +730,11 @@ def _maybe_get_delta_crl(
729
730
parent_crl_aki = certificate_list .authority_key_identifier ,
730
731
)
731
732
if not delta_certificate_list_cont :
732
- return None
733
+ raise CRLValidationIndeterminateError (
734
+ "Delta CRL matching Freshest CRL extension not available" ,
735
+ failures = [],
736
+ suspect_stale = None ,
737
+ )
733
738
734
739
delta_certificate_list = delta_certificate_list_cont .crl_data
735
740
@@ -924,17 +929,14 @@ def _check_cert_on_crl_and_delta(
924
929
925
930
926
931
async def _classify_relevant_crls (
927
- revinfo_manager : RevinfoManager ,
928
- cert : x509 . Certificate ,
932
+ certificate_lists : List [ CRLContainer ] ,
933
+ poe_manager : POEManager ,
929
934
errs : _CRLErrs ,
930
935
control_time : Optional [datetime ] = None ,
931
936
):
932
937
# NOTE: the control_time parameter is only used in the time sliding
933
938
# algorithm code path for AdES validation
934
939
935
- certificate_lists = await revinfo_manager .async_retrieve_crls (cert )
936
- poe_manager = revinfo_manager .poe_manager
937
-
938
940
complete_lists_by_issuer = defaultdict (list )
939
941
delta_lists_by_issuer = defaultdict (list )
940
942
for certificate_list_cont in certificate_lists :
@@ -1046,11 +1048,6 @@ async def verify_crl(
1046
1048
1047
1049
revinfo_manager = validation_context .revinfo_manager
1048
1050
errs = _CRLErrs ()
1049
- (
1050
- complete_lists_by_issuer ,
1051
- delta_lists_by_issuer ,
1052
- ) = await _classify_relevant_crls (revinfo_manager , cert , errs )
1053
-
1054
1051
try :
1055
1052
cert_issuer_auth = path .find_issuing_authority (cert )
1056
1053
except LookupError :
@@ -1059,6 +1056,14 @@ async def verify_crl(
1059
1056
f"{ proc_state .describe_cert ()} in path."
1060
1057
)
1061
1058
1059
+ # First, make an attempt to validate without downloading any extra CRLs
1060
+ certificate_lists = revinfo_manager .currently_available_crls ()
1061
+ poe_manager = revinfo_manager .poe_manager
1062
+ (
1063
+ complete_lists_by_issuer ,
1064
+ delta_lists_by_issuer ,
1065
+ ) = await _classify_relevant_crls (certificate_lists , poe_manager , errs )
1066
+
1062
1067
# In the main loop, only complete CRLs are processed, so delta CRLs are
1063
1068
# weeded out of the to-do list
1064
1069
crls_to_process = []
@@ -1068,27 +1073,76 @@ async def verify_crl(
1068
1073
1069
1074
checked_reasons = set ()
1070
1075
1071
- for certificate_list_cont in crls_to_process :
1076
+ async def _process (crl_container , deltas ):
1077
+ nonlocal checked_reasons
1078
+ nonlocal errs
1072
1079
try :
1073
1080
interim_reasons = await _handle_single_crl (
1074
1081
cert = cert ,
1075
1082
cert_issuer_auth = cert_issuer_auth ,
1076
- certificate_list_cont = certificate_list_cont ,
1083
+ certificate_list_cont = crl_container ,
1077
1084
path = path ,
1078
1085
validation_context = validation_context ,
1079
- delta_lists_by_issuer = delta_lists_by_issuer ,
1086
+ delta_lists_by_issuer = deltas ,
1080
1087
use_deltas = use_deltas ,
1081
1088
errs = errs ,
1082
1089
proc_state = proc_state ,
1083
1090
)
1084
1091
if interim_reasons is not None :
1085
1092
# Step l
1086
1093
checked_reasons |= interim_reasons
1094
+ except CRLValidationIndeterminateError as e :
1095
+ errs .append (e .msg , certificate_list_cont )
1087
1096
except ValueError as e :
1088
1097
msg = "Generic processing error while validating CRL."
1089
1098
logging .debug (msg , exc_info = e )
1090
1099
errs .append (msg , certificate_list_cont )
1091
1100
1101
+ for certificate_list_cont in crls_to_process :
1102
+ await _process (certificate_list_cont , delta_lists_by_issuer )
1103
+
1104
+ exc = _process_crl_completeness (
1105
+ checked_reasons , total_crls , errs , proc_state
1106
+ )
1107
+ if exc is None :
1108
+ return
1109
+ elif not revinfo_manager .fetching_allowed :
1110
+ raise exc
1111
+
1112
+ # If we're not done checking CRLs, but we are allowed to fetch more,
1113
+ # let's go download some more CRLs...
1114
+
1115
+ # TODO scan Freshest CRL extensions for delta CRLs?
1116
+
1117
+ extra_certificate_lists = await revinfo_manager .fetch_crls (cert )
1118
+ (
1119
+ extra_complete_lists_by_issuer ,
1120
+ extra_delta_lists_by_issuer ,
1121
+ ) = await _classify_relevant_crls (
1122
+ extra_certificate_lists , poe_manager , errs
1123
+ )
1124
+
1125
+ combined_deltas = {
1126
+ k : delta_lists_by_issuer .get (k , [])
1127
+ + extra_delta_lists_by_issuer .get (k , [])
1128
+ for k in set (delta_lists_by_issuer .keys ()).union (
1129
+ extra_delta_lists_by_issuer .keys ()
1130
+ )
1131
+ }
1132
+
1133
+ crls_to_process = []
1134
+ for issuer , issuer_crls in complete_lists_by_issuer .items ():
1135
+ # some of the new deltas might complement CRLs that we already had
1136
+ if issuer in extra_delta_lists_by_issuer :
1137
+ crls_to_process .extend (issuer_crls )
1138
+ for issuer_crls in extra_complete_lists_by_issuer .values ():
1139
+ crls_to_process .extend (issuer_crls )
1140
+
1141
+ for certificate_list_cont in crls_to_process :
1142
+ await _process (certificate_list_cont , combined_deltas )
1143
+
1144
+ total_crls += len (crls_to_process )
1145
+
1092
1146
exc = _process_crl_completeness (
1093
1147
checked_reasons , total_crls , errs , proc_state
1094
1148
)
@@ -1217,15 +1271,18 @@ async def _assess_crl_relevance(
1217
1271
if interim_reasons is None :
1218
1272
continue
1219
1273
1274
+ delta = None
1220
1275
if use_deltas :
1221
- delta = _maybe_get_delta_crl (
1222
- certificate_list = certificate_list ,
1223
- crl_issuer = putative_issuer ,
1224
- delta_lists_by_issuer = delta_lists_by_issuer ,
1225
- errs = errs ,
1226
- )
1227
- else :
1228
- delta = None
1276
+ try :
1277
+ delta = _maybe_get_delta_crl (
1278
+ certificate_list = certificate_list ,
1279
+ crl_issuer = putative_issuer ,
1280
+ delta_lists_by_issuer = delta_lists_by_issuer ,
1281
+ errs = errs ,
1282
+ )
1283
+ except CRLValidationIndeterminateError as e :
1284
+ errs .append (e .msg , certificate_list )
1285
+ continue
1229
1286
1230
1287
prov = ProvisionalCRLTrust (path = cand_path , delta = delta )
1231
1288
provisional_results .append (prov )
@@ -1271,8 +1328,12 @@ async def collect_relevant_crls_with_paths(
1271
1328
1272
1329
proc_state = proc_state or ValProcState (cert_path_stack = ConsList .sing (path ))
1273
1330
errs = _CRLErrs ()
1331
+ candidate_crls = revinfo_manager .currently_available_crls ()
1274
1332
classify_job = _classify_relevant_crls (
1275
- revinfo_manager , cert , errs , control_time = control_time
1333
+ candidate_crls ,
1334
+ revinfo_manager .poe_manager ,
1335
+ errs ,
1336
+ control_time = control_time ,
1276
1337
)
1277
1338
complete_lists_by_issuer , delta_lists_by_issuer = await classify_job
1278
1339
0 commit comments