Skip to content

Commit

Permalink
Reject detached signatures with eContent
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthiasValvekens committed Nov 21, 2023
1 parent a84a865 commit 11fcd6b
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 10 deletions.
6 changes: 6 additions & 0 deletions pyhanko/sign/validation/generic_cms.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,12 @@ async def cms_basic_validation(
md = hashes.Hash(md_spec)
md.update(raw)
raw_digest = md.finalize()
elif eci['content'] is not core.VOID:
raise errors.SignatureValidationError(
"CMS structural error: detached signatures should not have "
"encapsulated data",
ades_subindication=AdESFailure.FORMAT_FAILURE,
)

# first, do the cryptographic identity checks
# TODO theoretically (e.g. DSA with param inheritance) this requires
Expand Down
Binary file added pyhanko_tests/data/pdf/pdf-sig-with-econtent.pdf
Binary file not shown.
20 changes: 10 additions & 10 deletions pyhanko_tests/test_cms.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def test_generic_data_sign_legacy():
with pytest.deprecated_call():
# noinspection PyDeprecation
signature = FROM_CA.sign_general_data(
input_data, 'sha256', detached=False
input_data, 'sha256', detached=True
)

# reset the stream
Expand All @@ -136,7 +136,7 @@ def test_generic_data_sign_legacy():

eci = content['encap_content_info']
assert eci['content_type'].native == 'data'
assert eci['content'].native == b'Hello world!'
assert eci['content'].native is None

assert status.valid
assert status.intact
Expand Down Expand Up @@ -248,7 +248,7 @@ async def test_detached_cms_with_self_reported_timestamp():
signature = await FROM_CA.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
signed_attr_settings=PdfCMSSignedAttributes(signing_time=dt),
)
signature = cms.ContentInfo.load(signature.dump())
Expand All @@ -266,7 +266,7 @@ async def test_detached_cms_with_self_reported_timestamp():
@pytest.mark.asyncio
async def test_detached_cms_with_tst():
signature = await FROM_CA.async_sign_general_data(
b'Hello world!', 'sha256', detached=False, timestamper=DUMMY_TS
b'Hello world!', 'sha256', detached=True, timestamper=DUMMY_TS
)
signature = cms.ContentInfo.load(signature.dump())
status = await async_validate_detached_cms(
Expand All @@ -290,7 +290,7 @@ async def test_detached_cms_with_content_tst():
signature = await FROM_CA.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
timestamper=DUMMY_TS,
signed_attr_settings=signed_attr_settings,
)
Expand Down Expand Up @@ -343,7 +343,7 @@ def unsigned_attr_providers(
signature = await signer.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
timestamper=DUMMY_TS,
signed_attr_settings=PdfCMSSignedAttributes(
cades_signed_attrs=CAdESSignedAttrSpec(timestamp_content=True)
Expand Down Expand Up @@ -394,7 +394,7 @@ def signed_attr_providers(
signature = await signer.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
timestamper=DUMMY_TS,
)
signature = cms.ContentInfo.load(signature.dump())
Expand Down Expand Up @@ -1716,7 +1716,7 @@ async def test_detached_cades_cms_with_tst():
signature = await FROM_CA.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
timestamper=DUMMY_TS,
use_cades=True,
)
Expand Down Expand Up @@ -1935,7 +1935,7 @@ async def test_detached_cms_with_invalid_cn():
signature = await sgn.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
)
signature = cms.ContentInfo.load(signature.dump())
status = await async_validate_detached_cms(
Expand Down Expand Up @@ -2003,7 +2003,7 @@ def _signed_attr_providers(self, *args, **kwargs):
signature = await sgn.async_sign_general_data(
b'Hello world!',
'sha256',
detached=False,
detached=True,
)

signature['content']['certificates'].append(
Expand Down
12 changes: 12 additions & 0 deletions pyhanko_tests/test_signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1690,3 +1690,15 @@ def test_signature_dict_with_prop_auth_type():
s = r.embedded_signatures[0]
val_trusted(s)
assert s.sig_object['/Prop_AuthType'] == 'Password'


def test_sign_reject_econtent_if_detached():
fname = os.path.join(PDF_DATA_DIR, 'pdf-sig-with-econtent.pdf')
with open(fname, 'rb') as inf:
r = PdfFileReader(inf)
emb = r.embedded_signatures[0]

with pytest.raises(
SignatureValidationError, match='detached.*encapsulated'
):
val_untrusted(emb)

0 comments on commit 11fcd6b

Please sign in to comment.