public static function fromBinary(&$binaryData, &$offsetIndex = 0)
 {
     $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
     $firstIdentifierOctet = ord($identifier);
     assert(Identifier::isContextSpecificClass($firstIdentifierOctet));
     assert(Identifier::isConstructed($firstIdentifierOctet));
     $tag = Identifier::getTagNumber($identifier);
     $contentLength = self::parseContentLength($binaryData, $offsetIndex);
     $offsetIndexOfDecoratedObject = $offsetIndex;
     $decoratedObject = Object::fromBinary($binaryData, $offsetIndex);
     if ($decoratedObject->getObjectLength() != $contentLength) {
         throw new ParserException("Context-Specific explicitly tagged object [{$tag}] starting at offset {$offsetIndexOfDecoratedObject} is longer than allowed in the outer tag", $offsetIndexOfDecoratedObject);
     }
     $parsedObject = new self($tag, $decoratedObject);
     $parsedObject->setContentLength($contentLength);
     return $parsedObject;
 }
Exemple #2
0
 // (see ITU-T X.509 section 7 "Public-keys and public-key certificates" for cert structure)
 /* @var Sequence $rootObject */
 assert($rootObject->getType() == Identifier::SEQUENCE);
 $topLevelContainer = $rootObject->getChildren();
 $certificateInfo = $topLevelContainer[0];
 /* @var Sequence $certificateInfo */
 assert($certificateInfo->getType() == Identifier::SEQUENCE);
 // there need to be at least 8 child elements if the certificate extensions field is present
 assert($certificateInfo->getNumberofChildren() >= 8);
 $certInfoFields = $certificateInfo->getChildren();
 $certExtensions = $certInfoFields[7];
 // check if this is really the certificate extensions sequence
 /* @var Object $certExtensions */
 $certExtensionsType = $certExtensions->getType();
 assert(Identifier::isContextSpecificClass($certExtensionsType));
 assert(Identifier::getTagNumber($certExtensions->getType()) == 3);
 // this should contain a sequence of extensions
 $certExtensions = $certExtensions->getFirstChild();
 assert($certExtensions->getType() == Identifier::SEQUENCE);
 // now check all extensions and search for the SAN
 /** @var Object $extensionSequence */
 foreach ($certExtensions as $extensionSequence) {
     assert($extensionSequence->getType() == Identifier::SEQUENCE);
     assert($extensionSequence->getNumberofChildren() >= 2);
     $extensionSequenceChildren = $extensionSequence->getChildren();
     $objectIdentifier = $extensionSequenceChildren[0];
     /* @var ObjectIdentifier $objectIdentifier */
     assert($objectIdentifier->getType() == Identifier::OBJECT_IDENTIFIER);
     if ($objectIdentifier->getContent() == OID::CERT_EXT_SUBJECT_ALT_NAME) {
         // now we have the wanted octet string
         $octetString = $extensionSequenceChildren[1];
Exemple #3
0
 /**
  * @param string $binaryData
  * @param int $offsetIndex
  *
  * @throws ParserException
  *
  * @return \FG\ASN1\Object
  */
 public static final 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);
     }
     $identifierOctets = self::parseBinaryIdentifier($binaryData, $offsetIndex);
     $identifier = new Identifier($identifierOctets);
     $lengthOctets = self::parseContentLength($binaryData, $offsetIndex);
     $contentLength = new ContentLength($lengthOctets);
     $children = [];
     //запоминаем начало элемента
     $startPos = $offsetIndex;
     //для составных элементов ищем детей
     if ($identifier->isConstructed) {
         $children = self::parseChildren($binaryData, $offsetIndex, $contentLength);
         //разница между текущем положением сдвига и стартовым - длина детей, блина контента составного элемента
         $contentLength->length = abs($startPos - $offsetIndex);
         //если неопределенная форма - вычитаем 2 октета на EOC
         if ($contentLength->form === ContentLength::INDEFINITE_FORM) {
             $contentLength->length -= 2;
         }
     }
     if (!is_int($contentLength->length)) {
         throw new ParserException('Length of Object not determined', $offsetIndex);
     }
     $contentOctets = substr($binaryData, $startPos, $contentLength->length);
     //если сдвигов не происходило (дети не парсились) прибавим длину контента
     if ($offsetIndex === $startPos) {
         $offsetIndex = $startPos + $contentLength->length;
     }
     $content = new Content($contentOctets);
     if ($identifier->tagClass === Identifier::CLASS_UNIVERSAL) {
         //для простых элементов вызываем конструктор
         switch ($identifier->getTagNumber()) {
             case Identifier::EOC:
                 return new EOC($identifier, $contentLength, $content, $children);
             case Identifier::BITSTRING:
                 return new BitString($identifier, $contentLength, $content, $children);
             case Identifier::BOOLEAN:
                 return new Boolean($identifier, $contentLength, $content, $children);
             case Identifier::ENUMERATED:
                 return new Enumerated($identifier, $contentLength, $content, $children);
             case Identifier::INTEGER:
                 return new Integer($identifier, $contentLength, $content, $children);
             case Identifier::NULL:
                 return new NullObject($identifier, $contentLength, $content, $children);
             case Identifier::OBJECT_IDENTIFIER:
                 return new ObjectIdentifier($identifier, $contentLength, $content, $children);
             case Identifier::RELATIVE_OID:
                 return new RelativeObjectIdentifier($identifier, $contentLength, $content, $children);
             case Identifier::OCTETSTRING:
                 return new OctetString($identifier, $contentLength, $content, $children);
             case Identifier::SEQUENCE:
                 return new Sequence($identifier, $contentLength, $content, $children);
             case Identifier::SET:
                 return new Set($identifier, $contentLength, $content, $children);
             case Identifier::UTC_TIME:
                 return new UTCTime($identifier, $contentLength, $content, $children);
             case Identifier::GENERALIZED_TIME:
                 return new GeneralizedTime($identifier, $contentLength, $content, $children);
             case Identifier::IA5_STRING:
                 return new IA5String($identifier, $contentLength, $content, $children);
             case Identifier::PRINTABLE_STRING:
                 return new PrintableString($identifier, $contentLength, $content, $children);
             case Identifier::NUMERIC_STRING:
                 return new NumericString($identifier, $contentLength, $content, $children);
             case Identifier::UTF8_STRING:
                 return new UTF8String($identifier, $contentLength, $content, $children);
             case Identifier::UNIVERSAL_STRING:
                 return new UniversalString($identifier, $contentLength, $content, $children);
             case Identifier::CHARACTER_STRING:
                 return new CharacterString($identifier, $contentLength, $content, $children);
             case Identifier::GENERAL_STRING:
                 return new GeneralString($identifier, $contentLength, $content, $children);
             case Identifier::VISIBLE_STRING:
                 return new VisibleString($identifier, $contentLength, $content, $children);
             case Identifier::GRAPHIC_STRING:
                 return new GraphicString($identifier, $contentLength, $content, $children);
             case Identifier::BMP_STRING:
                 return new BMPString($identifier, $contentLength, $content, $children);
             case Identifier::T61_STRING:
                 return new T61String($identifier, $contentLength, $content, $children);
             case Identifier::OBJECT_DESCRIPTOR:
                 return new ObjectDescriptor($identifier, $contentLength, $content, $children);
             default:
                 // At this point the identifier may be >1 byte.
                 if ($identifier->isConstructed) {
                     return new UnknownConstructedObject($identifier, $contentLength, $content, $children);
                 } else {
                     return new UnknownObject($identifier, $contentLength, $content, $children);
                 }
         }
     }
     if ($identifier->tagClass === Identifier::CLASS_CONTEXT_SPECIFIC) {
         if ($identifier->isConstructed) {
             return new ExplicitlyTaggedObject($identifier, $contentLength, $content, $children);
         } else {
             return new ImplicitlyTaggedObject($identifier, $contentLength, $content, $children);
         }
     }
 }
 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;
 }