def test_old_style_signing_cert_attr_mismatch(with_issser): if with_issser: # this file has an old-style signing cert attr with issuerSerial fname = 'pades-with-old-style-signing-cert-attr-issser.pdf' else: fname = 'pades-with-old-style-signing-cert-attr.pdf' with open(os.path.join(PDF_DATA_DIR, fname), 'rb') as f: r = PdfFileReader(f) s = r.embedded_signatures[0] signer_info = s.signer_info digest = s.compute_digest() # signer1-long has the same key as signer1 alt_cert = TESTING_CA.get_cert(CertLabel('signer1-long')) signer_info['sid'] = { 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': alt_cert.issuer, 'serial_number': alt_cert.serial_number }) } with pytest.raises(SignatureValidationError, match="Signing certificate attribute does not match "): validate_sig_integrity(signer_info, alt_cert, expected_content_type='data', actual_digest=digest)
def test_signing_cert_attr_duplicated(): output = _tamper_with_signed_attrs('signing_certificate_v2', resign=True, duplicate=True) r = PdfFileReader(output) emb = r.embedded_signatures[0] digest = emb.compute_digest() with pytest.raises(SignatureValidationError, match="Wrong cardinality for signing cert"): validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data', digest)
def test_no_content_type(): output = _tamper_with_signed_attrs('content_type', delete=True, resign=True) r = PdfFileReader(output) emb = r.embedded_signatures[0] digest = emb.compute_digest() with pytest.raises(SignatureValidationError): validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data', digest)
def test_cms_algorithm_protection(replacement_value): output = _tamper_with_signed_attrs('cms_algorithm_protection', duplicate=replacement_value is None, replace_with=replacement_value, resign=True) r = PdfFileReader(output) emb = r.embedded_signatures[0] digest = emb.compute_digest() with pytest.raises(SignatureValidationError, match='.*CMS.*'): validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data', digest)
def test_wrong_content_type(): # delete the (signed) CMSAlgorithmProtection attribute # this should invalidate the signature output = _tamper_with_signed_attrs('content_type', replace_with='enveloped_data', resign=True) r = PdfFileReader(output) emb = r.embedded_signatures[0] digest = emb.compute_digest() with pytest.raises(SignatureValidationError): validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data', digest)
def test_signing_cert_attr_malformed_issuer(): from asn1crypto import x509 cert = TESTING_CA.get_cert(CertLabel('signer1')) bogus_attr = as_signing_certificate_v2(cert) bogus_attr['certs'][0]['issuer_serial']['issuer'][0] = x509.GeneralName( {'dns_name': 'www.example.com'}) output = _tamper_with_signed_attrs('signing_certificate_v2', resign=True, replace_with=bogus_attr) r = PdfFileReader(output) emb = r.embedded_signatures[0] digest = emb.compute_digest() with pytest.raises(SignatureValidationError, match="Signing certificate attribute does not match "): validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data', digest)
def _signer_sanity_check(signer): digest = hashlib.sha256(b'Hello world!').digest() with pytest.deprecated_call(): sig = signer.sign(digest, digest_algorithm='sha256') from pyhanko.sign.general import validate_sig_integrity intact, valid = validate_sig_integrity( sig['content']['signer_infos'][0], cert=signer.signing_cert, expected_content_type='data', actual_digest=digest ) assert intact and valid
def test_signed_attrs_tampering(): # delete the (signed) CMSAlgorithmProtection attribute # this should invalidate the signature output = _tamper_with_signed_attrs('cms_algorithm_protection', delete=True) r = PdfFileReader(output) emb = r.embedded_signatures[0] digest = emb.compute_digest() intact, valid = validate_sig_integrity(emb.signer_info, emb.signer_cert, 'data', digest) # "intact" refers to the messageDigest attribute, which we didn't touch assert intact and not valid