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

OID 2.999 decoded wrong #9

Closed
danielmarschall opened this issue Mar 5, 2019 · 5 comments
Closed

OID 2.999 decoded wrong #9

danielmarschall opened this issue Mar 5, 2019 · 5 comments

Comments

@danielmarschall
Copy link

danielmarschall commented Mar 5, 2019

Hello,

I found out that "OIDs greater than 2.39 are not correclty decoded", e.g. "2.999"

Please find attached my small test program.

<?php

declare(strict_types=1);

require_once "vendor/autoload.php";

use ASN1\Element;
use ASN1\Type\Structure;
use ASN1\Type\UnspecifiedType;
use ASN1\Type\Constructed\Sequence;
use ASN1\Type\Primitive\Boolean;
use ASN1\Type\Primitive\NullType;
use ASN1\Type\Primitive\UTF8String;
use ASN1\Component\Identifier;
use ASN1\Type\Primitive\Integer;
use ASN1\Type\Tagged\ExplicitlyTaggedType;
use ASN1\Type\Primitive\ObjectIdentifier;

function oid_test($oidx="1.3.6") {
        $seq = new Sequence(
            new ExplicitlyTaggedType(
                1, new ObjectIdentifier($oidx)
            )
        );
        $der = $seq->toDER();

        $seq = UnspecifiedType::fromDER($der)->asSequence();

        if ($oidx == $seq->at(0)->asTagged()->asExplicit()->asObjectIdentifier()->oid()) {
                echo "OK: $oidx\n";
        } else {
                echo "NOT OK: $oidx != ".$seq->at(0)->asTagged()->asExplicit()->asObjectIdentifier()->oid()."\n";
        }
}

oid_test("1.3.6");
oid_test("1.3.6.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999991");
oid_test("2.1");
oid_test("2.49");

?>
@sop
Copy link
Owner

sop commented Mar 5, 2019

Hi!

Actually OID 2.49 is invalid to begin with. By the specification first sub-identifier must be in the range of 0..39. This is because the first two values are packed into one integer, due to an optimization dating back over 30 years.

For details see http://luca.ntop.org/Teaching/Appunti/asn1.html chapter 5.9, or https://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf page 270.

Anyway, it's a bug that we're allowing an encoding with such values. I'll add a check and throw an exception where appropriate.

@danielmarschall
Copy link
Author

2.49 is valid. 2.999 is also valid. Even 2.99999999999999999999999999 is valid.

Actually, there are a lot of OIDs above 2.39 registered http://www.oid-info.com/get/2.49

The "0..39" limitation applies only to the top arcs 0 and 1, not to 2.

As reference, please see ITU Rec. X.690, page 13+ ( https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf )

Here is an utility which you can use to test the DER encoding/decoding https://misc.daniel-marschall.de/asn.1/oid-converter/online.php

@sop
Copy link
Owner

sop commented Mar 5, 2019

I see you're correct.

It seems that for root arc 2 there's no limitation for the first sub id. I'll look into it!

@danielmarschall
Copy link
Author

danielmarschall commented Apr 28, 2019

Hello,

I just checked your latest version and found out that your fix bbf871a solves this problem.

However, this commit has some problems with "Travis CI"? I don't know what that means.

For the sake of completeness, here are my testcases:

OK: 1.3.6
OK: 1.3.6.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999991
OK: 2.1
OK: 0.39
OK: 1.39
OK: 2.40
OK: 2.49
OK: 2.999
OK: 2.99999999999999999999999999999999999999999999999999999999999999999999999991

and the code for the testcases:

#!/usr/bin/php
<?php

declare(strict_types=1);

require_once "vendor/autoload.php";

use ASN1\Element;
use ASN1\Type\Structure;
use ASN1\Type\UnspecifiedType;
use ASN1\Type\Constructed\Sequence;
use ASN1\Type\Primitive\Boolean;
use ASN1\Type\Primitive\NullType;
use ASN1\Type\Primitive\UTF8String;
use ASN1\Component\Identifier;
use ASN1\Type\Primitive\Integer;
use ASN1\Type\Tagged\ExplicitlyTaggedType;
use ASN1\Type\Primitive\ObjectIdentifier;

function oid_test($oidx, $expected_der) {
  $fail = false;

  // First, encode the OID

  $seq = new Sequence(
      new ExplicitlyTaggedType(
          1, new ObjectIdentifier($oidx)
      )
  );
  $der = $seq->toDER();

  // First test: Check if DER encoding fits (create testcases at https://misc.daniel-marschall.de/asn.1/oid-converter/online.php )

  $string = substr($der,4); // remove SEQUENCE
  $der_hexdump = '';
  for ($i = 0; $i < strlen($string); $i++) {
      $der_hexdump .= str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT) . ' ';
  }
  if (strtoupper(trim($der_hexdump)) != strtoupper(($expected_der))) {
        echo "DER ENCODING MISMATCH: $oidx (is $der_hexdump , should be $expected_der)\n";
        $fail = true;
  }

  // Second test: Now check if decoding the encoded OID brings the same OID

  $seq = UnspecifiedType::fromDER($der)->asSequence();

  if ($oidx != $seq->at(0)->asTagged()->asExplicit()->asObjectIdentifier()->oid()) {
        echo "ENCODE/DECODE MISMATCH: $oidx != ".$seq->at(0)->asTagged()->asExplicit()->asObjectIdentifier()->oid()."\n";
        $fail = true;
  }

  if (!$fail) {
        echo "OK: $oidx\n";
  }
}

oid_test("1.3.6", '06 02 2B 06');
oid_test("1.3.6.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999991", '06 2C 2B 06 A8 9B C7 AF C5 EF 8E 9C F5 CD 96 9B 86 DC BD D8 F1 E4 93 B9 ED D6 B4 98 E0 A3 9E DB 94 8F FF FF FF FF FF FF FF FF FF FF FF 77');
oid_test("2.1", '06 01 51');
oid_test("0.39", '06 01 27');
oid_test("1.39", '06 01 4F');
oid_test("2.40", '06 01 78');
oid_test("2.49", '06 02 81 01');
oid_test("2.999", '06 02 88 37');
oid_test("2.99999999999999999999999999999999999999999999999999999999999999999999999991", '06 24 81 E2 B2 96 93 A4 EE B6 D6 94 E3 A5 D2 E3 E3 FB DA AD E8 E5 82 8E 85 CA BF 90 80 80 80 80 80 80 80 80 80 47');

If you want, you can include my testcase in your project, of course.

@sop
Copy link
Owner

sop commented Apr 29, 2019

That particular test run failed because PHP bumped nightly version to 8.0.0, but phpunit requires 7.x. I removed the nightly test from Travis on a later commit.

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

No branches or pull requests

2 participants