
| Current Path : /var/www/wsgi/www/api/venv/lib/python3.12/site-packages/pyhanko_certvalidator/ltv/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/wsgi/www/api/venv/lib/python3.12/site-packages/pyhanko_certvalidator/ltv/ades_past.py |
import dataclasses
import logging
from datetime import datetime, timezone
from typing import Optional
from pyhanko_certvalidator.context import (
CertValidationPolicySpec,
ValidationDataHandlers,
)
from pyhanko_certvalidator.errors import ValidationError
from pyhanko_certvalidator.ltv.errors import (
PastValidatePrecheckFailure,
TimeSlideFailure,
)
from pyhanko_certvalidator.ltv.time_slide import time_slide
from pyhanko_certvalidator.ltv.types import ValidationTimingInfo
from pyhanko_certvalidator.path import ValidationPath
from pyhanko_certvalidator.policy_decl import (
NO_REVOCATION,
AcceptAllAlgorithms,
CertRevTrustPolicy,
)
from pyhanko_certvalidator.validate import async_validate_path
__all__ = ['past_validate']
logger = logging.getLogger(__name__)
async def _past_validate_precheck(
path: ValidationPath,
validation_policy_spec: CertValidationPolicySpec,
):
# The past validation algorithm requires us to run the "regular"
# validation algorithm without regard for revocation and expiration
# on a known-good time
# Shell model: intersect the validity windows of all certs in the path
certs = list(path.iter_certs(include_root=False))
lower_bound = max(c.not_valid_before for c in certs)
upper_bound = min(c.not_valid_after for c in certs)
if lower_bound >= upper_bound:
raise PastValidatePrecheckFailure(
"The intersection of the validity periods of the certificates "
"in the path is empty or degenerate."
)
ref_time = ValidationTimingInfo(
validation_time=upper_bound,
best_signature_time=upper_bound,
point_in_time_validation=True,
)
validation_context = dataclasses.replace(
validation_policy_spec,
revinfo_policy=CertRevTrustPolicy(
revocation_checking_policy=NO_REVOCATION
),
algorithm_usage_policy=AcceptAllAlgorithms(),
).build_validation_context(timing_info=ref_time, handlers=None)
try:
await async_validate_path(
validation_context,
path,
validation_policy_spec.pkix_validation_params,
)
except ValidationError as e:
raise PastValidatePrecheckFailure(
"Elementary path validation routine failed during pre-check "
"for past point-in-time validation"
) from e
async def past_validate(
path: ValidationPath,
validation_policy_spec: CertValidationPolicySpec,
validation_data_handlers: ValidationDataHandlers,
init_control_time: Optional[datetime] = None,
best_signature_time: Optional[datetime] = None,
) -> datetime:
"""
Execute the ETSI EN 319 102-1 past certificate validation algorithm
against the given path (ETSI EN 319 102-1, ยง 5.6.2.1).
Instead of merely evaluating X.509 validation constraints, the algorithm
will perform a full point-in-time reevaluation of the path at the
control time mandated by the specification. This implies that a caller
implementing the past signature validation algorithm no longer needs to
explicitly reevaluate CA certificate revocation times and/or algorithm
constraints based on POEs.
.. warning::
This is incubating internal API.
:param path:
The prospective validation path against which to execute the algorithm.
:param validation_policy_spec:
The validation policy specification.
:param validation_data_handlers:
The handlers used to manage collected certificates,revocation
information and proof-of-existence records.
:param init_control_time:
Initial control time; defaults to the current time.
:param best_signature_time:
Usage time to use in freshness computations.
:return:
The control time returned by the time sliding algorithm.
Informally, the last time at which the certificate was known to be
valid.
"""
await _past_validate_precheck(
path,
validation_policy_spec,
)
try:
# time slide
init_control_time = init_control_time or datetime.now(tz=timezone.utc)
control_time = await time_slide(
path,
init_control_time=init_control_time,
rev_trust_policy=validation_policy_spec.revinfo_policy,
algo_usage_policy=validation_policy_spec.algorithm_usage_policy,
time_tolerance=validation_policy_spec.time_tolerance,
revinfo_manager=validation_data_handlers.revinfo_manager,
)
logger.info(
f"AdES time slide yields %s as the control time for path with "
f"leaf {path.describe_leaf()}",
control_time,
)
except ValidationError as e:
raise TimeSlideFailure(
f"Failed to get control time for point-in-time validation for path "
f"with leaf {path.describe_leaf()}"
) from e
ref_time = ValidationTimingInfo(
validation_time=control_time,
best_signature_time=best_signature_time or control_time,
point_in_time_validation=True,
)
# -> validate
validation_context = validation_policy_spec.build_validation_context(
timing_info=ref_time, handlers=validation_data_handlers
)
# Maintenance note:
# Doing a full point-in-time re-validation of the path is much more
# heavy-handed than what the AdES spec requires. We really only have to
# evaluate the chain constraints here.
# However, the past signature validation algorithm needs information about
# revocations up the chain and algorithm usage for _all_ operations in
# the validation process which is hard to pass on given the current
# architecture of certvalidator. Reevaluating with a time in the past
# is easier, and the POE enforcement is the same either way.
await async_validate_path(
validation_context,
path,
parameters=validation_policy_spec.pkix_validation_params,
)
return control_time