示例#1
0
async def test_detached_cms_with_content_tst():
    signed_attr_settings = PdfCMSSignedAttributes(
        cades_signed_attrs=CAdESSignedAttrSpec(timestamp_content=True)
    )
    signature = await FROM_CA.async_sign_general_data(
        b'Hello world!', 'sha256', detached=False, timestamper=DUMMY_TS,
        signed_attr_settings=signed_attr_settings
    )
    signature = cms.ContentInfo.load(signature.dump())
    status = await async_validate_detached_cms(
        b'Hello world!', signature['content']
    )
    assert status.signer_reported_dt is None
    assert status.timestamp_validity.intact
    assert status.timestamp_validity.valid
    assert status.timestamp_validity.timestamp == datetime.now(tz=pytz.utc)
    assert status.content_timestamp_validity
    assert status.content_timestamp_validity.intact
    assert status.content_timestamp_validity.valid
    assert status.content_timestamp_validity.timestamp == datetime.now(tz=pytz.utc)
    pretty_print = status.pretty_print_details()
    assert 'The TSA certificate is untrusted' in pretty_print
    assert 'Content timestamp' in pretty_print
    assert 'Signature timestamp' in pretty_print
    assert status.valid
    assert status.intact
    assert 'CONTENT_TIMESTAMP_TOKEN<INTACT:UNTRUSTED>' in status.summary()
    assert ',TIMESTAMP_TOKEN<INTACT:UNTRUSTED>' in status.summary()
示例#2
0
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)
示例#3
0
async def test_detached_cms_with_self_reported_timestamp():
    dt = datetime.fromisoformat('2020-11-01T05:00:00+00:00')
    signature = await FROM_CA.async_sign_general_data(
        b'Hello world!', 'sha256', detached=False,
        signed_attr_settings=PdfCMSSignedAttributes(signing_time=dt)
    )
    signature = cms.ContentInfo.load(signature.dump())
    status = await async_validate_detached_cms(
        b'Hello world!', signature['content']
    )
    assert status.signer_reported_dt == dt
    assert status.timestamp_validity is None
    assert 'reported by signer' in status.pretty_print_details()
    assert status.valid
    assert status.intact
示例#4
0
async def test_embed_signed_attachment():
    dt = datetime.fromisoformat('2020-11-01T05:00:00+00:00')
    signature = await FROM_CA.async_sign_general_data(
        VECTOR_IMAGE_PDF, 'sha256', PdfCMSSignedAttributes(signing_time=dt)
    )

    w = IncrementalPdfFileWriter(BytesIO(MINIMAL))
    signers.embed_payload_with_cms(
        w, file_spec_string='attachment.pdf',
        payload=embed.EmbeddedFileObject.from_file_data(
            w, data=VECTOR_IMAGE_PDF, mime_type='application/pdf',
            params=embed.EmbeddedFileParams(
                creation_date=dt, modification_date=dt
            )
        ),
        cms_obj=signature,
        file_name='添付ファイル.pdf',
        file_spec_kwargs={'description': "Signed attachment test"}
    )
    out = BytesIO()
    w.write(out)

    r = PdfFileReader(out)
    emb_lst = r.root['/Names']['/EmbeddedFiles']['/Names']
    assert len(emb_lst) == 4
    assert emb_lst[0] == 'attachment.pdf'
    spec_obj = emb_lst[1]
    assert spec_obj['/UF'] == '添付ファイル.pdf'
    stream = spec_obj['/EF']['/F']
    assert stream.data == VECTOR_IMAGE_PDF
    assert spec_obj['/RF']['/F'][0] == 'attachment.sig'
    assert spec_obj['/RF']['/UF'][0] == '添付ファイル.sig'
    rel_file_ref = spec_obj['/RF']['/F'].raw_get(1).reference

    assert emb_lst[2] == 'attachment.sig'
    spec_obj = emb_lst[3]
    assert spec_obj['/UF'] == '添付ファイル.sig'
    stream = spec_obj['/EF']['/F']
    assert stream.data == signature.dump()
    assert stream.container_ref == rel_file_ref
示例#5
0
async def test_validate_with_malformed_claimed_attrs(bad_attr, requests_mock):
    # This should parse up to the first level and be reencoded by asn1crypto
    #  without asking any questions.
    cms_sig = await FROM_CA.async_sign_general_data(
        b'Hello world', digest_algorithm='sha256',
        signed_attr_settings=PdfCMSSignedAttributes(
            cades_signed_attrs=CAdESSignedAttrSpec(
                signer_attributes=SignerAttrSpec(
                    claimed_attrs=[bad_attr, SAMPLE_GROUP_ATTR],
                    certified_attrs=[]
                )
            )
        )
    )
    status = await async_validate_detached_cms(
        input_data=b'Hello world', signed_data=cms_sig['content'],
        signer_validation_context=live_testing_vc(requests_mock)
    )
    assert isinstance(status, StandardCMSSignatureStatus)
    # The malformed attribute shouldn't have been processed,
    # but the other attrs should've
    assert len(status.cades_signer_attrs.claimed_attrs) == 1
示例#6
0
async def test_add_revinfo_wrong_subfilter():
    sv = fields.SigSeedValueSpec(flags=fields.SigSeedValFlags.ADD_REV_INFO,
                                 add_rev_info=True)

    sig_field_spec = fields.SigFieldSpec(
        sig_field_name='Sig',
        seed_value_dict=sv,
    )

    w = IncrementalPdfFileWriter(BytesIO(MINIMAL))
    fields.append_signature_field(w, sig_field_spec)

    cms_writer = cms_embedder.PdfCMSEmbedder().write_cms(field_name='Sig',
                                                         writer=w)
    next(cms_writer)
    # wrong subfilter: PAdES
    #  but we do embed an (empty) RevInfoArchival attribute
    sig_obj = signers.SignatureObject(bytes_reserved=8192, subfilter=PADES)

    cms_writer.send(cms_embedder.SigObjSetup(sig_placeholder=sig_obj))

    prep_digest, output = cms_writer.send(
        cms_embedder.SigIOSetup(md_algorithm='sha256', in_place=True))
    cms_obj = await FROM_CA.async_sign(
        data_digest=prep_digest.document_digest,
        digest_algorithm='sha256',
        signed_attr_settings=PdfCMSSignedAttributes(
            # empty
            adobe_revinfo_attr=asn1_pdf.RevocationInfoArchival({'ocsp': []})))
    await PdfTBSDocument.async_finish_signing(output, prep_digest, cms_obj)
    r = PdfFileReader(output)
    s = r.embedded_signatures[0]
    status = await async_validate_pdf_signature(s, dummy_ocsp_vc())
    summary = status.pretty_print_details()
    assert status.intact and status.valid
    assert 'not satisfy the SV constraints' in summary
    assert 'requires subfilter' in status.seed_value_constraint_error.args[0]
    assert not status.seed_value_ok
示例#7
0
async def test_parse_ac_with_malformed_attribute(requests_mock):
    attr_cert_cfg = f'''
    test-ac:
      holder:
          name: signer1
          # this needs to match against something from a totally different PKI
          # arch, so make the coupling as loose as possible
          include-base-cert-id: false
          include-entity-name: true
      issuer: root
      attributes:
          - id: charging_identity
            smart-value:
                schema: ietf-attribute
                params: ["Big Corp Inc."]
      validity:
        valid-from: "2000-01-01T00:00:00+0000"
        valid-to: "2100-01-01T00:00:00+0000"
    '''

    pki_arch = PKIArchitecture(
        arch_label=ArchLabel('test'),
        key_set=TESTING_CA.key_set, entities=TESTING_CA.entities,
        cert_spec_config=yaml.safe_load(BASIC_AC_ISSUER_SETUP),
        ac_spec_config=yaml.safe_load(attr_cert_cfg),
        service_config={},
        external_url_prefix='http://test.test',
    )
    spec = pki_arch.get_attr_cert_spec(CertLabel('test-ac'))

    # we have to get a bit creative to get Certomancer to output invalid asn1
    #  in exactly the way we want
    class FakeAttrSpec:
        # noinspection PyUnusedLocal
        def to_asn1(self, arch):
            return NONSENSICAL_ATTR

    # noinspection PyTypeChecker
    spec.attributes.append(FakeAttrSpec())

    cms_sig = await FROM_CA.async_sign_general_data(
        b'Hello world', digest_algorithm='sha256',
        signed_attr_settings=PdfCMSSignedAttributes(
            cades_signed_attrs=CAdESSignedAttrSpec(
                signer_attributes=SignerAttrSpec(
                    certified_attrs=[
                        pki_arch.get_attr_cert(CertLabel('test-ac'))
                    ],
                    claimed_attrs=[]
                )
            )
        )
    )
    vc = live_testing_vc(requests_mock)
    ac_vc = ValidationContext(
        trust_roots=[pki_arch.get_cert(CertLabel('ac-issuer'))],
        allow_fetching=False,
    )
    status = await async_validate_detached_cms(
        input_data=b'Hello world', signed_data=cms_sig['content'],
        signer_validation_context=vc,
        ac_validation_context=ac_vc
    )
    assert isinstance(status, StandardCMSSignatureStatus)
    # The malformed attribute shouldn't have been processed,
    # but the other attrs should've
    assert len(status.cades_signer_attrs.certified_attrs) == 1