def test_add_revinfo_without_timestamp(requests_mock): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) # create signature without revocation info with freeze_time('2020-11-01'): out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=FROM_CA, in_place=True ) # fast forward 1 month with freeze_time('2020-12-01'): vc = live_testing_vc(requests_mock) r = PdfFileReader(out) emb_sig = r.embedded_signatures[0] out = add_validation_info(emb_sig, vc) r = PdfFileReader(out) emb_sig = r.embedded_signatures[0] # even with revinfo, this should fail for lack of a timestamp with pytest.raises(SignatureValidationError, match='.*trusted timestamp.*'): validate_pdf_ltv_signature( emb_sig, RevocationInfoValidationType.PADES_LT, {'trust_roots': TRUST_ROOTS, 'retroactive_revinfo': True} ) # ... and certainly for LTA with pytest.raises(SignatureValidationError, match='Purported.*LTA.*'): validate_pdf_ltv_signature( emb_sig, RevocationInfoValidationType.PADES_LTA, {'trust_roots': TRUST_ROOTS, 'retroactive_revinfo': True} )
def test_adobe_revinfo_live_nofullchain(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) out = signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', validation_context=dummy_ocsp_vc(), subfilter=fields.SigSeedSubFilter.ADOBE_PKCS7_DETACHED, embed_validation_info=True ), signer=FROM_CA, timestamper=DUMMY_TS ) r = PdfFileReader(out) rivt_adobe = RevocationInfoValidationType.ADOBE_STYLE # same as for the pades test above with pytest.raises(SignatureValidationError): validate_pdf_ltv_signature( r.embedded_signatures[0], rivt_adobe, { 'trust_roots': TRUST_ROOTS, 'allow_fetching': False, 'ocsps': [FIXED_OCSP] } ) from requests_mock import Mocker with Mocker() as m: live_testing_vc(m) status = validate_pdf_ltv_signature( r.embedded_signatures[0], rivt_adobe, { 'trust_roots': TRUST_ROOTS, 'allow_fetching': True } ) assert status.valid and not status.trusted, status.summary()
def test_sv_sign_addrevinfo_req(requests_mock): sv = fields.SigSeedValueSpec(flags=fields.SigSeedValFlags.ADD_REV_INFO, add_rev_info=True) vc = live_testing_vc(requests_mock) meta = signers.PdfSignatureMetadata( field_name='Sig', validation_context=vc, subfilter=fields.SigSeedSubFilter.ADOBE_PKCS7_DETACHED, embed_validation_info=True) emb_sig = sign_with_sv(sv, meta) status = validate_pdf_ltv_signature( emb_sig, RevocationInfoValidationType.ADOBE_STYLE, {'trust_roots': TRUST_ROOTS}) assert status.valid and status.trusted assert emb_sig.sig_object['/SubFilter'] == '/adbe.pkcs7.detached' meta = signers.PdfSignatureMetadata( field_name='Sig', validation_context=vc, subfilter=fields.SigSeedSubFilter.ADOBE_PKCS7_DETACHED, embed_validation_info=False) with pytest.raises(SigningError): sign_with_sv(sv, meta) sign_with_sv(sv, meta, test_violation=True) meta = signers.PdfSignatureMetadata( field_name='Sig', validation_context=vc, subfilter=fields.SigSeedSubFilter.PADES, embed_validation_info=True) # this shouldn't work with PAdES with pytest.raises(SigningError): sign_with_sv(sv, meta) sign_with_sv(sv, meta, test_violation=True)
def test_add_revinfo_timestamp_separate_no_dss(requests_mock, with_vri): buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(buf) # create signature & timestamp without revocation info with freeze_time('2020-11-01'): signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=FROM_CA, in_place=True ) signers.PdfTimeStamper(timestamper=DUMMY_TS).timestamp_pdf( IncrementalPdfFileWriter(buf), 'sha256', in_place=True ) # fast forward 1 month with freeze_time('2020-12-01'): vc = live_testing_vc(requests_mock) r = PdfFileReader(buf) emb_sig = r.embedded_signatures[0] add_validation_info(emb_sig, vc, in_place=True, add_vri_entry=with_vri) r = PdfFileReader(buf) emb_sig = r.embedded_signatures[0] # without retroactive revinfo, the validation should fail status = validate_pdf_ltv_signature( emb_sig, RevocationInfoValidationType.PADES_LT, {'trust_roots': TRUST_ROOTS} ) assert status.valid and not status.trusted # with retroactive revinfo, it should be OK status = validate_pdf_ltv_signature( emb_sig, RevocationInfoValidationType.PADES_LT, {'trust_roots': TRUST_ROOTS, 'retroactive_revinfo': True} ) assert status.valid and status.trusted assert status.modification_level == ModificationLevel.LTA_UPDATES
def test_adobe_revinfo_live(requests_mock): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) vc = live_testing_vc(requests_mock) out = signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', validation_context=vc, subfilter=fields.SigSeedSubFilter.ADOBE_PKCS7_DETACHED, embed_validation_info=True ), signer=FROM_CA, timestamper=DUMMY_TS ) r = PdfFileReader(out) rivt_adobe = RevocationInfoValidationType.ADOBE_STYLE status = validate_pdf_ltv_signature(r.embedded_signatures[0], rivt_adobe, {'trust_roots': TRUST_ROOTS}) assert status.valid and status.trusted
def _signature_status(ltv_profile, force_revinfo, soft_revocation_check, pretty_print, vc_kwargs, key_usage_settings, executive_summary, embedded_sig): if soft_revocation_check and force_revinfo: raise click.ClickException( "--soft-revocation-check is incompatible with " "--force-revinfo") if force_revinfo: rev_mode = 'require' elif soft_revocation_check: rev_mode = 'soft-fail' else: rev_mode = 'hard-fail' vc_kwargs['revocation_mode'] = rev_mode try: if ltv_profile is None: vc = ValidationContext(**vc_kwargs) status = validation.validate_pdf_signature( embedded_sig, key_usage_settings=key_usage_settings, signer_validation_context=vc) else: status = validation.validate_pdf_ltv_signature( embedded_sig, ltv_profile, key_usage_settings=key_usage_settings, force_revinfo=force_revinfo, validation_context_kwargs=vc_kwargs) if executive_summary and not pretty_print: return 'VALID' if status.bottom_line else 'INVALID' elif pretty_print: return status.pretty_print_details() else: return status.summary() except validation.ValidationInfoReadingError as e: msg = ('An error occurred while parsing the revocation information ' 'for this signature: ' + str(e)) logger.error(msg) if pretty_print: return msg else: return 'REVINFO_FAILURE' except SignatureValidationError as e: msg = 'An error occurred while validating this signature: ' + str(e) logger.error(msg, exc_info=e) if pretty_print: return msg else: return 'INVALID'
def _signature_status(ltv_profile, ltv_obsessive, pretty_print, vc_kwargs, executive_summary, embedded_sig): try: if ltv_profile is None: vc = ValidationContext(**vc_kwargs) status = validation.validate_pdf_signature( embedded_sig, signer_validation_context=vc) else: status = validation.validate_pdf_ltv_signature( embedded_sig, ltv_profile, force_revinfo=ltv_obsessive, validation_context_kwargs=vc_kwargs) if executive_summary and not pretty_print: return 'VALID' if status.bottom_line else 'INVALID' elif pretty_print: return status.pretty_print_details() else: return status.summary() except validation.ValidationInfoReadingError as e: msg = ('An error occurred while parsing the revocation information ' 'for this signature: ' + str(e)) logger.error(msg, exc_info=e) if pretty_print: return msg else: return 'REVINFO_FAILURE' except SignatureValidationError as e: msg = 'An error occurred while validating this signature: ' + str(e) logger.error(msg, exc_info=e) if pretty_print: return msg else: return 'INVALID' except Exception as e: msg = 'Generic processing error: ' + str(e) logger.error(msg, exc_info=e) if pretty_print: return msg else: return 'MALFORMED'