Skip to content

Commit

Permalink
Add support for asserting nonrevoked status
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthiasValvekens committed Nov 14, 2023
1 parent 2348637 commit 02f82eb
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 12 deletions.
34 changes: 25 additions & 9 deletions pyhanko/sign/validation/ades.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
CertValidationPolicySpec,
ValidationDataHandlers,
)
from pyhanko_certvalidator.errors import PathError
from pyhanko_certvalidator.ltv.ades_past import past_validate
from pyhanko_certvalidator.ltv.poe import (
KnownPOE,
Expand All @@ -58,6 +59,7 @@
from pyhanko_certvalidator.path import ValidationPath
from pyhanko_certvalidator.policy_decl import (
AlgorithmUsagePolicy,
NonRevokedStatusAssertion,
RevocationCheckingRule,
)
from pyhanko_certvalidator.registry import PathBuilder, TrustManager
Expand Down Expand Up @@ -1331,6 +1333,9 @@ async def ades_past_signature_validation(
except errors.SignatureValidationError as e:
logger.warning(e)
return e.ades_subindication or AdESIndeterminate.GENERIC
except PathError as e:
logger.warning(e)
return AdESIndeterminate.CERTIFICATE_CHAIN_GENERAL_FAILURE


@dataclass(frozen=True)
Expand Down Expand Up @@ -1523,8 +1528,11 @@ def _build_prima_facie_poe_index_from_pdf_timestamps(

if ts_signed_data is not None:
# add DSS content
dss = DocumentSecurityStore.read_dss(hist_handler)
collected_so_far.update(_read_validation_objects_from_dss(dss))
try:
dss = DocumentSecurityStore.read_dss(hist_handler)
collected_so_far.update(_read_validation_objects_from_dss(dss))
except NoDSSFoundError:
pass
collected_so_far.update(for_next_ts)
doc_digest = embedded_sig.compute_digest()
coverage_normal = (
Expand Down Expand Up @@ -1899,6 +1907,7 @@ async def ades_lta_validation(
known_crls=init_local_knowledge.known_crls + dss_facts.known_crls,
known_certs=init_local_knowledge.known_certs + dss_facts.known_certs,
known_poes=init_local_knowledge.known_poes,
nonrevoked_assertions=init_local_knowledge.nonrevoked_assertions,
)

augmented_validation_spec = dataclasses.replace(
Expand Down Expand Up @@ -2116,12 +2125,6 @@ async def simulate_future_ades_lta_validation(
:return:
An AdES LTA validation result.
"""
# TODO add a mode that validates the most recent docts live at the current
# reference time? Otherwise timestamp validation will typically fail
# if the gap between the timestamp and the time of the simulation is large,
# since the revinfo in the document for that timestamp will be stale
# (but if the TS cert is not expired, fresh revinfo should be available)

now = current_reference_time or datetime.now(tz=timezone.utc)
timing_info = ValidationTimingInfo(
validation_time=future_validation_time,
Expand All @@ -2134,6 +2137,18 @@ async def simulate_future_ades_lta_validation(
orig_sig_validation_spec = pdf_validation_spec.signature_validation_spec
orig_local_knowledge = orig_sig_validation_spec.local_knowledge
dss_knowledge = _dss_to_local_knowledge(embedded_sig.reader)
new_nonrevoked_assertions = list(orig_local_knowledge.nonrevoked_assertions)
# assert the nonrevoked status of the last timestamp cert, since we can't
# get "future" revinfo anyway
try:
last_ts = embedded_sig.reader.embedded_timestamp_signatures[-1]
new_nonrevoked_assertions.append(
NonRevokedStatusAssertion(
last_ts.signer_cert.sha256, at=future_validation_time
)
)
except IndexError:
pass

def _poes():
# For the purposes of this test, we assert all proofs of existence
Expand All @@ -2148,7 +2163,7 @@ def _poes():
# we don't validate the would-be POEs that are embedded in the
# document at this point
yield KnownPOE(
poe_type=POEType.VALIDATION,
poe_type=POEType.PROVIDED,
digest=item.digest,
poe_time=now,
validation_object=item.validation_object,
Expand All @@ -2157,6 +2172,7 @@ def _poes():
updated_local_knowledge = dataclasses.replace(
orig_local_knowledge,
known_poes=list(_poes()),
nonrevoked_assertions=new_nonrevoked_assertions,
)

updated_pdf_validation_spec = dataclasses.replace(
Expand Down
5 changes: 5 additions & 0 deletions pyhanko/sign/validation/policy_decl.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
digest_for_poe,
)
from pyhanko_certvalidator.ltv.types import ValidationTimingInfo
from pyhanko_certvalidator.policy_decl import NonRevokedStatusAssertion
from pyhanko_certvalidator.revinfo.archival import CRLContainer, OCSPContainer

from pyhanko.sign.diff_analysis import DEFAULT_DIFF_POLICY, DiffPolicy
Expand Down Expand Up @@ -78,6 +79,9 @@ class LocalKnowledge:
known_crls: List[CRLContainer] = field(default_factory=list)
known_certs: List[x509.Certificate] = field(default_factory=list)
known_poes: List[KnownPOE] = field(default_factory=list)
nonrevoked_assertions: List[NonRevokedStatusAssertion] = field(
default_factory=list
)

def add_to_poe_manager(self, poe_manager: POEManager):
for poe in self.known_poes:
Expand Down Expand Up @@ -180,5 +184,6 @@ def bootstrap_validation_data_handlers(
ocsps=knowledge.known_ocsps,
certs=knowledge.known_certs,
poe_manager=poe_manager_override,
nonrevoked_assertions=knowledge.nonrevoked_assertions,
)
return handlers
6 changes: 3 additions & 3 deletions pyhanko/sign/validation/report/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def _summarise_attrs(

def _generate_report(
embedded_sig: EmbeddedPdfSignature, status: AdESBasicValidationResult
):
) -> ts_11910202.SignatureValidationReportType:
api_status: PdfSignatureStatus = cast(PdfSignatureStatus, status.api_status)
# this is meaningless for EdDSA signatures, but the entry is mandatory, so...
md_spec = get_pyca_cryptography_hash(api_status.md_algorithm)
Expand Down Expand Up @@ -320,7 +320,7 @@ def _generate_report(
signer_information=ts_11910202.SignerInformationType(
signer_certificate=ts_11910202.VOReferenceType(
voreference=(
f"#{derive_validation_object_identifier(signer_cert_vo)}",
f"{derive_validation_object_identifier(signer_cert_vo)}",
),
),
),
Expand All @@ -333,7 +333,7 @@ def _generate_report(
signature_validation_status=ts_11910202.ValidationStatusType(
main_indication=ades_main_indic,
sub_indication=(
f'urn:etsi:019102:subindication:{str(status.ades_subindic)}',
f'urn:etsi:019102:subindication:{status.ades_subindic.standard_name}',
),
),
)
Expand Down

0 comments on commit 02f82eb

Please sign in to comment.