CertificateExtensions.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <?php
  2. /*
  3. * This file is part of the PHPASN1 library.
  4. *
  5. * Copyright © Friedrich Große <friedrich.grosse@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace FG\X509;
  11. use FG\ASN1\Exception\ParserException;
  12. use FG\ASN1\OID;
  13. use FG\ASN1\ASNObject;
  14. use FG\ASN1\Parsable;
  15. use FG\ASN1\Identifier;
  16. use FG\ASN1\Universal\OctetString;
  17. use FG\ASN1\Universal\Set;
  18. use FG\ASN1\Universal\Sequence;
  19. use FG\ASN1\Universal\ObjectIdentifier;
  20. use FG\X509\SAN\SubjectAlternativeNames;
  21. class CertificateExtensions extends Set implements Parsable
  22. {
  23. private $innerSequence;
  24. private $extensions = [];
  25. public function __construct()
  26. {
  27. $this->innerSequence = new Sequence();
  28. parent::__construct($this->innerSequence);
  29. }
  30. public function addSubjectAlternativeNames(SubjectAlternativeNames $sans)
  31. {
  32. $this->addExtension(OID::CERT_EXT_SUBJECT_ALT_NAME, $sans);
  33. }
  34. private function addExtension($oidString, ASNObject $extension)
  35. {
  36. $sequence = new Sequence();
  37. $sequence->addChild(new ObjectIdentifier($oidString));
  38. $sequence->addChild($extension);
  39. $this->innerSequence->addChild($sequence);
  40. $this->extensions[] = $extension;
  41. }
  42. public function getContent()
  43. {
  44. return $this->extensions;
  45. }
  46. public static function fromBinary(&$binaryData, &$offsetIndex = 0)
  47. {
  48. self::parseIdentifier($binaryData[$offsetIndex], Identifier::SET, $offsetIndex++);
  49. self::parseContentLength($binaryData, $offsetIndex);
  50. $tmpOffset = $offsetIndex;
  51. $extensions = Sequence::fromBinary($binaryData, $offsetIndex);
  52. $tmpOffset += 1 + $extensions->getNumberOfLengthOctets();
  53. $parsedObject = new self();
  54. foreach ($extensions as $extension) {
  55. if ($extension->getType() != Identifier::SEQUENCE) {
  56. //FIXME wrong offset index
  57. throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Sequence but got '.$extension->getTypeName(), $offsetIndex);
  58. }
  59. $tmpOffset += 1 + $extension->getNumberOfLengthOctets();
  60. $children = $extension->getChildren();
  61. if (count($children) < 2) {
  62. throw new ParserException('Could not parse Certificate Extensions: Needs at least two child elements per extension sequence (object identifier and octet string)', $tmpOffset);
  63. }
  64. /** @var \FG\ASN1\ASNObject $objectIdentifier */
  65. $objectIdentifier = $children[0];
  66. /** @var OctetString $octetString */
  67. $octetString = $children[1];
  68. if ($objectIdentifier->getType() != Identifier::OBJECT_IDENTIFIER) {
  69. throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Object Identifier but got '.$extension->getTypeName(), $tmpOffset);
  70. }
  71. $tmpOffset += $objectIdentifier->getObjectLength();
  72. if ($objectIdentifier->getContent() == OID::CERT_EXT_SUBJECT_ALT_NAME) {
  73. $sans = SubjectAlternativeNames::fromBinary($binaryData, $tmpOffset);
  74. $parsedObject->addSubjectAlternativeNames($sans);
  75. } else {
  76. // can now only parse SANs. There might be more in the future
  77. $tmpOffset += $octetString->getObjectLength();
  78. }
  79. }
  80. $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ )
  81. return $parsedObject;
  82. }
  83. }