def test_demo_plugin(requests_mock): with_plugin_cfg = CertomancerConfig.from_file('tests/data/with-plugin.yml', 'tests/data') arch = with_plugin_cfg.get_pki_arch(ArchLabel('testing-ca')) illusionist.Illusionist(pki_arch=arch).register(requests_mock) importlib.import_module('example_plugin.encrypt_echo') # make the endpoint encrypt something endpoint = 'http://test.test/testing-ca/plugin/encrypt-echo/test-endpoint' payload = b'test test test' response = requests.post(endpoint, data=payload) # decrypt it env_data = cms.ContentInfo.load(response.content)['content'] key = arch.key_set.get_private_key(KeyLabel('signer1')) ktri = env_data['recipient_infos'][0].chosen encrypted_key = ktri['encrypted_key'].native decrypted_key = asymmetric.rsa_pkcs1v15_decrypt( asymmetric.load_private_key(key.dump()), encrypted_key) eci = env_data['encrypted_content_info'] cea = eci['content_encryption_algorithm'] assert cea['algorithm'].native == 'aes256_cbc' iv = cea['parameters'].native encrypted_content_bytes = eci['encrypted_content'].native decrypted_payload = symmetric.aes_cbc_pkcs7_decrypt( decrypted_key, encrypted_content_bytes, iv) assert decrypted_payload == payload
def test_demo_plugin(): with_plugin_cfg = CertomancerConfig.from_file('tests/data/with-plugin.yml', 'tests/data') with_plugin_app = Animator(AnimatorArchStore(with_plugin_cfg.pki_archs), with_web_ui=False) client = Client(with_plugin_app, Response) # make the endpoint encrypt something endpoint = '/testing-ca/plugin/encrypt-echo/test-endpoint' payload = b'test test test' response = client.post(endpoint, data=payload) # decrypt it env_data = cms.ContentInfo.load(response.data)['content'] arch = with_plugin_cfg.get_pki_arch(ArchLabel('testing-ca')) key = arch.key_set.get_private_key(KeyLabel('signer1')) ktri = env_data['recipient_infos'][0].chosen encrypted_key = ktri['encrypted_key'].native decrypted_key = asymmetric.rsa_pkcs1v15_decrypt( asymmetric.load_private_key(key.dump()), encrypted_key) eci = env_data['encrypted_content_info'] cea = eci['content_encryption_algorithm'] assert cea['algorithm'].native == 'aes256_cbc' iv = cea['parameters'].native encrypted_content_bytes = eci['encrypted_content'].native decrypted_payload = symmetric.aes_cbc_pkcs7_decrypt( decrypted_key, encrypted_content_bytes, iv) assert decrypted_payload == payload
async def test_embed_ac_revinfo_adobe_style(requests_mock): signer = get_ac_aware_signer() w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) pki_arch = CERTOMANCER.get_pki_arch(ArchLabel('testing-ca-with-aa')) dummy_ts = timestamps.DummyTimeStamper( tsa_cert=pki_arch.get_cert(CertLabel('tsa')), tsa_key=pki_arch.key_set.get_private_key(KeyLabel('tsa')), certs_to_embed=SimpleCertificateStore.from_certs( [pki_arch.get_cert('root')] ) ) from certomancer.integrations.illusionist import Illusionist from pyhanko_certvalidator.fetchers.requests_fetchers import ( RequestsFetcherBackend, ) fetchers = RequestsFetcherBackend().get_fetchers() main_vc = ValidationContext( trust_roots=[pki_arch.get_cert('root')], allow_fetching=True, other_certs=signer.cert_registry, fetchers=fetchers, revocation_mode='require' ) ac_vc = ValidationContext( trust_roots=[pki_arch.get_cert('root-aa')], allow_fetching=True, other_certs=signer.cert_registry, fetchers=fetchers, revocation_mode='require' ) Illusionist(pki_arch).register(requests_mock) out = await signers.async_sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', embed_validation_info=True, validation_context=main_vc, ac_validation_context=ac_vc ), timestamper=dummy_ts, signer=signer ) r = PdfFileReader(out) s = r.embedded_signatures[0] # 4 CA certs, 1 AA certs, 1 AC, 1 signer cert -> 7 certs assert len(s.other_embedded_certs) == 5 # signer cert is excluded assert len(s.embedded_attr_certs) == 1 from pyhanko.sign.validation import RevocationInfoValidationType status = await async_validate_pdf_ltv_signature( s, RevocationInfoValidationType.ADOBE_STYLE, validation_context_kwargs={ 'trust_roots': [pki_arch.get_cert('root')] }, ac_validation_context_kwargs={ 'trust_roots': [pki_arch.get_cert('root-aa')] } ) assert status.bottom_line roles = list(status.ac_attrs['role'].attr_values) role = roles[0] assert isinstance(role, cms.RoleSyntax) assert role['role_name'].native == '*****@*****.**'
async def test_sign_weak_sig_digest(): # We have to jump through some hoops to put together a signature # where the signing method's digest is not the same as the "external" # digest. This is intentional, since it's bad practice. input_buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(input_buf) cms_writer = cms_embedder.PdfCMSEmbedder().write_cms( field_name='Signature', writer=w ) next(cms_writer) timestamp = datetime.now(tz=tzlocal.get_localzone()) sig_obj = signers.SignatureObject(timestamp=timestamp, bytes_reserved=8192) external_md_algorithm = 'sha256' cms_writer.send(cms_embedder.SigObjSetup(sig_placeholder=sig_obj)) prep_digest, output = cms_writer.send( cms_embedder.SigIOSetup(md_algorithm=external_md_algorithm, in_place=True) ) signer = signers.SimpleSigner( signing_cert=TESTING_CA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA.key_set.get_private_key(KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs([ROOT_CERT, INTERM_CERT]) ) cms_obj = await signer.async_sign( data_digest=prep_digest.document_digest, digest_algorithm=external_md_algorithm, signed_attr_settings=PdfCMSSignedAttributes(signing_time=timestamp) ) si_obj: cms.SignerInfo = cms_obj['content']['signer_infos'][0] bad_algo = SignedDigestAlgorithm({'algorithm': 'md5_rsa'}) si_obj['signature_algorithm'] = signer.signature_mechanism = bad_algo attrs = si_obj['signed_attrs'] cms_prot = find_cms_attribute(attrs, 'cms_algorithm_protection')[0] cms_prot['signature_algorithm'] = bad_algo # recompute the signature si_obj['signature'] = signer.sign_raw(attrs.untag().dump(), 'md5') sig_contents = cms_writer.send(cms_obj) # we requested in-place output assert output is input_buf r = PdfFileReader(input_buf) emb = r.embedded_signatures[0] with pytest.raises(WeakHashAlgorithmError): await async_val_trusted(emb) lenient_vc = ValidationContext( trust_roots=[ROOT_CERT], weak_hash_algos=set() ) await async_val_trusted(emb, vc=lenient_vc)
def get_ac_aware_signer(actual_signer='signer1'): pki_arch = CERTOMANCER.get_pki_arch(ArchLabel('testing-ca-with-aa')) signer = signers.SimpleSigner( signing_cert=pki_arch.get_cert(CertLabel(actual_signer)), signing_key=pki_arch.key_set.get_private_key(KeyLabel(actual_signer)), cert_registry=SimpleCertificateStore.from_certs( [ pki_arch.get_cert('root'), pki_arch.get_cert('interm'), pki_arch.get_cert('root-aa'), pki_arch.get_cert('interm-aa'), pki_arch.get_cert('leaf-aa') ] ), attribute_certs=[ pki_arch.get_attr_cert(CertLabel('alice-role-with-rev')) ] ) return signer
def test_sign_with_explicit_dsa_implied_hash(): signer = signers.SimpleSigner( signing_cert=TESTING_CA_DSA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA_DSA.key_set.get_private_key( KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs( [DSA_ROOT_CERT, DSA_INTERM_CERT]), # this is not allowed, but the validator should accept it anyway signature_mechanism=SignedDigestAlgorithm({'algorithm': 'dsa'})) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) out = signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=signer) r = PdfFileReader(out) s = r.embedded_signatures[0] si = s.signer_info assert si['signature_algorithm']['algorithm'].native == 'dsa' assert s.field_name == 'Sig1' val_trusted(s, vc=SIMPLE_DSA_V_CONTEXT())
SELF_SIGN = signers.SimpleSigner.load(CRYPTO_DATA_DIR + '/selfsigned.key.pem', CRYPTO_DATA_DIR + '/selfsigned.cert.pem', key_passphrase=b'secret') ROOT_CERT = TESTING_CA.get_cert(CertLabel('root')) ECC_ROOT_CERT = TESTING_CA_ECDSA.get_cert(CertLabel('root')) DSA_ROOT_CERT = TESTING_CA_DSA.get_cert(CertLabel('root')) INTERM_CERT = TESTING_CA.get_cert(CertLabel('interm')) ECC_INTERM_CERT = TESTING_CA_ECDSA.get_cert(CertLabel('interm')) DSA_INTERM_CERT = TESTING_CA_DSA.get_cert(CertLabel('interm')) OCSP_CERT = TESTING_CA.get_cert(CertLabel('interm-ocsp')) REVOKED_CERT = TESTING_CA.get_cert(CertLabel('signer2')) TSA_CERT = TESTING_CA.get_cert(CertLabel('tsa')) TSA2_CERT = TESTING_CA.get_cert(CertLabel('tsa2')) FROM_CA = signers.SimpleSigner( signing_cert=TESTING_CA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA.key_set.get_private_key(KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs([ROOT_CERT, INTERM_CERT])) FROM_ECC_CA = signers.SimpleSigner( signing_cert=TESTING_CA_ECDSA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA_ECDSA.key_set.get_private_key(KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs( [ECC_ROOT_CERT, ECC_INTERM_CERT])) FROM_DSA_CA = signers.SimpleSigner( signing_cert=TESTING_CA_DSA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA_DSA.key_set.get_private_key(KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs( [DSA_ROOT_CERT, DSA_INTERM_CERT])) REVOKED_SIGNER = signers.SimpleSigner( signing_cert=TESTING_CA.get_cert(CertLabel('signer2')), signing_key=TESTING_CA.key_set.get_private_key(KeyLabel('signer2')), cert_registry=SimpleCertificateStore.from_certs([ROOT_CERT, INTERM_CERT]))