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; }
// (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];
/** * @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; }