| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 | 
							- <?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;
 
- use FG\ASN1\Universal\BitString;
 
- use FG\ASN1\Universal\Boolean;
 
- use FG\ASN1\Universal\Enumerated;
 
- use FG\ASN1\Universal\GeneralizedTime;
 
- use FG\ASN1\Universal\Integer;
 
- use FG\ASN1\Universal\NullObject;
 
- use FG\ASN1\Universal\ObjectIdentifier;
 
- use FG\ASN1\Universal\RelativeObjectIdentifier;
 
- use FG\ASN1\Universal\OctetString;
 
- use FG\ASN1\Universal\Sequence;
 
- use FG\ASN1\Universal\Set;
 
- use FG\ASN1\Universal\UTCTime;
 
- use FG\ASN1\Universal\IA5String;
 
- use FG\ASN1\Universal\PrintableString;
 
- use FG\ASN1\Universal\NumericString;
 
- use FG\ASN1\Universal\UTF8String;
 
- use FG\ASN1\Universal\UniversalString;
 
- use FG\ASN1\Universal\CharacterString;
 
- use FG\ASN1\Universal\GeneralString;
 
- use FG\ASN1\Universal\VisibleString;
 
- use FG\ASN1\Universal\GraphicString;
 
- use FG\ASN1\Universal\BMPString;
 
- use FG\ASN1\Universal\T61String;
 
- use FG\ASN1\Universal\ObjectDescriptor;
 
- use FG\Utility\BigInteger;
 
- use LogicException;
 
- /**
 
-  * Class ASNObject is the base class for all concrete ASN.1 objects.
 
-  */
 
- abstract class ASNObject implements Parsable
 
- {
 
-     private $contentLength;
 
-     private $nrOfLengthOctets;
 
-     /**
 
-      * Must return the number of octets of the content part.
 
-      *
 
-      * @return int
 
-      */
 
-     abstract protected function calculateContentLength();
 
-     /**
 
-      * Encode the object using DER encoding.
 
-      *
 
-      * @see http://en.wikipedia.org/wiki/X.690#DER_encoding
 
-      *
 
-      * @return string the binary representation of an objects value
 
-      */
 
-     abstract protected function getEncodedValue();
 
-     /**
 
-      * Return the content of this object in a non encoded form.
 
-      * This can be used to print the value in human readable form.
 
-      *
 
-      * @return mixed
 
-      */
 
-     abstract public function getContent();
 
-     /**
 
-      * Return the object type octet.
 
-      * This should use the class constants of Identifier.
 
-      *
 
-      * @see Identifier
 
-      *
 
-      * @return int
 
-      */
 
-     abstract public function getType();
 
-     /**
 
-      * Returns all identifier octets. If an inheriting class models a tag with
 
-      * the long form identifier format, it MUST reimplement this method to
 
-      * return all octets of the identifier.
 
-      *
 
-      * @throws LogicException If the identifier format is long form
 
-      *
 
-      * @return string Identifier as a set of octets
 
-      */
 
-     public function getIdentifier()
 
-     {
 
-         $firstOctet = $this->getType();
 
-         if (Identifier::isLongForm($firstOctet)) {
 
-             throw new LogicException(sprintf('Identifier of %s uses the long form and must therefor override "ASNObject::getIdentifier()".', get_class($this)));
 
-         }
 
-         return chr($firstOctet);
 
-     }
 
-     /**
 
-      * Encode this object using DER encoding.
 
-      *
 
-      * @return string the full binary representation of the complete object
 
-      */
 
-     public function getBinary()
 
-     {
 
-         $result  = $this->getIdentifier();
 
-         $result .= $this->createLengthPart();
 
-         $result .= $this->getEncodedValue();
 
-         return $result;
 
-     }
 
-     private function createLengthPart()
 
-     {
 
-         $contentLength = $this->getContentLength();
 
-         $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength);
 
-         if ($nrOfLengthOctets == 1) {
 
-             return chr($contentLength);
 
-         } else {
 
-             // the first length octet determines the number subsequent length octets
 
-             $lengthOctets = chr(0x80 | ($nrOfLengthOctets - 1));
 
-             for ($shiftLength = 8 * ($nrOfLengthOctets - 2); $shiftLength >= 0; $shiftLength -= 8) {
 
-                 $lengthOctets .= chr($contentLength >> $shiftLength);
 
-             }
 
-             return $lengthOctets;
 
-         }
 
-     }
 
-     protected function getNumberOfLengthOctets($contentLength = null)
 
-     {
 
-         if (!isset($this->nrOfLengthOctets)) {
 
-             if ($contentLength == null) {
 
-                 $contentLength = $this->getContentLength();
 
-             }
 
-             $this->nrOfLengthOctets = 1;
 
-             if ($contentLength > 127) {
 
-                 do { // long form
 
-                     $this->nrOfLengthOctets++;
 
-                     $contentLength = $contentLength >> 8;
 
-                 } while ($contentLength > 0);
 
-             }
 
-         }
 
-         return $this->nrOfLengthOctets;
 
-     }
 
-     protected function getContentLength()
 
-     {
 
-         if (!isset($this->contentLength)) {
 
-             $this->contentLength = $this->calculateContentLength();
 
-         }
 
-         return $this->contentLength;
 
-     }
 
-     protected function setContentLength($newContentLength)
 
-     {
 
-         $this->contentLength = $newContentLength;
 
-         $this->getNumberOfLengthOctets($newContentLength);
 
-     }
 
-     /**
 
-      * Returns the length of the whole object (including the identifier and length octets).
 
-      */
 
-     public function getObjectLength()
 
-     {
 
-         $nrOfIdentifierOctets = strlen($this->getIdentifier());
 
-         $contentLength = $this->getContentLength();
 
-         $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength);
 
-         return $nrOfIdentifierOctets + $nrOfLengthOctets + $contentLength;
 
-     }
 
-     public function __toString()
 
-     {
 
-         return $this->getContent();
 
-     }
 
-     /**
 
-      * Returns the name of the ASN.1 Type of this object.
 
-      *
 
-      * @see Identifier::getName()
 
-      */
 
-     public function getTypeName()
 
-     {
 
-         return Identifier::getName($this->getType());
 
-     }
 
-     /**
 
-      * @param string $binaryData
 
-      * @param int $offsetIndex
 
-      *
 
-      * @throws ParserException
 
-      *
 
-      * @return \FG\ASN1\ASNObject
 
-      */
 
-     public static function fromBinary(&$binaryData, &$offsetIndex = 0)
 
-     {
 
-         if (strlen($binaryData) <= $offsetIndex) {
 
-             throw new ParserException('Can not parse binary from data: Offset index larger than input size', $offsetIndex);
 
-         }
 
-         $identifierOctet = ord($binaryData[$offsetIndex]);
 
-         if (Identifier::isContextSpecificClass($identifierOctet) && Identifier::isConstructed($identifierOctet)) {
 
-             return ExplicitlyTaggedObject::fromBinary($binaryData, $offsetIndex);
 
-         }
 
-         switch ($identifierOctet) {
 
-             case Identifier::BITSTRING:
 
-                 return BitString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::BOOLEAN:
 
-                 return Boolean::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::ENUMERATED:
 
-                 return Enumerated::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::INTEGER:
 
-                 return Integer::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::NULL:
 
-                 return NullObject::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::OBJECT_IDENTIFIER:
 
-                 return ObjectIdentifier::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::RELATIVE_OID:
 
-                 return RelativeObjectIdentifier::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::OCTETSTRING:
 
-                 return OctetString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::SEQUENCE:
 
-                 return Sequence::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::SET:
 
-                 return Set::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::UTC_TIME:
 
-                 return UTCTime::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::GENERALIZED_TIME:
 
-                 return GeneralizedTime::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::IA5_STRING:
 
-                 return IA5String::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::PRINTABLE_STRING:
 
-                 return PrintableString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::NUMERIC_STRING:
 
-                 return NumericString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::UTF8_STRING:
 
-                 return UTF8String::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::UNIVERSAL_STRING:
 
-                 return UniversalString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::CHARACTER_STRING:
 
-                 return CharacterString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::GENERAL_STRING:
 
-                 return GeneralString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::VISIBLE_STRING:
 
-                 return VisibleString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::GRAPHIC_STRING:
 
-                 return GraphicString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::BMP_STRING:
 
-                 return BMPString::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::T61_STRING:
 
-                 return T61String::fromBinary($binaryData, $offsetIndex);
 
-             case Identifier::OBJECT_DESCRIPTOR:
 
-                 return ObjectDescriptor::fromBinary($binaryData, $offsetIndex);
 
-             default:
 
-                 // At this point the identifier may be >1 byte.
 
-                 if (Identifier::isConstructed($identifierOctet)) {
 
-                     return new UnknownConstructedObject($binaryData, $offsetIndex);
 
-                 } else {
 
-                     $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
 
-                     $lengthOfUnknownObject = self::parseContentLength($binaryData, $offsetIndex);
 
-                     $offsetIndex += $lengthOfUnknownObject;
 
-                     return new UnknownObject($identifier, $lengthOfUnknownObject);
 
-                 }
 
-         }
 
-     }
 
-     protected static function parseIdentifier($identifierOctet, $expectedIdentifier, $offsetForExceptionHandling)
 
-     {
 
-         if (is_string($identifierOctet) || is_numeric($identifierOctet) == false) {
 
-             $identifierOctet = ord($identifierOctet);
 
-         }
 
-         if ($identifierOctet != $expectedIdentifier) {
 
-             $message = 'Can not create an '.Identifier::getName($expectedIdentifier).' from an '.Identifier::getName($identifierOctet);
 
-             throw new ParserException($message, $offsetForExceptionHandling);
 
-         }
 
-     }
 
-     protected static function parseBinaryIdentifier($binaryData, &$offsetIndex)
 
-     {
 
-         if (strlen($binaryData) <= $offsetIndex) {
 
-             throw new ParserException('Can not parse identifier from data: Offset index larger than input size', $offsetIndex);
 
-         }
 
-         $identifier = $binaryData[$offsetIndex++];
 
-         if (Identifier::isLongForm(ord($identifier)) == false) {
 
-             return $identifier;
 
-         }
 
-         while (true) {
 
-             if (strlen($binaryData) <= $offsetIndex) {
 
-                 throw new ParserException('Can not parse identifier (long form) from data: Offset index larger than input size', $offsetIndex);
 
-             }
 
-             $nextOctet = $binaryData[$offsetIndex++];
 
-             $identifier .= $nextOctet;
 
-             if ((ord($nextOctet) & 0x80) === 0) {
 
-                 // the most significant bit is 0 to we have reached the end of the identifier
 
-                 break;
 
-             }
 
-         }
 
-         return $identifier;
 
-     }
 
-     protected static function parseContentLength(&$binaryData, &$offsetIndex, $minimumLength = 0)
 
-     {
 
-         if (strlen($binaryData) <= $offsetIndex) {
 
-             throw new ParserException('Can not parse content length from data: Offset index larger than input size', $offsetIndex);
 
-         }
 
-         $contentLength = ord($binaryData[$offsetIndex++]);
 
-         if (($contentLength & 0x80) != 0) {
 
-             // bit 8 is set -> this is the long form
 
-             $nrOfLengthOctets = $contentLength & 0x7F;
 
-             $contentLength = BigInteger::create(0x00);
 
-             for ($i = 0; $i < $nrOfLengthOctets; $i++) {
 
-                 if (strlen($binaryData) <= $offsetIndex) {
 
-                     throw new ParserException('Can not parse content length (long form) from data: Offset index larger than input size', $offsetIndex);
 
-                 }
 
-                 $contentLength = $contentLength->shiftLeft(8)->add(ord($binaryData[$offsetIndex++]));
 
-             }
 
-             if ($contentLength->compare(PHP_INT_MAX) > 0) {
 
-                 throw new ParserException("Can not parse content length from data: length > maximum integer", $offsetIndex);
 
-             }
 
-             $contentLength = $contentLength->toInteger();
 
-         }
 
-         if ($contentLength < $minimumLength) {
 
-             throw new ParserException('A '.get_called_class()." should have a content length of at least {$minimumLength}. Extracted length was {$contentLength}", $offsetIndex);
 
-         }
 
-         $lenDataRemaining = strlen($binaryData) - $offsetIndex;
 
-         if ($lenDataRemaining < $contentLength) {
 
-             throw new ParserException("Content length {$contentLength} exceeds remaining data length {$lenDataRemaining}", $offsetIndex);
 
-         }
 
-         return $contentLength;
 
-     }
 
- }
 
 
  |