Skip to content

description: The ASN.1 layer of PKI Framework: elements, DER, and the UnspecifiedType that makes you say what you expected.

ASN.1 and DER

Everything in a public key infrastructure is an ASN.1 structure encoded with the Distinguished Encoding Rules of X.690. SpomkyLabs\Pki\ASN1 is that layer, and the rest of the library is built on it.

You rarely need it to read a certificate — Certificate does that for you. You need it when you meet a structure the library does not model: a private extension, an OtherName, an attribute whose syntax is yours.

Elements

Every type is an Element. An element knows its tag and can encode itself:

use SpomkyLabs\Pki\ASN1\Element;
use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence;
use SpomkyLabs\Pki\ASN1\Type\Primitive\Integer;
use SpomkyLabs\Pki\ASN1\Type\Primitive\ObjectIdentifier;
use SpomkyLabs\Pki\ASN1\Type\Primitive\UTF8String;

$sequence = Sequence::create(
    ObjectIdentifier::create('1.3.6.1.4.1.99999.1'),
    Integer::create(42),
    UTF8String::create('hello')
);

$der = $sequence->toDER();
$again = Element::fromDER($der);

$again->tag() === Element::TYPE_SEQUENCE;   // true

There is no constructor to call: every type is built with create(), and decoded with fromDER().

UnspecifiedType

Decoding gives back something whose type is not known until you look at it. Rather than hand you an Element to test by hand, the library hands you an UnspecifiedType: a wrapper whose as*() methods each assert one type and return it.

use SpomkyLabs\Pki\ASN1\Type\UnspecifiedType;

$element = UnspecifiedType::fromDER($der);

$sequence = $element->asSequence();              // UnexpectedValueException if it is not one
$oid = $sequence->at(0)->asObjectIdentifier();   // at() returns an UnspecifiedType too
$count = $sequence->at(1)->asInteger()->intNumber();
$text = $sequence->at(2)->asUTF8String()->string();

Structure::at() returns an UnspecifiedType, so reading into a structure reads as a chain of assertions. Each one throws UnexpectedValueException when the material is not shaped the way the page of the specification says it is — which is what you want when the material came from outside.

$element->asUnspecified() goes the other way, from an Element you already hold.

Structures

Sequence and Set extend Structure, which is Countable and IteratorAggregate, and immutable like everything else:

$sequence = Sequence::create(Integer::create(1));

$sequence = $sequence->withAppended(Integer::create(2));
$sequence = $sequence->withReplaced(0, Integer::create(0));
$sequence = $sequence->withoutElement(1);

count($sequence);                 // 1
$sequence->has(0, Element::TYPE_INTEGER);  // true: present, and of that type

Structure::explodeDER() splits the DER of a structure into the DER of each of its children, without decoding them.

  • The types — every ASN.1 type the library implements, and the PHP it maps to.
  • Encoding and decoding — DER in and out, offsets, DERData, indefinite length.
  • Tagging — implicit and explicit tags, context-specific, application and private classes.
  • Decoding untrusted input — the limits to set before you decode what a stranger sent.