131 lines
4.2 KiB
PHP
131 lines
4.2 KiB
PHP
<?php
|
|
/*
|
|
* This file is part of the PHPASN1 library.
|
|
*
|
|
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace FG\ASN1;
|
|
|
|
use FG\ASN1\Exception\ParserException;
|
|
|
|
/**
|
|
* Class ExplicitlyTaggedObject decorate an inner object with an additional tag that gives information about
|
|
* its context specific meaning.
|
|
*
|
|
* Explanation taken from A Layman's Guide to a Subset of ASN.1, BER, and DER:
|
|
* >>> An RSA Laboratories Technical Note
|
|
* >>> Burton S. Kaliski Jr.
|
|
* >>> Revised November 1, 1993
|
|
*
|
|
* [...]
|
|
* Explicitly tagged types are derived from other types by adding an outer tag to the underlying type.
|
|
* In effect, explicitly tagged types are structured types consisting of one component, the underlying type.
|
|
* Explicit tagging is denoted by the ASN.1 keywords [class number] EXPLICIT (see Section 5.2).
|
|
* [...]
|
|
*
|
|
* @see http://luca.ntop.org/Teaching/Appunti/asn1.html
|
|
*/
|
|
class ExplicitlyTaggedObject extends Object
|
|
{
|
|
/** @var \FG\ASN1\Object[] */
|
|
private $decoratedObjects;
|
|
private $tag;
|
|
|
|
/**
|
|
* @param int $tag
|
|
* @param \FG\ASN1\Object $objects,...
|
|
*/
|
|
public function __construct($tag, /* HH_FIXME[4858]: variadic + strict */ ...$objects)
|
|
{
|
|
$this->tag = $tag;
|
|
$this->decoratedObjects = $objects;
|
|
}
|
|
|
|
protected function calculateContentLength()
|
|
{
|
|
$length = 0;
|
|
foreach ($this->decoratedObjects as $object) {
|
|
$length += $object->getObjectLength();
|
|
}
|
|
|
|
return $length;
|
|
}
|
|
|
|
protected function getEncodedValue()
|
|
{
|
|
$encoded = '';
|
|
foreach ($this->decoratedObjects as $object) {
|
|
$encoded .= $object->getBinary();
|
|
}
|
|
|
|
return $encoded;
|
|
}
|
|
|
|
public function getContent()
|
|
{
|
|
return $this->decoratedObjects;
|
|
}
|
|
|
|
public function __toString()
|
|
{
|
|
switch ($length = count($this->decoratedObjects)) {
|
|
case 0:
|
|
return "Context specific empty object with tag [{$this->tag}]";
|
|
case 1:
|
|
$decoratedType = Identifier::getShortName($this->decoratedObjects[0]->getType());
|
|
return "Context specific $decoratedType with tag [{$this->tag}]";
|
|
default:
|
|
return "$length context specific objects with tag [{$this->tag}]";
|
|
}
|
|
}
|
|
|
|
public function getType()
|
|
{
|
|
return ord($this->getIdentifier());
|
|
}
|
|
|
|
public function getIdentifier()
|
|
{
|
|
$identifier = Identifier::create(Identifier::CLASS_CONTEXT_SPECIFIC, true, $this->tag);
|
|
|
|
return is_int($identifier) ? chr($identifier) : $identifier;
|
|
}
|
|
|
|
public function getTag()
|
|
{
|
|
return $this->tag;
|
|
}
|
|
|
|
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
|
{
|
|
$identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
|
|
$firstIdentifierOctet = ord($identifier);
|
|
assert(Identifier::isContextSpecificClass($firstIdentifierOctet), 'identifier octet should indicate context specific class');
|
|
assert(Identifier::isConstructed($firstIdentifierOctet), 'identifier octet should indicate constructed object');
|
|
$tag = Identifier::getTagNumber($identifier);
|
|
|
|
$totalContentLength = self::parseContentLength($binaryData, $offsetIndex);
|
|
$remainingContentLength = $totalContentLength;
|
|
|
|
$offsetIndexOfDecoratedObject = $offsetIndex;
|
|
$decoratedObjects = [];
|
|
|
|
while ($remainingContentLength > 0) {
|
|
$nextObject = Object::fromBinary($binaryData, $offsetIndex);
|
|
$remainingContentLength -= $nextObject->getObjectLength();
|
|
$decoratedObjects[] = $nextObject;
|
|
}
|
|
|
|
if ($remainingContentLength != 0) {
|
|
throw new ParserException("Context-Specific explicitly tagged object [$tag] starting at offset $offsetIndexOfDecoratedObject specifies a length of $totalContentLength octets but $remainingContentLength remain after parsing the content", $offsetIndexOfDecoratedObject);
|
|
}
|
|
|
|
$parsedObject = new self($tag, ...$decoratedObjects);
|
|
$parsedObject->setContentLength($totalContentLength);
|
|
return $parsedObject;
|
|
}
|
|
}
|