/** * Constructor * * @param string $data DER encoded data * @throws DecodeException If data does not adhere to DER */ public function __construct($data) { $this->_identifier = Identifier::fromDER($data, $this->_contentOffset); Length::expectFromDER($data, $this->_contentOffset); $this->_der = $data; $this->_typeTag = intval($this->_identifier->tag()); }
/** * Decode element from DER data. * * @param string $data DER encoded data * @param int|null $offset Reference to the variable that contains offset * into the data where to start parsing. Variable is updated to * the offset next to the parsed element. If null, start from offset * 0. * @throws DecodeException If decoding fails * @throws \UnexpectedValueException If called in the context of an expected * type, but decoding yields another type * @return self */ public static function fromDER($data, &$offset = null) { assert('is_string($data)', "got " . gettype($data)); // decode identifier $idx = $offset ? $offset : 0; $identifier = Identifier::fromDER($data, $idx); // determine class that implements type specific decoding $cls = self::_determineImplClass($identifier); try { // decode remaining element $element = $cls::_decodeFromDER($identifier, $data, $idx); } catch (\LogicException $e) { // rethrow as a RuntimeException for unified exception handling throw new DecodeException("Error while decoding " . self::tagToName($identifier->tag()) . ".", 0, $e); } // if called in the context of a concrete class, check // that decoded type matches the type of a calling class $called_class = get_called_class(); if (__CLASS__ != $called_class) { if (!$element instanceof $called_class) { throw new \UnexpectedValueException("{$called_class} expected, got " . get_class($element) . "."); } } // update offset for the caller if (isset($offset)) { $offset = $idx; } return $element; }
/** * Explode DER structure to DER encoded components that it contains. * * @param string $data * @throws DecodeException * @return string[] */ public static function explodeDER($data) { $offset = 0; $identifier = Identifier::fromDER($data, $offset); if (!$identifier->isConstructed()) { throw new DecodeException("Element is not constructed."); } $length = Length::expectFromDER($data, $offset); $end = $offset + $length->length(); $parts = array(); while ($offset < $end) { // start of the element $idx = $offset; // skip identifier Identifier::fromDER($data, $offset); // decode element length $length = Length::expectFromDER($data, $offset); // extract der encoding of the element $parts[] = substr($data, $idx, $offset - $idx + $length->length()); // update offset over content $offset += $length->length(); } return $parts; }