def test_cert_constraint_issuer(requests_mock): vc = live_testing_vc(requests_mock) signer_validation_path = CertificateValidator( FROM_CA.signing_cert, FROM_CA.cert_registry, validation_context=vc).validate_usage(set()) tsa_validation_path = CertificateValidator( DUMMY_TS.tsa_cert, FROM_CA.cert_registry, validation_context=vc).validate_usage(set()) scc = fields.SigCertConstraints(flags=fields.SigCertConstraintFlags.ISSUER, issuers=[ROOT_CERT]) scc.satisfied_by(FROM_CA.signing_cert, signer_validation_path) scc.satisfied_by(DUMMY_TS.tsa_cert, tsa_validation_path) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(FROM_CA.signing_cert, None) scc = fields.SigCertConstraints(flags=fields.SigCertConstraintFlags.ISSUER, issuers=[INTERM_CERT]) scc.satisfied_by(FROM_CA.signing_cert, signer_validation_path) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, tsa_validation_path) scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.ISSUER, issuers=[INTERM_CERT, SELF_SIGN.signing_cert]) scc.satisfied_by(FROM_CA.signing_cert, signer_validation_path) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, tsa_validation_path) scc = fields.SigCertConstraints(issuers=[INTERM_CERT]) scc.satisfied_by(FROM_CA.signing_cert, signer_validation_path) scc.satisfied_by(DUMMY_TS.tsa_cert, tsa_validation_path)
def test_cert_constraint_composite(requests_mock): vc = live_testing_vc(requests_mock) signer_validation_path = CertificateValidator( FROM_CA.signing_cert, FROM_CA.cert_registry, validation_context=vc).validate_usage(set()) tsa_validation_path = CertificateValidator( DUMMY_TS.tsa_cert, FROM_CA.cert_registry, validation_context=vc).validate_usage(set()) from asn1crypto import x509 scc = fields.SigCertConstraints(flags=fields.SigCertConstraintFlags.ISSUER | fields.SigCertConstraintFlags.SUBJECT_DN, issuers=[INTERM_CERT], subject_dn=x509.Name.build({ 'common_name': 'Lord Testerino', 'country_name': 'BE' })) scc.satisfied_by(FROM_CA.signing_cert, signer_validation_path) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, tsa_validation_path) from asn1crypto import x509 scc = fields.SigCertConstraints(flags=fields.SigCertConstraintFlags.ISSUER | fields.SigCertConstraintFlags.SUBJECT_DN, issuers=[INTERM_CERT], subject_dn=x509.Name.build({ 'common_name': 'Alice & Bob', 'country_name': 'BE' })) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(FROM_CA.signing_cert, signer_validation_path)
def test_cert_constraint_deserialisation(): signer1 = FROM_CA.signing_cert signer2 = SELF_SIGN.signing_cert constr = fields.SigCertConstraints(subjects=[signer1, signer2]) constr_parsed = fields.SigCertConstraints.from_pdf_object( constr.as_pdf_object()) signer1_parsed, signer2_parsed = constr_parsed.subjects assert signer1_parsed.dump() == signer1.dump() assert signer2_parsed.dump() == signer2.dump() assert not constr_parsed.issuers issuer1 = FROM_CA.signing_cert issuer2 = SELF_SIGN.signing_cert constr = fields.SigCertConstraints(issuers=[issuer1, issuer2]) constr_parsed = fields.SigCertConstraints.from_pdf_object( constr.as_pdf_object()) issuer1_parsed, issuer2_parsed = constr_parsed.issuers assert issuer1_parsed.dump() == issuer1.dump() assert issuer2_parsed.dump() == issuer2.dump() assert not constr_parsed.subjects constr = fields.SigCertConstraints(subject_dn=signer1.subject) constr_ser = constr.as_pdf_object() assert '/C' in constr_ser['/SubjectDN'][0] constr_parsed = fields.SigCertConstraints.from_pdf_object(constr_ser) assert constr_parsed.subject_dn == signer1.subject
def test_cert_constraint_key_usage_ok(ku_strs): scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.KEY_USAGE, key_usage=[ fields.SigCertKeyUsage.read_from_sv_string(ku) for ku in ku_strs ]) scc.satisfied_by(FROM_CA.signing_cert, None)
def test_cert_constraint_key_usage_not_ok(ku_strs): scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.KEY_USAGE, key_usage=[ fields.SigCertKeyUsage.read_from_sv_string(ku) for ku in ku_strs ]) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(FROM_CA.signing_cert, None)
def test_sv_sign_cert_constraint(): # this is more thoroughly unit tested at a lower level (see further up), # so we simply try two basic scenarios here for now from asn1crypto import x509 sv = fields.SigSeedValueSpec(cert=fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT_DN, subject_dn=x509.Name.build({'common_name': 'Lord Testerino'}), )) sign_with_sv(sv, signers.PdfSignatureMetadata(field_name='Sig')) sv = fields.SigSeedValueSpec(cert=fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT_DN, subject_dn=x509.Name.build({'common_name': 'Not Lord Testerino'}), )) with pytest.raises(SigningError): sign_with_sv(sv, signers.PdfSignatureMetadata(field_name='Sig')) sign_with_sv(sv, signers.PdfSignatureMetadata(field_name='Sig'), test_violation=True)
def test_sv_cert_flag_unsupported(): sv = fields.SigSeedValueSpec( cert=fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.RESERVED, ) ) meta = signers.PdfSignatureMetadata(field_name='Sig') with pytest.raises(NotImplementedError): sign_with_sv(sv, meta)
def test_cert_constraint_subject(): scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT, subjects=[FROM_CA.signing_cert]) scc.satisfied_by(FROM_CA.signing_cert, None) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, None) scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT, subjects=[FROM_CA.signing_cert, SELF_SIGN.signing_cert]) scc.satisfied_by(FROM_CA.signing_cert, None) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, None) scc = fields.SigCertConstraints( subjects=[FROM_CA.signing_cert, SELF_SIGN.signing_cert]) scc.satisfied_by(FROM_CA.signing_cert, None) scc.satisfied_by(DUMMY_TS.tsa_cert, None)
def test_cert_constraint_subject_dn(): from asn1crypto import x509 scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT_DN, subject_dn=x509.Name.build({'common_name': 'Lord Testerino'}), ) scc.satisfied_by(FROM_CA.signing_cert, None) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, None) scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT_DN, subject_dn=x509.Name.build({ 'common_name': 'Lord Testerino', 'country_name': 'BE' })) scc.satisfied_by(FROM_CA.signing_cert, None) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(DUMMY_TS.tsa_cert, None) scc = fields.SigCertConstraints( flags=fields.SigCertConstraintFlags.SUBJECT_DN, subject_dn=x509.Name.build({ 'common_name': 'Alice & Bob', 'country_name': 'BE' })) with pytest.raises(UnacceptableSignerError): scc.satisfied_by(FROM_CA.signing_cert, None) # without the SUBJECT_DN flag, this should pass scc = fields.SigCertConstraints( subject_dn=x509.Name.build({ 'common_name': 'Alice & Bob', 'country_name': 'BE' })) scc.satisfied_by(FROM_CA.signing_cert, None)
def test_append_sig_field_with_simple_sv(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) sv = fields.SigSeedValueSpec( reasons=['a', 'b', 'c'], cert=fields.SigCertConstraints( subject_dn=FROM_CA.signing_cert.subject, issuers=[INTERM_CERT], subjects=[FROM_CA.signing_cert], key_usage=[ fields.SigCertKeyUsage.from_sets( {'digital_signature', 'non_repudiation'}, {'key_agreement'}) ]), digest_methods=['ssh256'], add_rev_info=True, subfilters=[fields.SigSeedSubFilter.ADOBE_PKCS7_DETACHED], timestamp_server_url='https://tsa.example.com', ) sp = fields.SigFieldSpec('InvisibleSig', seed_value_dict=sv) fields.append_signature_field(w, sp) out = BytesIO() w.write(out) out.seek(0) r = PdfFileReader(out) _, _, sig_field_ref = next(fields.enumerate_sig_fields(r)) sv_dict = sig_field_ref.get_object()['/SV'] assert sv_dict['/V'] == generic.NumberObject(2) del sv_dict['/V'] recovered_sv = fields.SigSeedValueSpec.from_pdf_object(sv_dict) # x509.Certificate doesn't have an __eq__ implementation apparently, # so for the purposes of the test, we replace them by byte dumps issuers1 = recovered_sv.cert.issuers issuers2 = sv.cert.issuers issuers1[0] = issuers1[0].dump() issuers2[0] = issuers2[0].dump() subjects1 = recovered_sv.cert.subjects subjects2 = sv.cert.subjects subjects1[0] = subjects1[0].dump() subjects2[0] = subjects2[0].dump() assert recovered_sv == sv