Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructed OCTET_STRING - a real-life example #13

Closed
fantasya-pbem opened this issue May 13, 2019 · 5 comments
Closed

Constructed OCTET_STRING - a real-life example #13

fantasya-pbem opened this issue May 13, 2019 · 5 comments

Comments

@fantasya-pbem
Copy link

Hi Joni!

I have an interesting example of weird DER code from the real life: Some insurance company uses CMS (Cryptographic Message Syntax) to exchange signed and encrypted data. Besides the indefinite-length encoding (which I managed using your latest release), I stumbled upon another irregularity, which I call "Constructed OCTET_STRING".

I have attached a minimal example file in DER format (gzipped) and the output of openssl-asn1parse.
constructed-octet-string.der.gz
constructed-octet-string.txt

Here is an excerpt from the parse output:

thalian@home ~ $ openssl asn1parse -in constructed-octet-string.der -inform DER
...
37:d=3 hl=2 l=inf cons: SEQUENCE
39:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
50:d=4 hl=2 l=inf cons: cont [ 0 ]
52:d=5 hl=2 l=inf cons: OCTET STRING
54:d=6 hl=2 l= 8 prim: OCTET STRING :Test-001
64:d=6 hl=2 l= 8 prim: OCTET STRING :Test-002
74:d=6 hl=2 l= 0 prim: EOC
...

At index 52 there is the byte code 24 80 which sop/asn1 interpretes as "constructed, octet string" (as openssl does). But then it throws an exception in class PrimitiveString#39, because the isPrimitive check fails.

After this constructed octet string there are many primitive octet strings following (each with a size of 4096 byte), until the last octet string and the first EOC is found (the whole data file has ~1.3 MB), so the sense of this encoding seems to be a application-specific encoding of arbitrary-length strings with indefinite length, chunked into 4K packages.

I am looking for a possibility to let sop/asn1 concatenate these octet strings so that (in this example) the output is a single octet string "Test-001Test-002".

@sop
Copy link
Owner

sop commented May 13, 2019

Hi!

Thanks for the files that helped me to reproduce the problem. Great that you managed to fix a workaround as well! :)

It appears that constructed strings are a thing in BER encoding. I added rudimentary support for this in php72 branch. That's a development branch that will be merged in the near future. It does require PHP 7.2 however. Can you checkout and try it?

@fantasya-pbem
Copy link
Author

fantasya-pbem commented May 13, 2019

Thanks for your quick answer! Great that you have support for this in the php72 branch. Unfortunately I might have to support PHP 7.1 also, but I will have a look at the branch!

EDIT: In my PHP 7.2 version I can use your php72 branch successfully! What about backporting the ConstructedString into master? How much effort would this be?

@sop
Copy link
Owner

sop commented May 13, 2019

Hi!

Good to hear. I'll add the functionality to old master. I've created a php70 branch and backported what i've done so far. Feel free to try it out.
I'll add a couple of features before publishing a tag though. Maybe tomorrow.

@sop
Copy link
Owner

sop commented May 14, 2019

I've pushed some changes to php70 branch. Given your example data, here's how one could extract the payload as a concatenated string:

$data = file_get_contents(__DIR__ . '/constructed-octet-string.der');
$content_info = Element::fromDER($data)->asUnspecified()->asSequence();
$signed_data = $content_info->at(1)->asTagged()->asExplicit()->asSequence();
$encapsulated = $signed_data->at(2)->asSequence();
$content = $encapsulated->at(1)->asTagged()->asExplicit()->asConstructedString();
echo $content->string() . "\n";

Do you think this would be sufficient?

@fantasya-pbem
Copy link
Author

Thank you! I'm using branch php70 now. I ended up as this:

$encapContentInfo = $signedData->at(2)->asSequence();
$content = $encapContentInfo->getTagged(0)->asExplicit()->asElement();
if ($content instanceof Stringable) { return $content->string(); }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants