wbond / asn1crypto

Python ASN.1 library with a focus on performance and a pythonic API
MIT License
335 stars 140 forks source link

Error parsing ParsableOctetString while parsing EncapsulatedContentInfo (test case) #283

Open ornati opened 1 month ago

ornati commented 1 month ago

Hello,

I have troubles parsing a "timestamp".. I don't have access to the code that produced it.

Code to reproduce the issue:

from asn1crypto.cms import EncapsulatedContentInfo

ENC_CONTENT_INFO_FILE = 'enc_content_info2.dat'
cnt = EncapsulatedContentInfo.load(open(ENC_CONTENT_INFO_FILE, 'rb').read())
cnt.native

enc_content_info2.dat.zip

Error with last git version b763a757bb2bef2ab63620611ddd8006d5e9e4a2 (it's the same with v1.5.1):

Traceback (most recent call last):
  File "/home/paolo/src/asn1crypto/crashtest.py", line 6, in <module>
    cnt.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4070, in native
    self._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4014, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 3986, in _parse_children
    child = _build(*child)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 5539, in _build
    value = _build(*info, spec=spec, spec_params={'no_explicit': True})
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 5581, in _build
    raise ValueError(unwrap(
ValueError: Error parsing asn1crypto.core.ParsableOctetString - method should have been primitive, but constructed was found
    while parsing asn1crypto.cms.EncapsulatedContentInfo

Side note, openssl asn1parse works:

openssl asn1parse -inform DER -in enc_content_info2.dat
jinhua115 commented 1 month ago

这是来自QQ邮箱的假期自动回复邮件。你好,我最近正在休假中,无法亲自回复你的邮件。我将在假期结束后,尽快给你回复。

joernheissler commented 1 month ago

You need to use asn1crypto.cms.ContentInfo.

ornati commented 1 month ago

Thanks!

However this test case was part of a bigger issue, this one:

from asn1crypto.cms import ContentInfo
import asn1crypto.tsp  # extends ContentInfo

INPUT_FILE = 'problematic.xml.p7m.tsd'

cnt = ContentInfo.load(open(INPUT_FILE, 'rb').read(), strict=True)
cnt.native

Error:

Traceback (most recent call last):
  File "/home/paolo/src/asn1crypto/crashtest2.py", line 8, in <module>
    cnt.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4086, in native
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4081, in native
    self._native[name] = child.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4086, in native
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4081, in native
    self._native[name] = child.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 1249, in native
    return self.chosen.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4555, in native
    self._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4527, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4521, in _parse_children
    child._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4014, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 3988, in _parse_children
    child._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4014, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 3986, in _parse_children
    child = _build(*child)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 5539, in _build
    value = _build(*info, spec=spec, spec_params={'no_explicit': True})
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 5581, in _build
    raise ValueError(unwrap(
ValueError: Error parsing asn1crypto.core.ParsableOctetString - method should have been primitive, but constructed was found
    while parsing asn1crypto.cms.EncapsulatedContentInfo
    while parsing asn1crypto.tsp.TimeStampAndCRL
    while parsing asn1crypto.tsp.TimeStampTokenEvidence
    while parsing asn1crypto.tsp.TimeStampedData
    while parsing asn1crypto.cms.ContentInfo

"problematic.xml.p7m.tsd" is a PKCS#7 with a timestamp applied.

Am I doing something wrong again? ;-)

If not I'll open another issue with "problematic.xml.p7m.tsd" attached.

joernheissler commented 1 month ago

I don't know if you're doing something wrong. If you could generate a minimal example (i.e. not a full PKCS#7 file) it would help a lot.

ornati commented 1 month ago

I managed to reproduce the problem with just the timestamp part applied to a simple TXT file.

I have:

I don't know how to get more minimal than this ;-)

cnt = ContentInfo.load(...)
cnt.value

results in

Traceback (most recent call last):
  File "/home/paolo/src/asn1crypto/crashtest3.py", line 7, in <module>
    cnt.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4086, in native
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4081, in native
    self._native[name] = child.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4086, in native
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4081, in native
    self._native[name] = child.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 1249, in native
    return self.chosen.native
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4555, in native
    self._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4527, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4521, in _parse_children
    child._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4014, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 3988, in _parse_children
    child._parse_children(recurse=True)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 4014, in _parse_children
    raise e
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 3986, in _parse_children
    child = _build(*child)
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 5539, in _build
    value = _build(*info, spec=spec, spec_params={'no_explicit': True})
  File "/home/paolo/src/asn1crypto/asn1crypto/core.py", line 5581, in _build
    raise ValueError(unwrap(
ValueError: Error parsing asn1crypto.core.ParsableOctetString - method should have been primitive, but constructed was found
    while parsing asn1crypto.cms.EncapsulatedContentInfo
    while parsing asn1crypto.tsp.TimeStampAndCRL
    while parsing asn1crypto.tsp.TimeStampTokenEvidence
    while parsing asn1crypto.tsp.TimeStampedData
    while parsing asn1crypto.cms.ContentInfo

I'm attaching everything here, but maybe I should open another issue? parsing-err-testcase.zip

joernheissler commented 1 month ago

This might be a bug in asn1crypto.

diff --git a/asn1crypto/tsp.py b/asn1crypto/tsp.py
index f006da9..ead07cc 100644
--- a/asn1crypto/tsp.py
+++ b/asn1crypto/tsp.py
@@ -171,7 +171,7 @@ class MetaData(Sequence):

 class TimeStampAndCRL(Sequence):
     _fields = [
-        ('time_stamp', EncapsulatedContentInfo),
+        ('time_stamp', ContentInfo),
         ('crl', CertificateList, {'optional': True}),
     ]

@wbond Do you remember why this is an EncapsulatedContentInfo? All test cases succeed with and without above patch.

RFC5544 defines:

TimeStampAndCRL ::= SEQUENCE {
   timeStamp   TimeStampToken,          -- according to RFC 3161
   crl         CertificateList OPTIONAL -- according to RFC 5280
}

And RFC3161 defines:

A TimeStampToken is as follows.  It is defined as a ContentInfo
([CMS]) and SHALL encapsulate a signed data content type.

TimeStampToken ::= ContentInfo
  -- contentType is id-signedData ([CMS])
  -- content is SignedData ([CMS])