├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json └── lib ├── ASN1 ├── ASNObject.php ├── AbstractString.php ├── AbstractTime.php ├── Base128.php ├── Composite │ ├── AttributeTypeAndValue.php │ ├── RDNString.php │ └── RelativeDistinguishedName.php ├── Construct.php ├── Exception │ ├── NotImplementedException.php │ └── ParserException.php ├── ExplicitlyTaggedObject.php ├── Identifier.php ├── OID.php ├── Parsable.php ├── TemplateParser.php ├── Universal │ ├── BMPString.php │ ├── BitString.php │ ├── Boolean.php │ ├── CharacterString.php │ ├── Enumerated.php │ ├── GeneralString.php │ ├── GeneralizedTime.php │ ├── GraphicString.php │ ├── IA5String.php │ ├── Integer.php │ ├── NullObject.php │ ├── NumericString.php │ ├── ObjectDescriptor.php │ ├── ObjectIdentifier.php │ ├── OctetString.php │ ├── PrintableString.php │ ├── RelativeObjectIdentifier.php │ ├── Sequence.php │ ├── Set.php │ ├── T61String.php │ ├── UTCTime.php │ ├── UTF8String.php │ ├── UniversalString.php │ └── VisibleString.php ├── UnknownConstructedObject.php └── UnknownObject.php ├── Utility ├── BigInteger.php ├── BigIntegerBcmath.php └── BigIntegerGmp.php └── X509 ├── AlgorithmIdentifier.php ├── CSR ├── Attributes.php └── CSR.php ├── CertificateExtensions.php ├── CertificateSubject.php ├── PrivateKey.php ├── PublicKey.php └── SAN ├── DNSName.php ├── IPAddress.php └── SubjectAlternativeNames.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### v2.5.0 (2022-12) 2 | * Support PHP 8.2 [#99](https://github.com/fgrosse/PHPASN1/pull/99) 3 | * PHP 8 compatibility fix for DateTime::getLastErrors [#98](https://github.com/fgrosse/PHPASN1/pull/98) 4 | * Support more OIDs [#95](https://github.com/fgrosse/PHPASN1/pull/95) 5 | * FINAL RELEASE. Library is now no longer actively maintained and marked as archived on GitHub 6 | 7 | #### v2.4.0 (2021-12) 8 | * Drop support for PHP 7.0 [#89](https://github.com/fgrosse/PHPASN1/pull/89) 9 | 10 | #### v2.3.1 (2021-12) 11 | * Add `#[\ReturnTypeWillChange]` attributes for PHP 8.1 compatibility [#87](https://github.com/fgrosse/PHPASN1/pull/87) 12 | 13 | #### v2.3.0 (2021-04) 14 | * Allow creating an unsigned CSR and adding the signature later [#82](https://github.com/fgrosse/PHPASN1/pull/82) 15 | 16 | #### v2.2.0 (2020-08) 17 | * support polyfills for bcmath and gmp, and add a composer.json 18 | suggestion for the `phpseclib/bcmath_polyfill` for servers unable 19 | to install PHP the gmp or bcmath extensions. 20 | 21 | #### v.2.1.1 & &v.2.0.2 (2018-12) 22 | * add stricter validation around some structures, highlighed 23 | by wycheproof test suite 24 | 25 | #### v.2.1.0 (2018-03) 26 | * add support for `bcmath` extension (making `gmp` optional) [#68](https://github.com/fgrosse/PHPASN1/pull/68) 27 | 28 | #### v.2.0.1 & v.1.5.3 (2017-12) 29 | * add .gitattributes file to prevent examples and tests to be installed via composer when --prefer-dist was set 30 | 31 | #### v.2.0.0 (2017-08) 32 | * rename `FG\ASN1\Object` to `FG\ASN1\ASNObject` because `Object` is a special class name in the next major PHP release 33 | - when you upgrade you have to adapt all corresponding `use` and `extends` statements as well as type hints and all 34 | usages of `Object::fromBinary(…)`. 35 | * generally drop PHP 5.6 support 36 | 37 | #### v.1.5.2 (2016-10-29) 38 | * allow empty octet strings 39 | 40 | #### v.1.5.1 (2015-10-02) 41 | * add keywords to composer.json (this is a version on its own so the keywords are found on a stable version at packagist.org) 42 | 43 | #### v.1.5.0 (2015-10-30) 44 | * fix a bug that would prevent you from decoding context specific tags on multiple objects [#57](https://github.com/fgrosse/PHPASN1/issues/57) 45 | - `ExplicitlyTaggedObject::__construct` does now accept multiple objects to be tagged with a single tag 46 | - `ExplicitlyTaggedObject::getContent` will now always return an array (even if only one object is tagged) 47 | 48 | #### v.1.4.2 (2015-09-29) 49 | * fix a bug that would prevent you from decoding empty tagged objects [#57](https://github.com/fgrosse/PHPASN1/issues/57) 50 | 51 | #### v.1.4.1 52 | * improve exception messages and general error handling [#55](https ://github.com/fgrosse/PHPASN1/pull/55) 53 | 54 | #### v.1.4.0 55 | * **require PHP 5.6** 56 | * support big integers (closes #1 and #37) 57 | * enforce one code style via [styleci.io][9] 58 | * track code coverage via [coveralls.io][10] 59 | * replace obsolete `FG\ASN1\Exception\GeneralException` with `\Exception` 60 | * `Construct` (`Sequence`, `Set`) does now implement `ArrayAccess`, `Countable` and `Iterator` so its easier to use 61 | * add [`TemplateParser`][11] 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2015 Friedrich Große 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHPASN1 2 | ======= 3 | 4 | [![Latest Stable Version](https://poser.pugx.org/fgrosse/phpasn1/v/stable.png)](https://packagist.org/packages/fgrosse/phpasn1) 5 | [![Total Downloads](https://poser.pugx.org/fgrosse/phpasn1/downloads.png)](https://packagist.org/packages/fgrosse/phpasn1) 6 | [![License](https://poser.pugx.org/fgrosse/phpasn1/license.png)](https://packagist.org/packages/fgrosse/phpasn1) 7 | 8 | --- 9 | 10 |

Notice: This library is no longer actively maintained!

11 | If you are currently using PHPASN1, this might not be an immediate problem for you, since this library was always rather stable. 12 | 13 | However, you are advised to migrate to alternative packages to ensure that your applications remain functional also with newer PHP versions. 14 | 15 | Another option is to fork this repository or use [one of the existing forks][14]. 16 | 17 | ⚠ **If you are using another fork, please make sure you trust the author** and validate the code you are relying upon! 18 | 19 | --- 20 | 21 | A PHP Framework that allows you to encode and decode arbitrary [ASN.1][3] structures 22 | using the [ITU-T X.690 Encoding Rules][4]. 23 | This encoding is very frequently used in [X.509 PKI environments][5] or the communication between heterogeneous computer systems. 24 | 25 | The API allows you to encode ASN.1 structures to create binary data such as certificate 26 | signing requests (CSR), X.509 certificates or certificate revocation lists (CRL). 27 | PHPASN1 can also read [BER encoded][6] binary data into separate PHP objects that can be manipulated by the user and reencoded afterwards. 28 | 29 | The **changelog** can now be found at [CHANGELOG.md](CHANGELOG.md). 30 | 31 | ## Dependencies 32 | 33 | PHPASN1 requires at least `PHP 7.0` and either the `gmp` or `bcmath` extension. 34 | Support for older PHP versions (i.e. PHP 5.6) was dropped starting with `v2.0`. 35 | If you must use an outdated PHP version consider using [PHPASN v1.5][13]. 36 | 37 | For the loading of object identifier names directly from the web [curl][7] is used. 38 | 39 | ## Installation 40 | 41 | The preferred way to install this library is to rely on [Composer][2]: 42 | 43 | ```bash 44 | $ composer require fgrosse/phpasn1 45 | ``` 46 | 47 | ## Usage 48 | 49 | ### Encoding ASN.1 Structures 50 | 51 | PHPASN1 offers you a class for each of the implemented ASN.1 universal types. 52 | The constructors should be pretty self explanatory so you should have no big trouble getting started. 53 | All data will be encoded using [DER encoding][8] 54 | 55 | ```php 56 | use FG\ASN1\OID; 57 | use FG\ASN1\Universal\Integer; 58 | use FG\ASN1\Universal\Boolean; 59 | use FG\ASN1\Universal\Enumerated; 60 | use FG\ASN1\Universal\IA5String; 61 | use FG\ASN1\Universal\ObjectIdentifier; 62 | use FG\ASN1\Universal\PrintableString; 63 | use FG\ASN1\Universal\Sequence; 64 | use FG\ASN1\Universal\Set; 65 | use FG\ASN1\Universal\NullObject; 66 | 67 | $integer = new Integer(123456); 68 | $boolean = new Boolean(true); 69 | $enum = new Enumerated(1); 70 | $ia5String = new IA5String('Hello world'); 71 | 72 | $asnNull = new NullObject(); 73 | $objectIdentifier1 = new ObjectIdentifier('1.2.250.1.16.9'); 74 | $objectIdentifier2 = new ObjectIdentifier(OID::RSA_ENCRYPTION); 75 | $printableString = new PrintableString('Foo bar'); 76 | 77 | $sequence = new Sequence($integer, $boolean, $enum, $ia5String); 78 | $set = new Set($sequence, $asnNull, $objectIdentifier1, $objectIdentifier2, $printableString); 79 | 80 | $myBinary = $sequence->getBinary(); 81 | $myBinary .= $set->getBinary(); 82 | 83 | echo base64_encode($myBinary); 84 | ``` 85 | 86 | 87 | ### Decoding binary data 88 | 89 | Decoding BER encoded binary data is just as easy as encoding it: 90 | 91 | ```php 92 | use FG\ASN1\ASNObject; 93 | 94 | $base64String = ... 95 | $binaryData = base64_decode($base64String); 96 | $asnObject = ASNObject::fromBinary($binaryData); 97 | 98 | 99 | // do stuff 100 | ``` 101 | 102 | If you already know exactly how your expected data should look like you can use the `FG\ASN1\TemplateParser`: 103 | 104 | ```php 105 | use FG\ASN1\TemplateParser; 106 | 107 | // first define your template 108 | $template = [ 109 | Identifier::SEQUENCE => [ 110 | Identifier::SET => [ 111 | Identifier::OBJECT_IDENTIFIER, 112 | Identifier::SEQUENCE => [ 113 | Identifier::INTEGER, 114 | Identifier::BITSTRING, 115 | ] 116 | ] 117 | ] 118 | ]; 119 | 120 | // if your binary data is not matching the template you provided this will throw an `\Exception`: 121 | $parser = new TemplateParser(); 122 | $object = $parser->parseBinary($data, $template); 123 | 124 | // there is also a convenience function if you parse binary data from base64: 125 | $object = $parser->parseBase64($data, $template); 126 | ``` 127 | 128 | You can use this function to make sure your data has exactly the format you are expecting. 129 | 130 | ### Navigating decoded data 131 | 132 | All constructed classes (i.e. `Sequence` and `Set`) can be navigated by array access or using an iterator. 133 | You can find examples 134 | [here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L148-148), 135 | [here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L121) and 136 | [here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/TemplateParserTest.php#L45). 137 | 138 | 139 | ### Give me more examples! 140 | 141 | To see some example usage of the API classes or some generated output check out the [examples](https://github.com/fgrosse/PHPASN1/tree/master/examples). 142 | 143 | 144 | ### How do I contribute? 145 | 146 | This project is no longer maintained and thus does not accept any new contributions. 147 | 148 | ### Thanks 149 | 150 | To [all contributors][1] so far! 151 | 152 | ## License 153 | 154 | This library is distributed under the [MIT License](LICENSE). 155 | 156 | [1]: https://github.com/fgrosse/PHPASN1/graphs/contributors 157 | [2]: https://getcomposer.org/ 158 | [3]: http://www.itu.int/ITU-T/asn1/ 159 | [4]: http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=x.690 160 | [5]: http://en.wikipedia.org/wiki/X.509 161 | [6]: http://en.wikipedia.org/wiki/X.690#BER_encoding 162 | [7]: http://php.net/manual/en/book.curl.php 163 | [8]: http://en.wikipedia.org/wiki/X.690#DER_encoding 164 | [9]: https://styleci.io 165 | [10]: https://coveralls.io/github/fgrosse/PHPASN1 166 | [11]: https://github.com/fgrosse/PHPASN1/blob/master/tests/ASN1/TemplateParserTest.php#L16 167 | [12]: https://groups.google.com/d/forum/phpasn1 168 | [13]: https://packagist.org/packages/fgrosse/phpasn1#1.5.2 169 | [14]: https://github.com/fgrosse/PHPASN1/forks?include=active&page=1&period=2y&sort_by=last_updated 170 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fgrosse/phpasn1", 3 | "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", 4 | "type": "library", 5 | "homepage": "https://github.com/FGrosse/PHPASN1", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Friedrich Große", 10 | "email": "friedrich.grosse@gmail.com", 11 | "homepage": "https://github.com/FGrosse", 12 | "role": "Author" 13 | }, 14 | { 15 | "name": "All contributors", 16 | "homepage": "https://github.com/FGrosse/PHPASN1/contributors" 17 | } 18 | ], 19 | "keywords": [ "x690", "x.690", "x.509", "x509", "asn1", "asn.1", "ber", "der", "binary", "encoding", "decoding" ], 20 | 21 | "require": { 22 | "php": "^7.1 || ^8.0" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", 26 | "php-coveralls/php-coveralls": "~2.0" 27 | }, 28 | "suggest": { 29 | "ext-gmp": "GMP is the preferred extension for big integer calculations", 30 | "ext-bcmath": "BCmath is the fallback extension for big integer calculations", 31 | "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available", 32 | "ext-curl": "For loading OID information from the web if they have not bee defined statically" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "FG\\": "lib/" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "FG\\Test\\": "tests/" 42 | } 43 | }, 44 | "extra": { 45 | "branch-alias": { 46 | "dev-master": "2.0.x-dev" 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/ASN1/ASNObject.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use FG\ASN1\Exception\ParserException; 14 | use FG\ASN1\Universal\BitString; 15 | use FG\ASN1\Universal\Boolean; 16 | use FG\ASN1\Universal\Enumerated; 17 | use FG\ASN1\Universal\GeneralizedTime; 18 | use FG\ASN1\Universal\Integer; 19 | use FG\ASN1\Universal\NullObject; 20 | use FG\ASN1\Universal\ObjectIdentifier; 21 | use FG\ASN1\Universal\RelativeObjectIdentifier; 22 | use FG\ASN1\Universal\OctetString; 23 | use FG\ASN1\Universal\Sequence; 24 | use FG\ASN1\Universal\Set; 25 | use FG\ASN1\Universal\UTCTime; 26 | use FG\ASN1\Universal\IA5String; 27 | use FG\ASN1\Universal\PrintableString; 28 | use FG\ASN1\Universal\NumericString; 29 | use FG\ASN1\Universal\UTF8String; 30 | use FG\ASN1\Universal\UniversalString; 31 | use FG\ASN1\Universal\CharacterString; 32 | use FG\ASN1\Universal\GeneralString; 33 | use FG\ASN1\Universal\VisibleString; 34 | use FG\ASN1\Universal\GraphicString; 35 | use FG\ASN1\Universal\BMPString; 36 | use FG\ASN1\Universal\T61String; 37 | use FG\ASN1\Universal\ObjectDescriptor; 38 | use FG\Utility\BigInteger; 39 | use LogicException; 40 | 41 | /** 42 | * Class ASNObject is the base class for all concrete ASN.1 objects. 43 | */ 44 | abstract class ASNObject implements Parsable 45 | { 46 | private $contentLength; 47 | private $nrOfLengthOctets; 48 | 49 | /** 50 | * Must return the number of octets of the content part. 51 | * 52 | * @return int 53 | */ 54 | abstract protected function calculateContentLength(); 55 | 56 | /** 57 | * Encode the object using DER encoding. 58 | * 59 | * @see http://en.wikipedia.org/wiki/X.690#DER_encoding 60 | * 61 | * @return string the binary representation of an objects value 62 | */ 63 | abstract protected function getEncodedValue(); 64 | 65 | /** 66 | * Return the content of this object in a non encoded form. 67 | * This can be used to print the value in human readable form. 68 | * 69 | * @return mixed 70 | */ 71 | abstract public function getContent(); 72 | 73 | /** 74 | * Return the object type octet. 75 | * This should use the class constants of Identifier. 76 | * 77 | * @see Identifier 78 | * 79 | * @return int 80 | */ 81 | abstract public function getType(); 82 | 83 | /** 84 | * Returns all identifier octets. If an inheriting class models a tag with 85 | * the long form identifier format, it MUST reimplement this method to 86 | * return all octets of the identifier. 87 | * 88 | * @throws LogicException If the identifier format is long form 89 | * 90 | * @return string Identifier as a set of octets 91 | */ 92 | public function getIdentifier() 93 | { 94 | $firstOctet = $this->getType(); 95 | 96 | if (Identifier::isLongForm($firstOctet)) { 97 | throw new LogicException(sprintf('Identifier of %s uses the long form and must therefor override "ASNObject::getIdentifier()".', get_class($this))); 98 | } 99 | 100 | return chr($firstOctet); 101 | } 102 | 103 | /** 104 | * Encode this object using DER encoding. 105 | * 106 | * @return string the full binary representation of the complete object 107 | */ 108 | public function getBinary() 109 | { 110 | $result = $this->getIdentifier(); 111 | $result .= $this->createLengthPart(); 112 | $result .= $this->getEncodedValue(); 113 | 114 | return $result; 115 | } 116 | 117 | private function createLengthPart() 118 | { 119 | $contentLength = $this->getContentLength(); 120 | $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength); 121 | 122 | if ($nrOfLengthOctets == 1) { 123 | return chr($contentLength); 124 | } else { 125 | // the first length octet determines the number subsequent length octets 126 | $lengthOctets = chr(0x80 | ($nrOfLengthOctets - 1)); 127 | for ($shiftLength = 8 * ($nrOfLengthOctets - 2); $shiftLength >= 0; $shiftLength -= 8) { 128 | $lengthOctets .= chr($contentLength >> $shiftLength); 129 | } 130 | 131 | return $lengthOctets; 132 | } 133 | } 134 | 135 | protected function getNumberOfLengthOctets($contentLength = null) 136 | { 137 | if (!isset($this->nrOfLengthOctets)) { 138 | if ($contentLength == null) { 139 | $contentLength = $this->getContentLength(); 140 | } 141 | 142 | $this->nrOfLengthOctets = 1; 143 | if ($contentLength > 127) { 144 | do { // long form 145 | $this->nrOfLengthOctets++; 146 | $contentLength = $contentLength >> 8; 147 | } while ($contentLength > 0); 148 | } 149 | } 150 | 151 | return $this->nrOfLengthOctets; 152 | } 153 | 154 | protected function getContentLength() 155 | { 156 | if (!isset($this->contentLength)) { 157 | $this->contentLength = $this->calculateContentLength(); 158 | } 159 | 160 | return $this->contentLength; 161 | } 162 | 163 | protected function setContentLength($newContentLength) 164 | { 165 | $this->contentLength = $newContentLength; 166 | $this->getNumberOfLengthOctets($newContentLength); 167 | } 168 | 169 | /** 170 | * Returns the length of the whole object (including the identifier and length octets). 171 | */ 172 | public function getObjectLength() 173 | { 174 | $nrOfIdentifierOctets = strlen($this->getIdentifier()); 175 | $contentLength = $this->getContentLength(); 176 | $nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength); 177 | 178 | return $nrOfIdentifierOctets + $nrOfLengthOctets + $contentLength; 179 | } 180 | 181 | public function __toString() 182 | { 183 | return $this->getContent(); 184 | } 185 | 186 | /** 187 | * Returns the name of the ASN.1 Type of this object. 188 | * 189 | * @see Identifier::getName() 190 | */ 191 | public function getTypeName() 192 | { 193 | return Identifier::getName($this->getType()); 194 | } 195 | 196 | /** 197 | * @param string $binaryData 198 | * @param int $offsetIndex 199 | * 200 | * @throws ParserException 201 | * 202 | * @return \FG\ASN1\ASNObject 203 | */ 204 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 205 | { 206 | if (strlen($binaryData) <= $offsetIndex) { 207 | throw new ParserException('Can not parse binary from data: Offset index larger than input size', $offsetIndex); 208 | } 209 | 210 | $identifierOctet = ord($binaryData[$offsetIndex]); 211 | if (Identifier::isContextSpecificClass($identifierOctet) && Identifier::isConstructed($identifierOctet)) { 212 | return ExplicitlyTaggedObject::fromBinary($binaryData, $offsetIndex); 213 | } 214 | 215 | switch ($identifierOctet) { 216 | case Identifier::BITSTRING: 217 | return BitString::fromBinary($binaryData, $offsetIndex); 218 | case Identifier::BOOLEAN: 219 | return Boolean::fromBinary($binaryData, $offsetIndex); 220 | case Identifier::ENUMERATED: 221 | return Enumerated::fromBinary($binaryData, $offsetIndex); 222 | case Identifier::INTEGER: 223 | return Integer::fromBinary($binaryData, $offsetIndex); 224 | case Identifier::NULL: 225 | return NullObject::fromBinary($binaryData, $offsetIndex); 226 | case Identifier::OBJECT_IDENTIFIER: 227 | return ObjectIdentifier::fromBinary($binaryData, $offsetIndex); 228 | case Identifier::RELATIVE_OID: 229 | return RelativeObjectIdentifier::fromBinary($binaryData, $offsetIndex); 230 | case Identifier::OCTETSTRING: 231 | return OctetString::fromBinary($binaryData, $offsetIndex); 232 | case Identifier::SEQUENCE: 233 | return Sequence::fromBinary($binaryData, $offsetIndex); 234 | case Identifier::SET: 235 | return Set::fromBinary($binaryData, $offsetIndex); 236 | case Identifier::UTC_TIME: 237 | return UTCTime::fromBinary($binaryData, $offsetIndex); 238 | case Identifier::GENERALIZED_TIME: 239 | return GeneralizedTime::fromBinary($binaryData, $offsetIndex); 240 | case Identifier::IA5_STRING: 241 | return IA5String::fromBinary($binaryData, $offsetIndex); 242 | case Identifier::PRINTABLE_STRING: 243 | return PrintableString::fromBinary($binaryData, $offsetIndex); 244 | case Identifier::NUMERIC_STRING: 245 | return NumericString::fromBinary($binaryData, $offsetIndex); 246 | case Identifier::UTF8_STRING: 247 | return UTF8String::fromBinary($binaryData, $offsetIndex); 248 | case Identifier::UNIVERSAL_STRING: 249 | return UniversalString::fromBinary($binaryData, $offsetIndex); 250 | case Identifier::CHARACTER_STRING: 251 | return CharacterString::fromBinary($binaryData, $offsetIndex); 252 | case Identifier::GENERAL_STRING: 253 | return GeneralString::fromBinary($binaryData, $offsetIndex); 254 | case Identifier::VISIBLE_STRING: 255 | return VisibleString::fromBinary($binaryData, $offsetIndex); 256 | case Identifier::GRAPHIC_STRING: 257 | return GraphicString::fromBinary($binaryData, $offsetIndex); 258 | case Identifier::BMP_STRING: 259 | return BMPString::fromBinary($binaryData, $offsetIndex); 260 | case Identifier::T61_STRING: 261 | return T61String::fromBinary($binaryData, $offsetIndex); 262 | case Identifier::OBJECT_DESCRIPTOR: 263 | return ObjectDescriptor::fromBinary($binaryData, $offsetIndex); 264 | default: 265 | // At this point the identifier may be >1 byte. 266 | if (Identifier::isConstructed($identifierOctet)) { 267 | return new UnknownConstructedObject($binaryData, $offsetIndex); 268 | } else { 269 | $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); 270 | $lengthOfUnknownObject = self::parseContentLength($binaryData, $offsetIndex); 271 | $offsetIndex += $lengthOfUnknownObject; 272 | 273 | return new UnknownObject($identifier, $lengthOfUnknownObject); 274 | } 275 | } 276 | } 277 | 278 | protected static function parseIdentifier($identifierOctet, $expectedIdentifier, $offsetForExceptionHandling) 279 | { 280 | if (is_string($identifierOctet) || is_numeric($identifierOctet) == false) { 281 | $identifierOctet = ord($identifierOctet); 282 | } 283 | 284 | if ($identifierOctet != $expectedIdentifier) { 285 | $message = 'Can not create an '.Identifier::getName($expectedIdentifier).' from an '.Identifier::getName($identifierOctet); 286 | throw new ParserException($message, $offsetForExceptionHandling); 287 | } 288 | } 289 | 290 | protected static function parseBinaryIdentifier($binaryData, &$offsetIndex) 291 | { 292 | if (strlen($binaryData) <= $offsetIndex) { 293 | throw new ParserException('Can not parse identifier from data: Offset index larger than input size', $offsetIndex); 294 | } 295 | 296 | $identifier = $binaryData[$offsetIndex++]; 297 | 298 | if (Identifier::isLongForm(ord($identifier)) == false) { 299 | return $identifier; 300 | } 301 | 302 | while (true) { 303 | if (strlen($binaryData) <= $offsetIndex) { 304 | throw new ParserException('Can not parse identifier (long form) from data: Offset index larger than input size', $offsetIndex); 305 | } 306 | $nextOctet = $binaryData[$offsetIndex++]; 307 | $identifier .= $nextOctet; 308 | 309 | if ((ord($nextOctet) & 0x80) === 0) { 310 | // the most significant bit is 0 to we have reached the end of the identifier 311 | break; 312 | } 313 | } 314 | 315 | return $identifier; 316 | } 317 | 318 | protected static function parseContentLength(&$binaryData, &$offsetIndex, $minimumLength = 0) 319 | { 320 | if (strlen($binaryData) <= $offsetIndex) { 321 | throw new ParserException('Can not parse content length from data: Offset index larger than input size', $offsetIndex); 322 | } 323 | 324 | $contentLength = ord($binaryData[$offsetIndex++]); 325 | if (($contentLength & 0x80) != 0) { 326 | // bit 8 is set -> this is the long form 327 | $nrOfLengthOctets = $contentLength & 0x7F; 328 | $contentLength = BigInteger::create(0x00); 329 | for ($i = 0; $i < $nrOfLengthOctets; $i++) { 330 | if (strlen($binaryData) <= $offsetIndex) { 331 | throw new ParserException('Can not parse content length (long form) from data: Offset index larger than input size', $offsetIndex); 332 | } 333 | $contentLength = $contentLength->shiftLeft(8)->add(ord($binaryData[$offsetIndex++])); 334 | } 335 | 336 | if ($contentLength->compare(PHP_INT_MAX) > 0) { 337 | throw new ParserException("Can not parse content length from data: length > maximum integer", $offsetIndex); 338 | } 339 | 340 | $contentLength = $contentLength->toInteger(); 341 | } 342 | 343 | if ($contentLength < $minimumLength) { 344 | throw new ParserException('A '.get_called_class()." should have a content length of at least {$minimumLength}. Extracted length was {$contentLength}", $offsetIndex); 345 | } 346 | 347 | $lenDataRemaining = strlen($binaryData) - $offsetIndex; 348 | 349 | if ($lenDataRemaining < $contentLength) { 350 | throw new ParserException("Content length {$contentLength} exceeds remaining data length {$lenDataRemaining}", $offsetIndex); 351 | } 352 | 353 | return $contentLength; 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /lib/ASN1/AbstractString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use Exception; 14 | 15 | abstract class AbstractString extends ASNObject implements Parsable 16 | { 17 | /** @var string */ 18 | protected $value; 19 | private $checkStringForIllegalChars = true; 20 | private $allowedCharacters = []; 21 | 22 | /** 23 | * The abstract base class for ASN.1 classes which represent some string of character. 24 | * 25 | * @param string $string 26 | */ 27 | public function __construct($string) 28 | { 29 | $this->value = $string; 30 | } 31 | 32 | public function getContent() 33 | { 34 | return $this->value; 35 | } 36 | 37 | protected function allowCharacter($character) 38 | { 39 | $this->allowedCharacters[] = $character; 40 | } 41 | 42 | protected function allowCharacters(...$characters) 43 | { 44 | foreach ($characters as $character) { 45 | $this->allowedCharacters[] = $character; 46 | } 47 | } 48 | 49 | protected function allowNumbers() 50 | { 51 | foreach (range('0', '9') as $char) { 52 | $this->allowedCharacters[] = (string) $char; 53 | } 54 | } 55 | 56 | protected function allowAllLetters() 57 | { 58 | $this->allowSmallLetters(); 59 | $this->allowCapitalLetters(); 60 | } 61 | 62 | protected function allowSmallLetters() 63 | { 64 | foreach (range('a', 'z') as $char) { 65 | $this->allowedCharacters[] = $char; 66 | } 67 | } 68 | 69 | protected function allowCapitalLetters() 70 | { 71 | foreach (range('A', 'Z') as $char) { 72 | $this->allowedCharacters[] = $char; 73 | } 74 | } 75 | 76 | protected function allowSpaces() 77 | { 78 | $this->allowedCharacters[] = ' '; 79 | } 80 | 81 | protected function allowAll() 82 | { 83 | $this->checkStringForIllegalChars = false; 84 | } 85 | 86 | protected function calculateContentLength() 87 | { 88 | return strlen($this->value); 89 | } 90 | 91 | protected function getEncodedValue() 92 | { 93 | if ($this->checkStringForIllegalChars) { 94 | $this->checkString(); 95 | } 96 | 97 | return $this->value; 98 | } 99 | 100 | protected function checkString() 101 | { 102 | $stringLength = $this->getContentLength(); 103 | for ($i = 0; $i < $stringLength; $i++) { 104 | if (in_array($this->value[$i], $this->allowedCharacters) == false) { 105 | $typeName = Identifier::getName($this->getType()); 106 | throw new Exception("Could not create a {$typeName} from the character sequence '{$this->value}'."); 107 | } 108 | } 109 | } 110 | 111 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 112 | { 113 | $parsedObject = new static(''); 114 | 115 | self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); 116 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 117 | $string = substr($binaryData, $offsetIndex, $contentLength); 118 | $offsetIndex += $contentLength; 119 | 120 | $parsedObject->value = $string; 121 | $parsedObject->setContentLength($contentLength); 122 | return $parsedObject; 123 | } 124 | 125 | public static function isValid($string) 126 | { 127 | $testObject = new static($string); 128 | try { 129 | $testObject->checkString(); 130 | 131 | return true; 132 | } catch (Exception $exception) { 133 | return false; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /lib/ASN1/AbstractTime.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use DateInterval; 14 | use DateTime; 15 | use DateTimeZone; 16 | use Exception; 17 | 18 | abstract class AbstractTime extends ASNObject 19 | { 20 | /** @var DateTime */ 21 | protected $value; 22 | 23 | public function __construct($dateTime = null, $dateTimeZone = 'UTC') 24 | { 25 | if ($dateTime == null || is_string($dateTime)) { 26 | $timeZone = new DateTimeZone($dateTimeZone); 27 | $dateTimeObject = new DateTime($dateTime, $timeZone); 28 | if ($dateTimeObject == false) { 29 | $errorMessage = $this->getLastDateTimeErrors(); 30 | $className = Identifier::getName($this->getType()); 31 | throw new Exception(sprintf("Could not create %s from date time string '%s': %s", $className, $dateTime, $errorMessage)); 32 | } 33 | $dateTime = $dateTimeObject; 34 | } elseif (!$dateTime instanceof DateTime) { 35 | throw new Exception('Invalid first argument for some instance of AbstractTime constructor'); 36 | } 37 | 38 | $this->value = $dateTime; 39 | } 40 | 41 | public function getContent() 42 | { 43 | return $this->value; 44 | } 45 | 46 | protected function getLastDateTimeErrors() 47 | { 48 | $messages = ''; 49 | $lastErrors = DateTime::getLastErrors() ?: ['errors' => []]; 50 | foreach ($lastErrors['errors'] as $errorMessage) { 51 | $messages .= "{$errorMessage}, "; 52 | } 53 | 54 | return substr($messages, 0, -2); 55 | } 56 | 57 | public function __toString() 58 | { 59 | return $this->value->format("Y-m-d\tH:i:s"); 60 | } 61 | 62 | protected static function extractTimeZoneData(&$binaryData, &$offsetIndex, DateTime $dateTime) 63 | { 64 | $sign = $binaryData[$offsetIndex++]; 65 | $timeOffsetHours = intval(substr($binaryData, $offsetIndex, 2)); 66 | $timeOffsetMinutes = intval(substr($binaryData, $offsetIndex + 2, 2)); 67 | $offsetIndex += 4; 68 | 69 | $interval = new DateInterval("PT{$timeOffsetHours}H{$timeOffsetMinutes}M"); 70 | if ($sign == '+') { 71 | $dateTime->sub($interval); 72 | } else { 73 | $dateTime->add($interval); 74 | } 75 | 76 | return $dateTime; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/ASN1/Base128.php: -------------------------------------------------------------------------------- 1 | modulus(0x80)->toInteger()); 22 | 23 | $value = $value->shiftRight(7); 24 | while ($value->compare(0) > 0) { 25 | $octets .= chr(0x80 | $value->modulus(0x80)->toInteger()); 26 | $value = $value->shiftRight(7); 27 | } 28 | 29 | return strrev($octets); 30 | } 31 | 32 | /** 33 | * @param string $octets 34 | * 35 | * @throws InvalidArgumentException if the given octets represent a malformed base-128 value or the decoded value would exceed the the maximum integer length 36 | * 37 | * @return int 38 | */ 39 | public static function decode($octets) 40 | { 41 | $bitsPerOctet = 7; 42 | $value = BigInteger::create(0); 43 | $i = 0; 44 | 45 | while (true) { 46 | if (!isset($octets[$i])) { 47 | throw new InvalidArgumentException(sprintf('Malformed base-128 encoded value (0x%s).', strtoupper(bin2hex($octets)) ?: '0')); 48 | } 49 | 50 | $octet = ord($octets[$i++]); 51 | 52 | $l1 = $value->shiftLeft($bitsPerOctet); 53 | $r1 = $octet & 0x7f; 54 | $value = $l1->add($r1); 55 | 56 | if (0 === ($octet & 0x80)) { 57 | break; 58 | } 59 | } 60 | 61 | return (string)$value; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/ASN1/Composite/AttributeTypeAndValue.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Composite; 12 | 13 | use FG\ASN1\ASNObject; 14 | use FG\ASN1\Universal\Sequence; 15 | use FG\ASN1\Universal\ObjectIdentifier; 16 | 17 | class AttributeTypeAndValue extends Sequence 18 | { 19 | /** 20 | * @param ObjectIdentifier|string $objIdentifier 21 | * @param \FG\ASN1\ASNObject $value 22 | */ 23 | public function __construct($objIdentifier, ASNObject $value) 24 | { 25 | if ($objIdentifier instanceof ObjectIdentifier == false) { 26 | $objIdentifier = new ObjectIdentifier($objIdentifier); 27 | } 28 | parent::__construct($objIdentifier, $value); 29 | } 30 | 31 | public function __toString() 32 | { 33 | return $this->children[0].': '.$this->children[1]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/ASN1/Composite/RDNString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Composite; 12 | 13 | use FG\ASN1\Universal\PrintableString; 14 | use FG\ASN1\Universal\IA5String; 15 | use FG\ASN1\Universal\UTF8String; 16 | 17 | class RDNString extends RelativeDistinguishedName 18 | { 19 | /** 20 | * @param string|\FG\ASN1\Universal\ObjectIdentifier $objectIdentifierString 21 | * @param string|\FG\ASN1\ASNObject $value 22 | */ 23 | public function __construct($objectIdentifierString, $value) 24 | { 25 | if (PrintableString::isValid($value)) { 26 | $value = new PrintableString($value); 27 | } else { 28 | if (IA5String::isValid($value)) { 29 | $value = new IA5String($value); 30 | } else { 31 | $value = new UTF8String($value); 32 | } 33 | } 34 | 35 | parent::__construct($objectIdentifierString, $value); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/ASN1/Composite/RelativeDistinguishedName.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Composite; 12 | 13 | use FG\ASN1\Exception\NotImplementedException; 14 | use FG\ASN1\ASNObject; 15 | use FG\ASN1\Universal\Set; 16 | 17 | class RelativeDistinguishedName extends Set 18 | { 19 | /** 20 | * @param string|\FG\ASN1\Universal\ObjectIdentifier $objIdentifierString 21 | * @param \FG\ASN1\ASNObject $value 22 | */ 23 | public function __construct($objIdentifierString, ASNObject $value) 24 | { 25 | // TODO: This does only support one element in the RelativeDistinguishedName Set but it it is defined as follows: 26 | // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue 27 | parent::__construct(new AttributeTypeAndValue($objIdentifierString, $value)); 28 | } 29 | 30 | public function getContent() 31 | { 32 | /** @var \FG\ASN1\ASNObject $firstObject */ 33 | $firstObject = $this->children[0]; 34 | return $firstObject->__toString(); 35 | } 36 | 37 | /** 38 | * At the current version this code can not work since the implementation of Construct requires 39 | * the class to support a constructor without arguments. 40 | * 41 | * @deprecated this function is not yet implemented! Feel free to submit a pull request on github 42 | * @param string $binaryData 43 | * @param int $offsetIndex 44 | * @throws NotImplementedException 45 | */ 46 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 47 | { 48 | throw new NotImplementedException(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/ASN1/Construct.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use ArrayAccess; 14 | use ArrayIterator; 15 | use Countable; 16 | use FG\ASN1\Exception\ParserException; 17 | use Iterator; 18 | 19 | abstract class Construct extends ASNObject implements Countable, ArrayAccess, Iterator, Parsable 20 | { 21 | /** @var \FG\ASN1\ASNObject[] */ 22 | protected $children; 23 | private $iteratorPosition; 24 | 25 | /** 26 | * @param \FG\ASN1\ASNObject[] $children the variadic type hint is commented due to https://github.com/facebook/hhvm/issues/4858 27 | */ 28 | public function __construct(/* HH_FIXME[4858]: variadic + strict */ ...$children) 29 | { 30 | $this->children = $children; 31 | $this->iteratorPosition = 0; 32 | } 33 | 34 | public function getContent() 35 | { 36 | return $this->children; 37 | } 38 | 39 | #[\ReturnTypeWillChange] 40 | public function rewind() 41 | { 42 | $this->iteratorPosition = 0; 43 | } 44 | 45 | #[\ReturnTypeWillChange] 46 | public function current() 47 | { 48 | return $this->children[$this->iteratorPosition]; 49 | } 50 | 51 | #[\ReturnTypeWillChange] 52 | public function key() 53 | { 54 | return $this->iteratorPosition; 55 | } 56 | 57 | #[\ReturnTypeWillChange] 58 | public function next() 59 | { 60 | $this->iteratorPosition++; 61 | } 62 | 63 | #[\ReturnTypeWillChange] 64 | public function valid() 65 | { 66 | return isset($this->children[$this->iteratorPosition]); 67 | } 68 | 69 | #[\ReturnTypeWillChange] 70 | public function offsetExists($offset) 71 | { 72 | return array_key_exists($offset, $this->children); 73 | } 74 | 75 | #[\ReturnTypeWillChange] 76 | public function offsetGet($offset) 77 | { 78 | return $this->children[$offset]; 79 | } 80 | 81 | #[\ReturnTypeWillChange] 82 | public function offsetSet($offset, $value) 83 | { 84 | if ($offset === null) { 85 | $offset = count($this->children); 86 | } 87 | 88 | $this->children[$offset] = $value; 89 | } 90 | 91 | #[\ReturnTypeWillChange] 92 | public function offsetUnset($offset) 93 | { 94 | unset($this->children[$offset]); 95 | } 96 | 97 | protected function calculateContentLength() 98 | { 99 | $length = 0; 100 | foreach ($this->children as $component) { 101 | $length += $component->getObjectLength(); 102 | } 103 | 104 | return $length; 105 | } 106 | 107 | protected function getEncodedValue() 108 | { 109 | $result = ''; 110 | foreach ($this->children as $component) { 111 | $result .= $component->getBinary(); 112 | } 113 | 114 | return $result; 115 | } 116 | 117 | public function addChild(ASNObject $child) 118 | { 119 | $this->children[] = $child; 120 | } 121 | 122 | public function addChildren(array $children) 123 | { 124 | foreach ($children as $child) { 125 | $this->addChild($child); 126 | } 127 | } 128 | 129 | public function __toString() 130 | { 131 | $nrOfChildren = $this->getNumberOfChildren(); 132 | $childString = $nrOfChildren == 1 ? 'child' : 'children'; 133 | 134 | return "[{$nrOfChildren} {$childString}]"; 135 | } 136 | 137 | public function getNumberOfChildren() 138 | { 139 | return count($this->children); 140 | } 141 | 142 | /** 143 | * @return \FG\ASN1\ASNObject[] 144 | */ 145 | public function getChildren() 146 | { 147 | return $this->children; 148 | } 149 | 150 | /** 151 | * @return \FG\ASN1\ASNObject 152 | */ 153 | public function getFirstChild() 154 | { 155 | return $this->children[0]; 156 | } 157 | 158 | /** 159 | * @param string $binaryData 160 | * @param int $offsetIndex 161 | * 162 | * @throws Exception\ParserException 163 | * 164 | * @return Construct|static 165 | */ 166 | #[\ReturnTypeWillChange] 167 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 168 | { 169 | $parsedObject = new static(); 170 | self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); 171 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 172 | $startIndex = $offsetIndex; 173 | 174 | $children = []; 175 | $octetsToRead = $contentLength; 176 | while ($octetsToRead > 0) { 177 | $newChild = ASNObject::fromBinary($binaryData, $offsetIndex); 178 | $octetsToRead -= $newChild->getObjectLength(); 179 | $children[] = $newChild; 180 | } 181 | 182 | if ($octetsToRead !== 0) { 183 | throw new ParserException("Sequence length incorrect", $startIndex); 184 | } 185 | 186 | $parsedObject->addChildren($children); 187 | $parsedObject->setContentLength($contentLength); 188 | 189 | return $parsedObject; 190 | } 191 | 192 | #[\ReturnTypeWillChange] 193 | public function count($mode = COUNT_NORMAL) 194 | { 195 | return count($this->children, $mode); 196 | } 197 | 198 | public function getIterator() 199 | { 200 | return new ArrayIterator($this->children); 201 | } 202 | } -------------------------------------------------------------------------------- /lib/ASN1/Exception/NotImplementedException.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Exception; 12 | 13 | class NotImplementedException extends \Exception 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /lib/ASN1/Exception/ParserException.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Exception; 12 | 13 | class ParserException extends \Exception 14 | { 15 | private $errorMessage; 16 | private $offset; 17 | 18 | public function __construct($errorMessage, $offset) 19 | { 20 | $this->errorMessage = $errorMessage; 21 | $this->offset = $offset; 22 | parent::__construct("ASN.1 Parser Exception at offset {$this->offset}: {$this->errorMessage}"); 23 | } 24 | 25 | public function getOffset() 26 | { 27 | return $this->offset; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/ASN1/ExplicitlyTaggedObject.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use FG\ASN1\Exception\ParserException; 14 | 15 | /** 16 | * Class ExplicitlyTaggedObject decorate an inner object with an additional tag that gives information about 17 | * its context specific meaning. 18 | * 19 | * Explanation taken from A Layman's Guide to a Subset of ASN.1, BER, and DER: 20 | * >>> An RSA Laboratories Technical Note 21 | * >>> Burton S. Kaliski Jr. 22 | * >>> Revised November 1, 1993 23 | * 24 | * [...] 25 | * Explicitly tagged types are derived from other types by adding an outer tag to the underlying type. 26 | * In effect, explicitly tagged types are structured types consisting of one component, the underlying type. 27 | * Explicit tagging is denoted by the ASN.1 keywords [class number] EXPLICIT (see Section 5.2). 28 | * [...] 29 | * 30 | * @see http://luca.ntop.org/Teaching/Appunti/asn1.html 31 | */ 32 | class ExplicitlyTaggedObject extends ASNObject 33 | { 34 | /** @var \FG\ASN1\ASNObject[] */ 35 | private $decoratedObjects; 36 | private $tag; 37 | 38 | /** 39 | * @param int $tag 40 | * @param \FG\ASN1\ASNObject $objects,... 41 | */ 42 | public function __construct($tag, /* HH_FIXME[4858]: variadic + strict */ ...$objects) 43 | { 44 | $this->tag = $tag; 45 | $this->decoratedObjects = $objects; 46 | } 47 | 48 | protected function calculateContentLength() 49 | { 50 | $length = 0; 51 | foreach ($this->decoratedObjects as $object) { 52 | $length += $object->getObjectLength(); 53 | } 54 | 55 | return $length; 56 | } 57 | 58 | protected function getEncodedValue() 59 | { 60 | $encoded = ''; 61 | foreach ($this->decoratedObjects as $object) { 62 | $encoded .= $object->getBinary(); 63 | } 64 | 65 | return $encoded; 66 | } 67 | 68 | public function getContent() 69 | { 70 | return $this->decoratedObjects; 71 | } 72 | 73 | public function __toString() 74 | { 75 | switch ($length = count($this->decoratedObjects)) { 76 | case 0: 77 | return "Context specific empty object with tag [{$this->tag}]"; 78 | case 1: 79 | $decoratedType = Identifier::getShortName($this->decoratedObjects[0]->getType()); 80 | return "Context specific $decoratedType with tag [{$this->tag}]"; 81 | default: 82 | return "$length context specific objects with tag [{$this->tag}]"; 83 | } 84 | } 85 | 86 | public function getType() 87 | { 88 | return ord($this->getIdentifier()); 89 | } 90 | 91 | public function getIdentifier() 92 | { 93 | $identifier = Identifier::create(Identifier::CLASS_CONTEXT_SPECIFIC, true, $this->tag); 94 | 95 | return is_int($identifier) ? chr($identifier) : $identifier; 96 | } 97 | 98 | public function getTag() 99 | { 100 | return $this->tag; 101 | } 102 | 103 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 104 | { 105 | $identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); 106 | $firstIdentifierOctet = ord($identifier); 107 | assert(Identifier::isContextSpecificClass($firstIdentifierOctet), 'identifier octet should indicate context specific class'); 108 | assert(Identifier::isConstructed($firstIdentifierOctet), 'identifier octet should indicate constructed object'); 109 | $tag = Identifier::getTagNumber($identifier); 110 | 111 | $totalContentLength = self::parseContentLength($binaryData, $offsetIndex); 112 | $remainingContentLength = $totalContentLength; 113 | 114 | $offsetIndexOfDecoratedObject = $offsetIndex; 115 | $decoratedObjects = []; 116 | 117 | while ($remainingContentLength > 0) { 118 | $nextObject = ASNObject::fromBinary($binaryData, $offsetIndex); 119 | $remainingContentLength -= $nextObject->getObjectLength(); 120 | $decoratedObjects[] = $nextObject; 121 | } 122 | 123 | if ($remainingContentLength != 0) { 124 | 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); 125 | } 126 | 127 | $parsedObject = new self($tag, ...$decoratedObjects); 128 | $parsedObject->setContentLength($totalContentLength); 129 | return $parsedObject; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /lib/ASN1/Identifier.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use Exception; 14 | 15 | /** 16 | * The Identifier encodes the ASN.1 tag (class and number) of the type of a data value. 17 | * 18 | * Every identifier whose number is in the range 0 to 30 has the following structure: 19 | * 20 | * Bits: 8 7 6 5 4 3 2 1 21 | * | Class | P/C | Tag number | 22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | * 24 | * Bits 8 and 7 define the class of this type ( Universal, Application, Context-specific or Private). 25 | * Bit 6 encoded whether this type is primitive or constructed 26 | * The remaining bits 5 - 1 encode the tag number 27 | */ 28 | class Identifier 29 | { 30 | const CLASS_UNIVERSAL = 0x00; 31 | const CLASS_APPLICATION = 0x01; 32 | const CLASS_CONTEXT_SPECIFIC = 0x02; 33 | const CLASS_PRIVATE = 0x03; 34 | 35 | const EOC = 0x00; // unsupported for now 36 | const BOOLEAN = 0x01; 37 | const INTEGER = 0x02; 38 | const BITSTRING = 0x03; 39 | const OCTETSTRING = 0x04; 40 | const NULL = 0x05; 41 | const OBJECT_IDENTIFIER = 0x06; 42 | const OBJECT_DESCRIPTOR = 0x07; 43 | const EXTERNAL = 0x08; // unsupported for now 44 | const REAL = 0x09; // unsupported for now 45 | const ENUMERATED = 0x0A; 46 | const EMBEDDED_PDV = 0x0B; // unsupported for now 47 | const UTF8_STRING = 0x0C; 48 | const RELATIVE_OID = 0x0D; 49 | // value 0x0E and 0x0F are reserved for future use 50 | 51 | const SEQUENCE = 0x30; 52 | const SET = 0x31; 53 | const NUMERIC_STRING = 0x12; 54 | const PRINTABLE_STRING = 0x13; 55 | const T61_STRING = 0x14; // sometimes referred to as TeletextString 56 | const VIDEOTEXT_STRING = 0x15; 57 | const IA5_STRING = 0x16; 58 | const UTC_TIME = 0x17; 59 | const GENERALIZED_TIME = 0x18; 60 | const GRAPHIC_STRING = 0x19; 61 | const VISIBLE_STRING = 0x1A; 62 | const GENERAL_STRING = 0x1B; 63 | const UNIVERSAL_STRING = 0x1C; 64 | const CHARACTER_STRING = 0x1D; // Unrestricted character type 65 | const BMP_STRING = 0x1E; 66 | 67 | const LONG_FORM = 0x1F; 68 | const IS_CONSTRUCTED = 0x20; 69 | 70 | /** 71 | * Creates an identifier. Short form identifiers are returned as integers 72 | * for BC, long form identifiers will be returned as a string of octets. 73 | * 74 | * @param int $class 75 | * @param bool $isConstructed 76 | * @param int $tagNumber 77 | * 78 | * @throws Exception if the given arguments are invalid 79 | * 80 | * @return int|string 81 | */ 82 | public static function create($class, $isConstructed, $tagNumber) 83 | { 84 | if (!is_numeric($class) || $class < self::CLASS_UNIVERSAL || $class > self::CLASS_PRIVATE) { 85 | throw new Exception(sprintf('Invalid class %d given', $class)); 86 | } 87 | 88 | if (!is_bool($isConstructed)) { 89 | throw new Exception("\$isConstructed must be a boolean value ($isConstructed given)"); 90 | } 91 | 92 | $tagNumber = self::makeNumeric($tagNumber); 93 | if ($tagNumber < 0) { 94 | throw new Exception(sprintf('Invalid $tagNumber %d given. You can only use positive integers.', $tagNumber)); 95 | } 96 | 97 | if ($tagNumber < self::LONG_FORM) { 98 | return ($class << 6) | ($isConstructed << 5) | $tagNumber; 99 | } 100 | 101 | $firstOctet = ($class << 6) | ($isConstructed << 5) | self::LONG_FORM; 102 | 103 | // Tag numbers formatted in long form are base-128 encoded. See X.609#8.1.2.4 104 | return chr($firstOctet).Base128::encode($tagNumber); 105 | } 106 | 107 | public static function isConstructed($identifierOctet) 108 | { 109 | return ($identifierOctet & self::IS_CONSTRUCTED) === self::IS_CONSTRUCTED; 110 | } 111 | 112 | public static function isLongForm($identifierOctet) 113 | { 114 | return ($identifierOctet & self::LONG_FORM) === self::LONG_FORM; 115 | } 116 | 117 | /** 118 | * Return the name of the mapped ASN.1 type with a preceding "ASN.1 ". 119 | * 120 | * Example: ASN.1 Octet String 121 | * 122 | * @see Identifier::getShortName() 123 | * 124 | * @param int|string $identifier 125 | * 126 | * @return string 127 | */ 128 | public static function getName($identifier) 129 | { 130 | $identifierOctet = self::makeNumeric($identifier); 131 | 132 | $typeName = static::getShortName($identifier); 133 | 134 | if (($identifierOctet & self::LONG_FORM) < self::LONG_FORM) { 135 | $typeName = "ASN.1 {$typeName}"; 136 | } 137 | 138 | return $typeName; 139 | } 140 | 141 | /** 142 | * Return the short version of the type name. 143 | * 144 | * If the given identifier octet can be mapped to a known universal type this will 145 | * return its name. Else Identifier::getClassDescription() is used to retrieve 146 | * information about the identifier. 147 | * 148 | * @see Identifier::getName() 149 | * @see Identifier::getClassDescription() 150 | * 151 | * @param int|string $identifier 152 | * 153 | * @return string 154 | */ 155 | public static function getShortName($identifier) 156 | { 157 | $identifierOctet = self::makeNumeric($identifier); 158 | 159 | switch ($identifierOctet) { 160 | case self::EOC: 161 | return 'End-of-contents octet'; 162 | case self::BOOLEAN: 163 | return 'Boolean'; 164 | case self::INTEGER: 165 | return 'Integer'; 166 | case self::BITSTRING: 167 | return 'Bit String'; 168 | case self::OCTETSTRING: 169 | return 'Octet String'; 170 | case self::NULL: 171 | return 'NULL'; 172 | case self::OBJECT_IDENTIFIER: 173 | return 'Object Identifier'; 174 | case self::OBJECT_DESCRIPTOR: 175 | return 'Object Descriptor'; 176 | case self::EXTERNAL: 177 | return 'External Type'; 178 | case self::REAL: 179 | return 'Real'; 180 | case self::ENUMERATED: 181 | return 'Enumerated'; 182 | case self::EMBEDDED_PDV: 183 | return 'Embedded PDV'; 184 | case self::UTF8_STRING: 185 | return 'UTF8 String'; 186 | case self::RELATIVE_OID: 187 | return 'Relative OID'; 188 | case self::SEQUENCE: 189 | return 'Sequence'; 190 | case self::SET: 191 | return 'Set'; 192 | case self::NUMERIC_STRING: 193 | return 'Numeric String'; 194 | case self::PRINTABLE_STRING: 195 | return 'Printable String'; 196 | case self::T61_STRING: 197 | return 'T61 String'; 198 | case self::VIDEOTEXT_STRING: 199 | return 'Videotext String'; 200 | case self::IA5_STRING: 201 | return 'IA5 String'; 202 | case self::UTC_TIME: 203 | return 'UTC Time'; 204 | case self::GENERALIZED_TIME: 205 | return 'Generalized Time'; 206 | case self::GRAPHIC_STRING: 207 | return 'Graphic String'; 208 | case self::VISIBLE_STRING: 209 | return 'Visible String'; 210 | case self::GENERAL_STRING: 211 | return 'General String'; 212 | case self::UNIVERSAL_STRING: 213 | return 'Universal String'; 214 | case self::CHARACTER_STRING: 215 | return 'Character String'; 216 | case self::BMP_STRING: 217 | return 'BMP String'; 218 | 219 | case 0x0E: 220 | return 'RESERVED (0x0E)'; 221 | case 0x0F: 222 | return 'RESERVED (0x0F)'; 223 | 224 | case self::LONG_FORM: 225 | default: 226 | $classDescription = self::getClassDescription($identifier); 227 | 228 | if (is_int($identifier)) { 229 | $identifier = chr($identifier); 230 | } 231 | 232 | return "$classDescription (0x".strtoupper(bin2hex($identifier)).')'; 233 | } 234 | } 235 | 236 | /** 237 | * Returns a textual description of the information encoded in a given identifier octet. 238 | * 239 | * The first three (most significant) bytes are evaluated to determine if this is a 240 | * constructed or primitive type and if it is either universal, application, context-specific or 241 | * private. 242 | * 243 | * Example: 244 | * Constructed context-specific 245 | * Primitive universal 246 | * 247 | * @param int|string $identifier 248 | * 249 | * @return string 250 | */ 251 | public static function getClassDescription($identifier) 252 | { 253 | $identifierOctet = self::makeNumeric($identifier); 254 | 255 | if (self::isConstructed($identifierOctet)) { 256 | $classDescription = 'Constructed '; 257 | } else { 258 | $classDescription = 'Primitive '; 259 | } 260 | $classBits = $identifierOctet >> 6; 261 | switch ($classBits) { 262 | case self::CLASS_UNIVERSAL: 263 | $classDescription .= 'universal'; 264 | break; 265 | case self::CLASS_APPLICATION: 266 | $classDescription .= 'application'; 267 | break; 268 | case self::CLASS_CONTEXT_SPECIFIC: 269 | $tagNumber = self::getTagNumber($identifier); 270 | $classDescription = "[$tagNumber] Context-specific"; 271 | break; 272 | case self::CLASS_PRIVATE: 273 | $classDescription .= 'private'; 274 | break; 275 | 276 | default: 277 | return "INVALID IDENTIFIER OCTET: {$identifierOctet}"; 278 | } 279 | 280 | return $classDescription; 281 | } 282 | 283 | /** 284 | * @param int|string $identifier 285 | * 286 | * @return int 287 | */ 288 | public static function getTagNumber($identifier) 289 | { 290 | $firstOctet = self::makeNumeric($identifier); 291 | $tagNumber = $firstOctet & self::LONG_FORM; 292 | 293 | if ($tagNumber < self::LONG_FORM) { 294 | return $tagNumber; 295 | } 296 | 297 | if (is_numeric($identifier)) { 298 | $identifier = chr($identifier); 299 | } 300 | return Base128::decode(substr($identifier, 1)); 301 | } 302 | 303 | public static function isUniversalClass($identifier) 304 | { 305 | $identifier = self::makeNumeric($identifier); 306 | 307 | return $identifier >> 6 == self::CLASS_UNIVERSAL; 308 | } 309 | 310 | public static function isApplicationClass($identifier) 311 | { 312 | $identifier = self::makeNumeric($identifier); 313 | 314 | return $identifier >> 6 == self::CLASS_APPLICATION; 315 | } 316 | 317 | public static function isContextSpecificClass($identifier) 318 | { 319 | $identifier = self::makeNumeric($identifier); 320 | 321 | return $identifier >> 6 == self::CLASS_CONTEXT_SPECIFIC; 322 | } 323 | 324 | public static function isPrivateClass($identifier) 325 | { 326 | $identifier = self::makeNumeric($identifier); 327 | 328 | return $identifier >> 6 == self::CLASS_PRIVATE; 329 | } 330 | 331 | private static function makeNumeric($identifierOctet) 332 | { 333 | if (!is_numeric($identifierOctet)) { 334 | return ord($identifierOctet); 335 | } else { 336 | return $identifierOctet; 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /lib/ASN1/OID.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | class OID 14 | { 15 | const RSA_ENCRYPTION = '1.2.840.113549.1.1.1'; 16 | const MD5_WITH_RSA_ENCRYPTION = '1.2.840.113549.1.1.4'; 17 | const SHA1_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.5'; 18 | const SHA256_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.11'; 19 | const PKCS9_EMAIL = '1.2.840.113549.1.9.1'; 20 | const PKCS9_UNSTRUCTURED_NAME = '1.2.840.113549.1.9.2'; 21 | const PKCS9_CONTENT_TYPE = '1.2.840.113549.1.9.3'; 22 | const PKCS9_MESSAGE_DIGEST = '1.2.840.113549.1.9.4'; 23 | const PKCS9_SIGNING_TIME = '1.2.840.113549.1.9.5'; 24 | const PKCS9_EXTENSION_REQUEST = '1.2.840.113549.1.9.14'; 25 | 26 | // certificate extension identifier 27 | const CERT_EXT_SUBJECT_DIRECTORY_ATTR = '2.5.29.9'; 28 | const CERT_EXT_SUBJECT_KEY_IDENTIFIER = '2.5.29.14'; 29 | const CERT_EXT_KEY_USAGE = '2.5.29.15'; 30 | const CERT_EXT_PRIVATE_KEY_USAGE_PERIOD = '2.5.29.16'; 31 | const CERT_EXT_SUBJECT_ALT_NAME = '2.5.29.17'; 32 | const CERT_EXT_ISSUER_ALT_NAME = '2.5.29.18'; 33 | const CERT_EXT_BASIC_CONSTRAINTS = '2.5.29.19'; 34 | const CERT_EXT_CRL_NUMBER = '2.5.29.20'; 35 | const CERT_EXT_REASON_CODE = '2.5.29.21'; 36 | const CERT_EXT_INVALIDITY_DATE = '2.5.29.24'; 37 | const CERT_EXT_DELTA_CRL_INDICATOR = '2.5.29.27'; 38 | const CERT_EXT_ISSUING_DIST_POINT = '2.5.29.28'; 39 | const CERT_EXT_CERT_ISSUER = '2.5.29.29'; 40 | const CERT_EXT_NAME_CONSTRAINTS = '2.5.29.30'; 41 | const CERT_EXT_CRL_DISTRIBUTION_POINTS = '2.5.29.31'; 42 | const CERT_EXT_CERT_POLICIES = '2.5.29.32'; 43 | const CERT_EXT_AUTHORITY_KEY_IDENTIFIER = '2.5.29.35'; 44 | const CERT_EXT_EXTENDED_KEY_USAGE = '2.5.29.37'; 45 | 46 | // standard certificate files 47 | const COMMON_NAME = '2.5.4.3'; 48 | const SURNAME = '2.5.4.4'; 49 | const SERIAL_NUMBER = '2.5.4.5'; 50 | const COUNTRY_NAME = '2.5.4.6'; 51 | const LOCALITY_NAME = '2.5.4.7'; 52 | const STATE_OR_PROVINCE_NAME = '2.5.4.8'; 53 | const STREET_ADDRESS = '2.5.4.9'; 54 | const ORGANIZATION_NAME = '2.5.4.10'; 55 | const OU_NAME = '2.5.4.11'; 56 | const TITLE = '2.5.4.12'; 57 | const DESCRIPTION = '2.5.4.13'; 58 | const POSTAL_ADDRESS = '2.5.4.16'; 59 | const POSTAL_CODE = '2.5.4.17'; 60 | const AUTHORITY_REVOCATION_LIST = '2.5.4.38'; 61 | 62 | const AUTHORITY_INFORMATION_ACCESS = '1.3.6.1.5.5.7.1.1'; 63 | 64 | /** 65 | * Returns the name of the given object identifier. 66 | * 67 | * Some OIDs are saved as class constants in this class. 68 | * If the wanted oidString is not among them, this method will 69 | * query http://oid-info.com for the right name. 70 | * This behavior can be suppressed by setting the second method parameter to false. 71 | * 72 | * @param string $oidString 73 | * @param bool $loadFromWeb 74 | * 75 | * @see self::loadFromWeb($oidString) 76 | * 77 | * @return string 78 | */ 79 | public static function getName($oidString, $loadFromWeb = true) 80 | { 81 | $oids = [ 82 | '1.2' => 'ISO Member Body', 83 | '1.3' => 'org', 84 | '1.3.6.1.5.5.8.1.1' => 'hmac-md5', 85 | '1.3.6.1.5.5.8.1.2' => 'hmac-sha1', 86 | '1.3.132' => 'certicom-arc', 87 | '2.23' => 'International Organizations', 88 | '2.23.43' => 'wap', 89 | '2.23.43.1' => 'wap-wsg', 90 | '2.5.1.5' => 'Selected Attribute Types', 91 | '2.5.1.5.55' => 'clearance', 92 | '1.2.840' => 'ISO US Member Body', 93 | '1.2.840.10040' => 'X9.57', 94 | '1.2.840.10040.4' => 'X9.57 CM ?', 95 | '1.2.840.10040.4.1' => 'dsaEncryption', 96 | '1.2.840.10040.4.3' => 'dsaWithSHA1', 97 | '1.2.840.10045' => 'ANSI X9.62', 98 | '1.2.840.10045.1' => 'X9-62_id-fieldType', 99 | '1.2.840.10045.1.1' => 'X9-62_prime-field', 100 | '1.2.840.10045.1.2' => 'X9-62_characteristic-two-field', 101 | '1.2.840.10045.1.2.3' => 'X9-62_id-characteristic-two-basis', 102 | '1.2.840.10045.1.2.3.1' => 'X9-62_onBasis', 103 | '1.2.840.10045.1.2.3.2' => 'X9-62_tpBasis', 104 | '1.2.840.10045.1.2.3.3' => 'X9-62_ppBasis', 105 | '1.2.840.10045.2' => 'X9-62_id-publicKeyType', 106 | '1.2.840.10045.2.1' => 'X9-62_id-ecPublicKey', 107 | '1.2.840.10045.3' => 'X9-62_ellipticCurve', 108 | '1.2.840.10045.3.0' => 'X9-62_c-TwoCurve', 109 | '1.2.840.10045.3.0.1' => 'X9-62_c2pnb163v1', 110 | '1.2.840.10045.3.0.2' => 'X9-62_c2pnb163v2', 111 | '1.2.840.10045.3.0.3' => 'X9-62_c2pnb163v3', 112 | '1.2.840.10045.3.0.4' => 'X9-62_c2pnb176v1', 113 | '1.2.840.10045.3.0.5' => 'X9-62_c2tnb191v1', 114 | '1.2.840.10045.3.0.6' => 'X9-62_c2tnb191v2', 115 | '1.2.840.10045.3.0.7' => 'X9-62_c2tnb191v3', 116 | '1.2.840.10045.3.0.8' => 'X9-62_c2onb191v4', 117 | '1.2.840.10045.3.0.9' => 'X9-62_c2onb191v5', 118 | '1.2.840.10045.3.0.10' => 'X9-62_c2pnb208w1', 119 | '1.2.840.10045.3.0.11' => 'X9-62_c2tnb239v1', 120 | '1.2.840.10045.3.0.12' => 'X9-62_c2tnb239v2', 121 | '1.2.840.10045.3.0.13' => 'X9-62_c2tnb239v3', 122 | '1.2.840.10045.3.0.14' => 'X9-62_c2onb239v4', 123 | '1.2.840.10045.3.0.15' => 'X9-62_c2onb239v5', 124 | '1.2.840.10045.3.0.16' => 'X9-62_c2pnb272w1', 125 | '1.2.840.10045.3.0.17' => 'X9-62_c2pnb304w1', 126 | '1.2.840.10045.3.0.18' => 'X9-62_c2tnb359v1', 127 | '1.2.840.10045.3.0.19' => 'X9-62_c2pnb368w1', 128 | '1.2.840.10045.3.0.20' => 'X9-62_c2tnb431r1', 129 | '1.2.840.10045.3.1' => 'X9-62_primeCurve', 130 | '1.2.840.10045.3.1.1' => 'X9-62_prime192v1', 131 | '1.2.840.10045.3.1.2' => 'X9-62_prime192v2', 132 | '1.2.840.10045.3.1.3' => 'X9-62_prime192v3', 133 | '1.2.840.10045.3.1.4' => 'X9-62_prime239v1', 134 | '1.2.840.10045.3.1.5' => 'X9-62_prime239v2', 135 | '1.2.840.10045.3.1.6' => 'X9-62_prime239v3', 136 | '1.2.840.10045.3.1.7' => 'X9-62_prime256v1', 137 | '1.2.840.10045.4' => 'X9-62_id-ecSigType', 138 | '1.2.840.10045.4.1' => 'ecdsa-with-SHA1', 139 | '1.2.840.10045.4.2' => 'ecdsa-with-Recommended', 140 | '1.2.840.10045.4.3' => 'ecdsa-with-Specified', 141 | '1.2.840.10045.4.3.1' => 'ecdsa-with-SHA224', 142 | '1.2.840.10045.4.3.2' => 'ecdsa-with-SHA256', 143 | '1.2.840.10045.4.3.3' => 'ecdsa-with-SHA384', 144 | '1.2.840.10045.4.3.4' => 'ecdsa-with-SHA512', 145 | '1.3.132.0' => 'secg_ellipticCurve', 146 | '2.23.43.1.4' => 'wap-wsg-idm-ecid', 147 | '2.23.43.1.4.1' => 'wap-wsg-idm-ecid-wtls1', 148 | '2.23.43.1.4.3' => 'wap-wsg-idm-ecid-wtls3', 149 | '2.23.43.1.4.4' => 'wap-wsg-idm-ecid-wtls4', 150 | '2.23.43.1.4.5' => 'wap-wsg-idm-ecid-wtls5', 151 | '2.23.43.1.4.6' => 'wap-wsg-idm-ecid-wtls6', 152 | '2.23.43.1.4.7' => 'wap-wsg-idm-ecid-wtls7', 153 | '2.23.43.1.4.8' => 'wap-wsg-idm-ecid-wtls8', 154 | '2.23.43.1.4.9' => 'wap-wsg-idm-ecid-wtls9', 155 | '2.23.43.1.4.10' => 'wap-wsg-idm-ecid-wtls10', 156 | '2.23.43.1.4.11' => 'wap-wsg-idm-ecid-wtls11', 157 | '2.23.43.1.4.12' => 'wap-wsg-idm-ecid-wtls12', 158 | '1.2.840.113533.7.66.10' => 'cast5-cbc', 159 | '1.2.840.113533.7.66.12' => 'pbeWithMD5AndCast5CBC', 160 | '1.2.840.113533.7.66.13' => 'password based MAC', 161 | '1.2.840.113533.7.66.30' => 'Diffie-Hellman based MAC', 162 | '1.2.840.113549' => 'RSA Data Security, Inc.', 163 | '1.2.840.113549.1' => 'RSA Data Security, Inc. PKCS', 164 | '1.2.840.113549.1.1' => 'pkcs1', 165 | '1.2.840.113549.1.1.1' => 'rsaEncryption', 166 | '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', 167 | '1.2.840.113549.1.1.3' => 'md4WithRSAEncryption', 168 | '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption', 169 | '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption', 170 | '1.2.840.113549.1.1.7' => 'rsaesOaep', 171 | '1.2.840.113549.1.1.8' => 'mgf1', 172 | '1.2.840.113549.1.1.9' => 'pSpecified', 173 | '1.2.840.113549.1.1.10' => 'rsassaPss', 174 | '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption', 175 | '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption', 176 | '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption', 177 | '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption', 178 | '1.2.840.113549.1.3' => 'pkcs3', 179 | '1.2.840.113549.1.3.1' => 'dhKeyAgreement', 180 | '1.2.840.113549.1.5' => 'pkcs5', 181 | '1.2.840.113549.1.5.1' => 'pbeWithMD2AndDES-CBC', 182 | '1.2.840.113549.1.5.3' => 'pbeWithMD5AndDES-CBC', 183 | '1.2.840.113549.1.5.4' => 'pbeWithMD2AndRC2-CBC', 184 | '1.2.840.113549.1.5.6' => 'pbeWithMD5AndRC2-CBC', 185 | '1.2.840.113549.1.5.10' => 'pbeWithSHA1AndDES-CBC', 186 | '1.2.840.113549.1.5.11' => 'pbeWithSHA1AndRC2-CBC', 187 | '1.2.840.113549.1.5.12' => 'PBKDF2', 188 | '1.2.840.113549.1.5.13' => 'PBES2', 189 | '1.2.840.113549.1.5.14' => 'PBMAC1', 190 | '1.2.840.113549.1.7' => 'pkcs7', 191 | '1.2.840.113549.1.7.1' => 'pkcs7-data', 192 | '1.2.840.113549.1.7.2' => 'pkcs7-signedData', 193 | '1.2.840.113549.1.7.3' => 'pkcs7-envelopedData', 194 | '1.2.840.113549.1.7.4' => 'pkcs7-signedAndEnvelopedData', 195 | '1.2.840.113549.1.7.5' => 'pkcs7-digestData', 196 | '1.2.840.113549.1.7.6' => 'pkcs7-encryptedData', 197 | '1.2.840.113549.1.9' => 'pkcs9', 198 | '1.2.840.113549.1.9.1' => 'emailAddress', 199 | '1.2.840.113549.1.9.2' => 'unstructuredName', 200 | '1.2.840.113549.1.9.3' => 'contentType', 201 | '1.2.840.113549.1.9.4' => 'messageDigest', 202 | '1.2.840.113549.1.9.5' => 'signingTime', 203 | '1.2.840.113549.1.9.6' => 'countersignature', 204 | '1.2.840.113549.1.9.7' => 'challengePassword', 205 | '1.2.840.113549.1.9.8' => 'unstructuredAddress', 206 | '1.2.840.113549.1.9.9' => 'extendedCertificateAttributes', 207 | '1.2.840.113549.1.9.14' => 'Extension Request', 208 | '1.2.840.113549.1.9.15' => 'S/MIME Capabilities', 209 | '1.2.840.113549.1.9.16' => 'S/MIME', 210 | '1.2.840.113549.1.9.16.0' => 'id-smime-mod', 211 | '1.2.840.113549.1.9.16.1' => 'id-smime-ct', 212 | '1.2.840.113549.1.9.16.2' => 'id-smime-aa', 213 | '1.2.840.113549.1.9.16.3' => 'id-smime-alg', 214 | '1.2.840.113549.1.9.16.4' => 'id-smime-cd', 215 | '1.2.840.113549.1.9.16.5' => 'id-smime-spq', 216 | '1.2.840.113549.1.9.16.6' => 'id-smime-cti', 217 | '1.2.840.113549.1.9.16.0.1' => 'id-smime-mod-cms', 218 | '1.2.840.113549.1.9.16.0.2' => 'id-smime-mod-ess', 219 | '1.2.840.113549.1.9.16.0.3' => 'id-smime-mod-oid', 220 | '1.2.840.113549.1.9.16.0.4' => 'id-smime-mod-msg-v3', 221 | '1.2.840.113549.1.9.16.0.5' => 'id-smime-mod-ets-eSignature-88', 222 | '1.2.840.113549.1.9.16.0.6' => 'id-smime-mod-ets-eSignature-97', 223 | '1.2.840.113549.1.9.16.0.7' => 'id-smime-mod-ets-eSigPolicy-88', 224 | '1.2.840.113549.1.9.16.0.8' => 'id-smime-mod-ets-eSigPolicy-97', 225 | '1.2.840.113549.1.9.16.1.1' => 'id-smime-ct-receipt', 226 | '1.2.840.113549.1.9.16.1.2' => 'id-smime-ct-authData', 227 | '1.2.840.113549.1.9.16.1.3' => 'id-smime-ct-publishCert', 228 | '1.2.840.113549.1.9.16.1.4' => 'id-smime-ct-TSTInfo', 229 | '1.2.840.113549.1.9.16.1.5' => 'id-smime-ct-TDTInfo', 230 | '1.2.840.113549.1.9.16.1.6' => 'id-smime-ct-contentInfo', 231 | '1.2.840.113549.1.9.16.1.7' => 'id-smime-ct-DVCSRequestData', 232 | '1.2.840.113549.1.9.16.1.8' => 'id-smime-ct-DVCSResponseData', 233 | '1.2.840.113549.1.9.16.1.9' => 'id-smime-ct-compressedData', 234 | '1.2.840.113549.1.9.16.1.27' => 'id-ct-asciiTextWithCRLF', 235 | '1.2.840.113549.1.9.16.2.1' => 'id-smime-aa-receiptRequest', 236 | '1.2.840.113549.1.9.16.2.2' => 'id-smime-aa-securityLabel', 237 | '1.2.840.113549.1.9.16.2.3' => 'id-smime-aa-mlExpandHistory', 238 | '1.2.840.113549.1.9.16.2.4' => 'id-smime-aa-contentHint', 239 | '1.2.840.113549.1.9.16.2.5' => 'id-smime-aa-msgSigDigest', 240 | '1.2.840.113549.1.9.16.2.6' => 'id-smime-aa-encapContentType', 241 | '1.2.840.113549.1.9.16.2.7' => 'id-smime-aa-contentIdentifier', 242 | '1.2.840.113549.1.9.16.2.8' => 'id-smime-aa-macValue', 243 | '1.2.840.113549.1.9.16.2.9' => 'id-smime-aa-equivalentLabels', 244 | '1.2.840.113549.1.9.16.2.10' => 'id-smime-aa-contentReference', 245 | '1.2.840.113549.1.9.16.2.11' => 'id-smime-aa-encrypKeyPref', 246 | '1.2.840.113549.1.9.16.2.12' => 'id-smime-aa-signingCertificate', 247 | '1.2.840.113549.1.9.16.2.13' => 'id-smime-aa-smimeEncryptCerts', 248 | '1.2.840.113549.1.9.16.2.14' => 'id-smime-aa-timeStampToken', 249 | '1.2.840.113549.1.9.16.2.15' => 'id-smime-aa-ets-sigPolicyId', 250 | '1.2.840.113549.1.9.16.2.16' => 'id-smime-aa-ets-commitmentType', 251 | '1.2.840.113549.1.9.16.2.17' => 'id-smime-aa-ets-signerLocation', 252 | '1.2.840.113549.1.9.16.2.18' => 'id-smime-aa-ets-signerAttr', 253 | '1.2.840.113549.1.9.16.2.19' => 'id-smime-aa-ets-otherSigCert', 254 | '1.2.840.113549.1.9.16.2.20' => 'id-smime-aa-ets-contentTimestamp', 255 | '1.2.840.113549.1.9.16.2.21' => 'id-smime-aa-ets-CertificateRefs', 256 | '1.2.840.113549.1.9.16.2.22' => 'id-smime-aa-ets-RevocationRefs', 257 | '1.2.840.113549.1.9.16.2.23' => 'id-smime-aa-ets-certValues', 258 | '1.2.840.113549.1.9.16.2.24' => 'id-smime-aa-ets-revocationValues', 259 | '1.2.840.113549.1.9.16.2.25' => 'id-smime-aa-ets-escTimeStamp', 260 | '1.2.840.113549.1.9.16.2.26' => 'id-smime-aa-ets-certCRLTimestamp', 261 | '1.2.840.113549.1.9.16.2.27' => 'id-smime-aa-ets-archiveTimeStamp', 262 | '1.2.840.113549.1.9.16.2.28' => 'id-smime-aa-signatureType', 263 | '1.2.840.113549.1.9.16.2.29' => 'id-smime-aa-dvcs-dvc', 264 | '1.2.840.113549.1.9.16.3.1' => 'id-smime-alg-ESDHwith3DES', 265 | '1.2.840.113549.1.9.16.3.2' => 'id-smime-alg-ESDHwithRC2', 266 | '1.2.840.113549.1.9.16.3.3' => 'id-smime-alg-3DESwrap', 267 | '1.2.840.113549.1.9.16.3.4' => 'id-smime-alg-RC2wrap', 268 | '1.2.840.113549.1.9.16.3.5' => 'id-smime-alg-ESDH', 269 | '1.2.840.113549.1.9.16.3.6' => 'id-smime-alg-CMS3DESwrap', 270 | '1.2.840.113549.1.9.16.3.7' => 'id-smime-alg-CMSRC2wrap', 271 | '1.2.840.113549.1.9.16.3.9' => 'id-alg-PWRI-KEK', 272 | '1.2.840.113549.1.9.16.4.1' => 'id-smime-cd-ldap', 273 | '1.2.840.113549.1.9.16.5.1' => 'id-smime-spq-ets-sqt-uri', 274 | '1.2.840.113549.1.9.16.5.2' => 'id-smime-spq-ets-sqt-unotice', 275 | '1.2.840.113549.1.9.16.6.1' => 'id-smime-cti-ets-proofOfOrigin', 276 | '1.2.840.113549.1.9.16.6.2' => 'id-smime-cti-ets-proofOfReceipt', 277 | '1.2.840.113549.1.9.16.6.3' => 'id-smime-cti-ets-proofOfDelivery', 278 | '1.2.840.113549.1.9.16.6.4' => 'id-smime-cti-ets-proofOfSender', 279 | '1.2.840.113549.1.9.16.6.5' => 'id-smime-cti-ets-proofOfApproval', 280 | '1.2.840.113549.1.9.16.6.6' => 'id-smime-cti-ets-proofOfCreation', 281 | '1.2.840.113549.1.9.20' => 'friendlyName', 282 | '1.2.840.113549.1.9.21' => 'localKeyID', 283 | '1.3.6.1.4.1.311.17.1' => 'Microsoft CSP Name', 284 | '1.3.6.1.4.1.311.17.2' => 'Microsoft Local Key set', 285 | '1.2.840.113549.1.9.22' => 'certTypes', 286 | '1.2.840.113549.1.9.22.1' => 'x509Certificate', 287 | '1.2.840.113549.1.9.22.2' => 'sdsiCertificate', 288 | 289 | '1.2.840.113549.1.9.23' => 'crlTypes', 290 | '1.2.840.113549.1.9.23.1' => 'x509Crl', 291 | '1.2.840.113549.1.12' => 'pkcs12', 292 | '1.2.840.113549.1.12.1' => 'pkcs12-pbeids', 293 | '1.2.840.113549.1.12.1.1' => 'pbeWithSHA1And128BitRC4', 294 | '1.2.840.113549.1.12.1.2' => 'pbeWithSHA1And40BitRC4', 295 | '1.2.840.113549.1.12.1.3' => 'pbeWithSHA1And3-KeyTripleDES-CBC', 296 | '1.2.840.113549.1.12.1.4' => 'pbeWithSHA1And2-KeyTripleDES-CBC', 297 | '1.2.840.113549.1.12.1.5' => 'pbeWithSHA1And128BitRC2-CBC', 298 | '1.2.840.113549.1.12.1.6' => 'pbeWithSHA1And40BitRC2-CBC', 299 | '1.2.840.113549.1.12.10' => 'pkcs12-Version1', 300 | '1.2.840.113549.1.12.10.1' => 'pkcs12-BagIds', 301 | '1.2.840.113549.1.12.10.1.1' => 'keyBag', 302 | '1.2.840.113549.1.12.10.1.2' => 'pkcs8ShroudedKeyBag', 303 | '1.2.840.113549.1.12.10.1.3' => 'certBag', 304 | '1.2.840.113549.1.12.10.1.4' => 'crlBag', 305 | '1.2.840.113549.1.12.10.1.5' => 'secretBag', 306 | '1.2.840.113549.1.12.10.1.6' => 'safeContentsBag', 307 | '1.2.840.113549.2.2' => 'md2', 308 | '1.2.840.113549.2.4' => 'md4', 309 | '1.2.840.113549.2.5' => 'md5', 310 | '1.2.840.113549.2.6' => 'hmacWithMD5', 311 | '1.2.840.113549.2.7' => 'hmacWithSHA1', 312 | '1.2.840.113549.2.8' => 'hmacWithSHA224', 313 | '1.2.840.113549.2.9' => 'hmacWithSHA256', 314 | '1.2.840.113549.2.10' => 'hmacWithSHA384', 315 | '1.2.840.113549.2.11' => 'hmacWithSHA512', 316 | '1.2.840.113549.3.2' => 'rc2-cbc', 317 | '1.2.840.113549.3.4' => 'rc4', 318 | '1.2.840.113549.3.7' => 'des-ede3-cbc', 319 | '1.2.840.113549.3.8' => 'rc5-cbc', 320 | '1.3.6.1.4.1.311.2.1.14' => 'Microsoft Extension Request', 321 | '1.3.6.1.4.1.311.2.1.21' => 'Microsoft Individual Code Signing', 322 | '1.3.6.1.4.1.311.2.1.22' => 'Microsoft Commercial Code Signing', 323 | '1.3.6.1.4.1.311.10.3.1' => 'Microsoft Trust List Signing', 324 | '1.3.6.1.4.1.311.10.3.3' => 'Microsoft Server Gated Crypto', 325 | '1.3.6.1.4.1.311.10.3.4' => 'Microsoft Encrypted File System', 326 | '1.3.6.1.4.1.311.20.2.2' => 'Microsoft Smartcardlogin', 327 | '1.3.6.1.4.1.311.20.2.3' => 'Microsoft Universal Principal Name', 328 | '1.3.6.1.4.1.188.7.1.1.2' => 'idea-cbc', 329 | '1.3.6.1.4.1.3029.1.2' => 'bf-cbc', 330 | '1.3.6.1.5.5.7' => 'PKIX', 331 | '1.3.6.1.5.5.7.0' => 'id-pkix-mod', 332 | '1.3.6.1.5.5.7.1' => 'id-pe', 333 | '1.3.6.1.5.5.7.2' => 'id-qt', 334 | '1.3.6.1.5.5.7.3' => 'id-kp', 335 | '1.3.6.1.5.5.7.4' => 'id-it', 336 | '1.3.6.1.5.5.7.5' => 'id-pkip', 337 | '1.3.6.1.5.5.7.6' => 'id-alg', 338 | '1.3.6.1.5.5.7.7' => 'id-cmc', 339 | '1.3.6.1.5.5.7.8' => 'id-on', 340 | '1.3.6.1.5.5.7.9' => 'id-pda', 341 | '1.3.6.1.5.5.7.10' => 'id-aca', 342 | '1.3.6.1.5.5.7.11' => 'id-qcs', 343 | '1.3.6.1.5.5.7.12' => 'id-cct', 344 | '1.3.6.1.5.5.7.21' => 'id-ppl', 345 | '1.3.6.1.5.5.7.48' => 'id-ad', 346 | '1.3.6.1.5.5.7.0.1' => 'id-pkix1-explicit-88', 347 | '1.3.6.1.5.5.7.0.2' => 'id-pkix1-implicit-88', 348 | '1.3.6.1.5.5.7.0.3' => 'id-pkix1-explicit-93', 349 | '1.3.6.1.5.5.7.0.4' => 'id-pkix1-implicit-93', 350 | '1.3.6.1.5.5.7.0.5' => 'id-mod-crmf', 351 | '1.3.6.1.5.5.7.0.6' => 'id-mod-cmc', 352 | '1.3.6.1.5.5.7.0.7' => 'id-mod-kea-profile-88', 353 | '1.3.6.1.5.5.7.0.8' => 'id-mod-kea-profile-93', 354 | '1.3.6.1.5.5.7.0.9' => 'id-mod-cmp', 355 | '1.3.6.1.5.5.7.0.10' => 'id-mod-qualified-cert-88', 356 | '1.3.6.1.5.5.7.0.11' => 'id-mod-qualified-cert-93', 357 | '1.3.6.1.5.5.7.0.12' => 'id-mod-attribute-cert', 358 | '1.3.6.1.5.5.7.0.13' => 'id-mod-timestamp-protocol', 359 | '1.3.6.1.5.5.7.0.14' => 'id-mod-ocsp', 360 | '1.3.6.1.5.5.7.0.15' => 'id-mod-dvcs', 361 | '1.3.6.1.5.5.7.0.16' => 'id-mod-cmp2000', 362 | '1.3.6.1.5.5.7.1.1' => 'Authority Information Access', 363 | '1.3.6.1.5.5.7.1.2' => 'Biometric Info', 364 | '1.3.6.1.5.5.7.1.3' => 'qcStatements', 365 | '1.3.6.1.5.5.7.1.4' => 'ac-auditEntity', 366 | '1.3.6.1.5.5.7.1.5' => 'ac-targeting', 367 | '1.3.6.1.5.5.7.1.6' => 'aaControls', 368 | '1.3.6.1.5.5.7.1.7' => 'sbgp-ipAddrBlock', 369 | '1.3.6.1.5.5.7.1.8' => 'sbgp-autonomousSysNum', 370 | '1.3.6.1.5.5.7.1.9' => 'sbgp-routerIdentifier', 371 | '1.3.6.1.5.5.7.1.10' => 'ac-proxying', 372 | '1.3.6.1.5.5.7.1.11' => 'Subject Information Access', 373 | '1.3.6.1.5.5.7.1.14' => 'Proxy Certificate Information', 374 | '1.3.6.1.5.5.7.2.1' => 'Policy Qualifier CPS', 375 | '1.3.6.1.5.5.7.2.2' => 'Policy Qualifier User Notice', 376 | '1.3.6.1.5.5.7.2.3' => 'textNotice', 377 | '1.3.6.1.5.5.7.3.1' => 'TLS Web Server Authentication', 378 | '1.3.6.1.5.5.7.3.2' => 'TLS Web Client Authentication', 379 | '1.3.6.1.5.5.7.3.3' => 'Code Signing', 380 | '1.3.6.1.5.5.7.3.4' => 'E-mail Protection', 381 | '1.3.6.1.5.5.7.3.5' => 'IPSec End System', 382 | '1.3.6.1.5.5.7.3.6' => 'IPSec Tunnel', 383 | '1.3.6.1.5.5.7.3.7' => 'IPSec User', 384 | '1.3.6.1.5.5.7.3.8' => 'Time Stamping', 385 | '1.3.6.1.5.5.7.3.9' => 'OCSP Signing', 386 | '1.3.6.1.5.5.7.3.10' => 'dvcs', 387 | '1.3.6.1.5.5.7.4.1' => 'id-it-caProtEncCert', 388 | '1.3.6.1.5.5.7.4.2' => 'id-it-signKeyPairTypes', 389 | '1.3.6.1.5.5.7.4.3' => 'id-it-encKeyPairTypes', 390 | '1.3.6.1.5.5.7.4.4' => 'id-it-preferredSymmAlg', 391 | '1.3.6.1.5.5.7.4.5' => 'id-it-caKeyUpdateInfo', 392 | '1.3.6.1.5.5.7.4.6' => 'id-it-currentCRL', 393 | '1.3.6.1.5.5.7.4.7' => 'id-it-unsupportedOIDs', 394 | '1.3.6.1.5.5.7.4.8' => 'id-it-subscriptionRequest', 395 | '1.3.6.1.5.5.7.4.9' => 'id-it-subscriptionResponse', 396 | '1.3.6.1.5.5.7.4.10' => 'id-it-keyPairParamReq', 397 | '1.3.6.1.5.5.7.4.11' => 'id-it-keyPairParamRep', 398 | '1.3.6.1.5.5.7.4.12' => 'id-it-revPassphrase', 399 | '1.3.6.1.5.5.7.4.13' => 'id-it-implicitConfirm', 400 | '1.3.6.1.5.5.7.4.14' => 'id-it-confirmWaitTime', 401 | '1.3.6.1.5.5.7.4.15' => 'id-it-origPKIMessage', 402 | '1.3.6.1.5.5.7.4.16' => 'id-it-suppLangTags', 403 | '1.3.6.1.5.5.7.5.1' => 'id-regCtrl', 404 | '1.3.6.1.5.5.7.5.2' => 'id-regInfo', 405 | '1.3.6.1.5.5.7.5.1.1' => 'id-regCtrl-regToken', 406 | '1.3.6.1.5.5.7.5.1.2' => 'id-regCtrl-authenticator', 407 | '1.3.6.1.5.5.7.5.1.3' => 'id-regCtrl-pkiPublicationInfo', 408 | '1.3.6.1.5.5.7.5.1.4' => 'id-regCtrl-pkiArchiveOptions', 409 | '1.3.6.1.5.5.7.5.1.5' => 'id-regCtrl-oldCertID', 410 | '1.3.6.1.5.5.7.5.1.6' => 'id-regCtrl-protocolEncrKey', 411 | '1.3.6.1.5.5.7.5.2.1' => 'id-regInfo-utf8Pairs', 412 | '1.3.6.1.5.5.7.5.2.2' => 'id-regInfo-certReq', 413 | '1.3.6.1.5.5.7.6.1' => 'id-alg-des40', 414 | '1.3.6.1.5.5.7.6.2' => 'id-alg-noSignature', 415 | '1.3.6.1.5.5.7.6.3' => 'id-alg-dh-sig-hmac-sha1', 416 | '1.3.6.1.5.5.7.6.4' => 'id-alg-dh-pop', 417 | '1.3.6.1.5.5.7.7.1' => 'id-cmc-statusInfo', 418 | '1.3.6.1.5.5.7.7.2' => 'id-cmc-identification', 419 | '1.3.6.1.5.5.7.7.3' => 'id-cmc-identityProof', 420 | '1.3.6.1.5.5.7.7.4' => 'id-cmc-dataReturn', 421 | '1.3.6.1.5.5.7.7.5' => 'id-cmc-transactionId', 422 | '1.3.6.1.5.5.7.7.6' => 'id-cmc-senderNonce', 423 | '1.3.6.1.5.5.7.7.7' => 'id-cmc-recipientNonce', 424 | '1.3.6.1.5.5.7.7.8' => 'id-cmc-addExtensions', 425 | '1.3.6.1.5.5.7.7.9' => 'id-cmc-encryptedPOP', 426 | '1.3.6.1.5.5.7.7.10' => 'id-cmc-decryptedPOP', 427 | '1.3.6.1.5.5.7.7.11' => 'id-cmc-lraPOPWitness', 428 | '1.3.6.1.5.5.7.7.15' => 'id-cmc-getCert', 429 | '1.3.6.1.5.5.7.7.16' => 'id-cmc-getCRL', 430 | '1.3.6.1.5.5.7.7.17' => 'id-cmc-revokeRequest', 431 | '1.3.6.1.5.5.7.7.18' => 'id-cmc-regInfo', 432 | '1.3.6.1.5.5.7.7.19' => 'id-cmc-responseInfo', 433 | '1.3.6.1.5.5.7.7.21' => 'id-cmc-queryPending', 434 | '1.3.6.1.5.5.7.7.22' => 'id-cmc-popLinkRandom', 435 | '1.3.6.1.5.5.7.7.23' => 'id-cmc-popLinkWitness', 436 | '1.3.6.1.5.5.7.7.24' => 'id-cmc-confirmCertAcceptance', 437 | '1.3.6.1.5.5.7.8.1' => 'id-on-personalData', 438 | '1.3.6.1.5.5.7.8.3' => 'Permanent Identifier', 439 | '1.3.6.1.5.5.7.9.1' => 'id-pda-dateOfBirth', 440 | '1.3.6.1.5.5.7.9.2' => 'id-pda-placeOfBirth', 441 | '1.3.6.1.5.5.7.9.3' => 'id-pda-gender', 442 | '1.3.6.1.5.5.7.9.4' => 'id-pda-countryOfCitizenship', 443 | '1.3.6.1.5.5.7.9.5' => 'id-pda-countryOfResidence', 444 | '1.3.6.1.5.5.7.10.1' => 'id-aca-authenticationInfo', 445 | '1.3.6.1.5.5.7.10.2' => 'id-aca-accessIdentity', 446 | '1.3.6.1.5.5.7.10.3' => 'id-aca-chargingIdentity', 447 | '1.3.6.1.5.5.7.10.4' => 'id-aca-group', 448 | '1.3.6.1.5.5.7.10.5' => 'id-aca-role', 449 | '1.3.6.1.5.5.7.10.6' => 'id-aca-encAttrs', 450 | '1.3.6.1.5.5.7.11.1' => 'id-qcs-pkixQCSyntax-v1', 451 | '1.3.6.1.5.5.7.12.1' => 'id-cct-crs', 452 | '1.3.6.1.5.5.7.12.2' => 'id-cct-PKIData', 453 | '1.3.6.1.5.5.7.12.3' => 'id-cct-PKIResponse', 454 | '1.3.6.1.5.5.7.21.0' => 'Any language', 455 | '1.3.6.1.5.5.7.21.1' => 'Inherit all', 456 | '1.3.6.1.5.5.7.21.2' => 'Independent', 457 | '1.3.6.1.5.5.7.48.1' => 'OCSP', 458 | '1.3.6.1.5.5.7.48.2' => 'CA Issuers', 459 | '1.3.6.1.5.5.7.48.3' => 'AD Time Stamping', 460 | '1.3.6.1.5.5.7.48.4' => 'ad dvcs', 461 | '1.3.6.1.5.5.7.48.5' => 'CA Repository', 462 | '1.3.6.1.5.5.7.48.1.1' => 'Basic OCSP Response', 463 | '1.3.6.1.5.5.7.48.1.2' => 'OCSP Nonce', 464 | '1.3.6.1.5.5.7.48.1.3' => 'OCSP CRL ID', 465 | '1.3.6.1.5.5.7.48.1.4' => 'Acceptable OCSP Responses', 466 | '1.3.6.1.5.5.7.48.1.5' => 'OCSP No Check', 467 | '1.3.6.1.5.5.7.48.1.6' => 'OCSP Archive Cutoff', 468 | '1.3.6.1.5.5.7.48.1.7' => 'OCSP Service Locator', 469 | '1.3.6.1.5.5.7.48.1.8' => 'Extended OCSP Status', 470 | '1.3.6.1.5.5.7.48.1.9' => 'id-pkix-OCSP_valid', 471 | '1.3.6.1.5.5.7.48.1.10' => 'id-pkix-OCSP_path', 472 | '1.3.6.1.5.5.7.48.1.11' => 'Trust Root', 473 | '1.3.14.3.2' => 'algorithm', 474 | '1.3.14.3.2.3' => 'md5WithRSA', 475 | '1.3.14.3.2.6' => 'des-ecb', 476 | '1.3.14.3.2.7' => 'des-cbc', 477 | '1.3.14.3.2.8' => 'des-ofb', 478 | '1.3.14.3.2.9' => 'des-cfb', 479 | '1.3.14.3.2.11' => 'rsaSignature', 480 | '1.3.14.3.2.12' => 'dsaEncryption-old', 481 | '1.3.14.3.2.13' => 'dsaWithSHA', 482 | '1.3.14.3.2.15' => 'shaWithRSAEncryption', 483 | '1.3.14.3.2.17' => 'des-ede', 484 | '1.3.14.3.2.18' => 'sha', 485 | '1.3.14.3.2.26' => 'sha1', 486 | '1.3.14.3.2.27' => 'dsaWithSHA1-old', 487 | '1.3.14.3.2.29' => 'sha1WithRSA', 488 | '1.3.36.3.2.1' => 'ripemd160', 489 | '1.3.36.3.3.1.2' => 'ripemd160WithRSA', 490 | '1.3.101.1.4.1' => 'Strong Extranet ID', 491 | '2.5' => 'directory services (X.500)', 492 | '2.5.4' => 'X509', 493 | '2.5.4.3' => 'commonName', 494 | '2.5.4.4' => 'surname', 495 | '2.5.4.5' => 'serialNumber', 496 | '2.5.4.6' => 'countryName', 497 | '2.5.4.7' => 'localityName', 498 | '2.5.4.8' => 'stateOrProvinceName', 499 | '2.5.4.9' => 'streetAddress', 500 | '2.5.4.10' => 'organizationName', 501 | '2.5.4.11' => 'organizationalUnitName', 502 | '2.5.4.12' => 'title', 503 | '2.5.4.13' => 'description', 504 | '2.5.4.14' => 'searchGuide', 505 | '2.5.4.15' => 'businessCategory', 506 | '2.5.4.16' => 'postalAddress', 507 | '2.5.4.17' => 'postalCode', 508 | '2.5.4.18' => 'postOfficeBox', 509 | '2.5.4.19' => 'physicalDeliveryOfficeName', 510 | '2.5.4.20' => 'telephoneNumber', 511 | '2.5.4.21' => 'telexNumber', 512 | '2.5.4.22' => 'teletexTerminalIdentifier', 513 | '2.5.4.23' => 'facsimileTelephoneNumber', 514 | '2.5.4.24' => 'x121Address', 515 | '2.5.4.25' => 'internationaliSDNNumber', 516 | '2.5.4.26' => 'registeredAddress', 517 | '2.5.4.27' => 'destinationIndicator', 518 | '2.5.4.28' => 'preferredDeliveryMethod', 519 | '2.5.4.29' => 'presentationAddress', 520 | '2.5.4.30' => 'supportedApplicationContext', 521 | '2.5.4.31' => 'member', 522 | '2.5.4.32' => 'owner', 523 | '2.5.4.33' => 'roleOccupant', 524 | '2.5.4.34' => 'seeAlso', 525 | '2.5.4.35' => 'userPassword', 526 | '2.5.4.36' => 'userCertificate', 527 | '2.5.4.37' => 'cACertificate', 528 | '2.5.4.38' => 'authorityRevocationList', 529 | '2.5.4.39' => 'certificateRevocationList', 530 | '2.5.4.40' => 'crossCertificatePair', 531 | '2.5.4.41' => 'name', 532 | '2.5.4.42' => 'givenName', 533 | '2.5.4.43' => 'initials', 534 | '2.5.4.44' => 'generationQualifier', 535 | '2.5.4.45' => 'x500UniqueIdentifier', 536 | '2.5.4.46' => 'dnQualifier', 537 | '2.5.4.47' => 'enhancedSearchGuide', 538 | '2.5.4.48' => 'protocolInformation', 539 | '2.5.4.49' => 'distinguishedName', 540 | '2.5.4.50' => 'uniqueMember', 541 | '2.5.4.51' => 'houseIdentifier', 542 | '2.5.4.52' => 'supportedAlgorithms', 543 | '2.5.4.53' => 'deltaRevocationList', 544 | '2.5.4.54' => 'dmdName', 545 | '2.5.4.65' => 'pseudonym', 546 | '2.5.4.72' => 'role', 547 | '2.5.8' => 'directory services - algorithms', 548 | '2.5.8.1.1' => 'rsa', 549 | '2.5.8.3.100' => 'mdc2WithRSA', 550 | '2.5.8.3.101' => 'mdc2', 551 | '2.5.29' => 'id-ce', 552 | '2.5.29.9' => 'X509v3 Subject Directory Attributes', 553 | '2.5.29.14' => 'X509v3 Subject Key Identifier', 554 | '2.5.29.15' => 'X509v3 Key Usage', 555 | '2.5.29.16' => 'X509v3 Private Key Usage Period', 556 | '2.5.29.17' => 'X509v3 Subject Alternative Name', 557 | '2.5.29.18' => 'X509v3 Issuer Alternative Name', 558 | '2.5.29.19' => 'X509v3 Basic Constraints', 559 | '2.5.29.20' => 'X509v3 CRL Number', 560 | '2.5.29.21' => 'X509v3 CRL Reason Code', 561 | '2.5.29.24' => 'Invalidity Date', 562 | '2.5.29.27' => 'X509v3 Delta CRL Indicator', 563 | '2.5.29.28' => 'X509v3 Issuing Distribution Point', 564 | '2.5.29.29' => 'X509v3 Certificate Issuer', 565 | '2.5.29.30' => 'X509v3 Name Constraints', 566 | '2.5.29.31' => 'X509v3 CRL Distribution Points', 567 | '2.5.29.32' => 'X509v3 Certificate Policies', 568 | '2.5.29.32.0' => 'X509v3 Any Policy', 569 | '2.5.29.33' => 'X509v3 Policy Mappings', 570 | '2.5.29.35' => 'X509v3 Authority Key Identifier', 571 | '2.5.29.36' => 'X509v3 Policy Constraints', 572 | '2.5.29.37' => 'X509v3 Extended Key Usage', 573 | '2.5.29.46' => 'X509v3 Freshest CRL', 574 | '2.5.29.54' => 'X509v3 Inhibit Any Policy', 575 | '2.5.29.55' => 'X509v3 AC Targeting', 576 | '2.5.29.56' => 'X509v3 No Revocation Available', 577 | '2.5.29.37.0' => 'Any Extended Key Usage', 578 | '2.16.840.1.113730' => 'Netscape Communications Corp.', 579 | '2.16.840.1.113730.1' => 'Netscape Certificate Extension', 580 | '2.16.840.1.113730.2' => 'Netscape Data Type', 581 | '2.16.840.1.113730.1.1' => 'Netscape Cert Type', 582 | '2.16.840.1.113730.1.2' => 'Netscape Base Url', 583 | '2.16.840.1.113730.1.3' => 'Netscape Revocation Url', 584 | '2.16.840.1.113730.1.4' => 'Netscape CA Revocation Url', 585 | '2.16.840.1.113730.1.7' => 'Netscape Renewal Url', 586 | '2.16.840.1.113730.1.8' => 'Netscape CA Policy Url', 587 | '2.16.840.1.113730.1.12' => 'Netscape SSL Server Name', 588 | '2.16.840.1.113730.1.13' => 'Netscape Comment', 589 | '2.16.840.1.113730.2.5' => 'Netscape Certificate Sequence', 590 | '2.16.840.1.113730.4.1' => 'Netscape Server Gated Crypto', 591 | '1.3.6' => 'dod', 592 | '1.3.6.1' => 'iana', 593 | '1.3.6.1.1' => 'Directory', 594 | '1.3.6.1.2' => 'Management', 595 | '1.3.6.1.3' => 'Experimental', 596 | '1.3.6.1.4' => 'Private', 597 | '1.3.6.1.5' => 'Security', 598 | '1.3.6.1.6' => 'SNMPv2', 599 | '1.3.6.1.7' => 'Mail', 600 | '1.3.6.1.4.1' => 'Enterprises', 601 | '1.3.6.1.4.1.1466.344' => 'dcObject', 602 | '1.2.840.113549.1.9.16.3.8' => 'zlib compression', 603 | '2.16.840.1.101.3' => 'csor', 604 | '2.16.840.1.101.3.4' => 'nistAlgorithms', 605 | '2.16.840.1.101.3.4.1' => 'aes', 606 | '2.16.840.1.101.3.4.1.1' => 'aes-128-ecb', 607 | '2.16.840.1.101.3.4.1.2' => 'aes-128-cbc', 608 | '2.16.840.1.101.3.4.1.3' => 'aes-128-ofb', 609 | '2.16.840.1.101.3.4.1.4' => 'aes-128-cfb', 610 | '2.16.840.1.101.3.4.1.5' => 'id-aes128-wrap', 611 | '2.16.840.1.101.3.4.1.6' => 'aes-128-gcm', 612 | '2.16.840.1.101.3.4.1.7' => 'aes-128-ccm', 613 | '2.16.840.1.101.3.4.1.8' => 'id-aes128-wrap-pad', 614 | '2.16.840.1.101.3.4.1.21' => 'aes-192-ecb', 615 | '2.16.840.1.101.3.4.1.22' => 'aes-192-cbc', 616 | '2.16.840.1.101.3.4.1.23' => 'aes-192-ofb', 617 | '2.16.840.1.101.3.4.1.24' => 'aes-192-cfb', 618 | '2.16.840.1.101.3.4.1.25' => 'id-aes192-wrap', 619 | '2.16.840.1.101.3.4.1.26' => 'aes-192-gcm', 620 | '2.16.840.1.101.3.4.1.27' => 'aes-192-ccm', 621 | '2.16.840.1.101.3.4.1.28' => 'id-aes192-wrap-pad', 622 | '2.16.840.1.101.3.4.1.41' => 'aes-256-ecb', 623 | '2.16.840.1.101.3.4.1.42' => 'aes-256-cbc', 624 | '2.16.840.1.101.3.4.1.43' => 'aes-256-ofb', 625 | '2.16.840.1.101.3.4.1.44' => 'aes-256-cfb', 626 | '2.16.840.1.101.3.4.1.45' => 'id-aes256-wrap', 627 | '2.16.840.1.101.3.4.1.46' => 'aes-256-gcm', 628 | '2.16.840.1.101.3.4.1.47' => 'aes-256-ccm', 629 | '2.16.840.1.101.3.4.1.48' => 'id-aes256-wrap-pad', 630 | '2.16.840.1.101.3.4.2' => 'nist_hashalgs', 631 | '2.16.840.1.101.3.4.2.1' => 'sha256', 632 | '2.16.840.1.101.3.4.2.2' => 'sha384', 633 | '2.16.840.1.101.3.4.2.3' => 'sha512', 634 | '2.16.840.1.101.3.4.2.4' => 'sha224', 635 | '2.16.840.1.101.3.4.3' => 'dsa_with_sha2', 636 | '2.16.840.1.101.3.4.3.1' => 'dsa_with_SHA224', 637 | '2.16.840.1.101.3.4.3.2' => 'dsa_with_SHA256', 638 | '2.5.29.23' => 'Hold Instruction Code', 639 | '0.9' => 'data', 640 | '0.9.2342' => 'pss', 641 | '0.9.2342.19200300' => 'ucl', 642 | '0.9.2342.19200300.100' => 'pilot', 643 | '0.9.2342.19200300.100.1' => 'pilotAttributeType', 644 | '0.9.2342.19200300.100.3' => 'pilotAttributeSyntax', 645 | '0.9.2342.19200300.100.4' => 'pilotObjectClass', 646 | '0.9.2342.19200300.100.10' => 'pilotGroups', 647 | '2.23.42' => 'Secure Electronic Transactions', 648 | '2.23.42.0' => 'content types', 649 | '2.23.42.1' => 'message extensions', 650 | '2.23.42.3' => 'set-attr', 651 | '2.23.42.5' => 'set-policy', 652 | '2.23.42.7' => 'certificate extensions', 653 | '2.23.42.8' => 'set-brand', 654 | '2.23.42.0.0' => 'setct-PANData', 655 | '2.23.42.0.1' => 'setct-PANToken', 656 | '2.23.42.0.2' => 'setct-PANOnly', 657 | '2.23.42.0.3' => 'setct-OIData', 658 | '2.23.42.0.4' => 'setct-PI', 659 | '2.23.42.0.5' => 'setct-PIData', 660 | '2.23.42.0.6' => 'setct-PIDataUnsigned', 661 | '2.23.42.0.7' => 'setct-HODInput', 662 | '2.23.42.0.8' => 'setct-AuthResBaggage', 663 | '2.23.42.0.9' => 'setct-AuthRevReqBaggage', 664 | '2.23.42.0.10' => 'setct-AuthRevResBaggage', 665 | '2.23.42.0.11' => 'setct-CapTokenSeq', 666 | '2.23.42.0.12' => 'setct-PInitResData', 667 | '2.23.42.0.13' => 'setct-PI-TBS', 668 | '2.23.42.0.14' => 'setct-PResData', 669 | '2.23.42.0.16' => 'setct-AuthReqTBS', 670 | '2.23.42.0.17' => 'setct-AuthResTBS', 671 | '2.23.42.0.18' => 'setct-AuthResTBSX', 672 | '2.23.42.0.19' => 'setct-AuthTokenTBS', 673 | '2.23.42.0.20' => 'setct-CapTokenData', 674 | '2.23.42.0.21' => 'setct-CapTokenTBS', 675 | '2.23.42.0.22' => 'setct-AcqCardCodeMsg', 676 | '2.23.42.0.23' => 'setct-AuthRevReqTBS', 677 | '2.23.42.0.24' => 'setct-AuthRevResData', 678 | '2.23.42.0.25' => 'setct-AuthRevResTBS', 679 | '2.23.42.0.26' => 'setct-CapReqTBS', 680 | '2.23.42.0.27' => 'setct-CapReqTBSX', 681 | '2.23.42.0.28' => 'setct-CapResData', 682 | '2.23.42.0.29' => 'setct-CapRevReqTBS', 683 | '2.23.42.0.30' => 'setct-CapRevReqTBSX', 684 | '2.23.42.0.31' => 'setct-CapRevResData', 685 | '2.23.42.0.32' => 'setct-CredReqTBS', 686 | '2.23.42.0.33' => 'setct-CredReqTBSX', 687 | '2.23.42.0.34' => 'setct-CredResData', 688 | '2.23.42.0.35' => 'setct-CredRevReqTBS', 689 | '2.23.42.0.36' => 'setct-CredRevReqTBSX', 690 | '2.23.42.0.37' => 'setct-CredRevResData', 691 | '2.23.42.0.38' => 'setct-PCertReqData', 692 | '2.23.42.0.39' => 'setct-PCertResTBS', 693 | '2.23.42.0.40' => 'setct-BatchAdminReqData', 694 | '2.23.42.0.41' => 'setct-BatchAdminResData', 695 | '2.23.42.0.42' => 'setct-CardCInitResTBS', 696 | '2.23.42.0.43' => 'setct-MeAqCInitResTBS', 697 | '2.23.42.0.44' => 'setct-RegFormResTBS', 698 | '2.23.42.0.45' => 'setct-CertReqData', 699 | '2.23.42.0.46' => 'setct-CertReqTBS', 700 | '2.23.42.0.47' => 'setct-CertResData', 701 | '2.23.42.0.48' => 'setct-CertInqReqTBS', 702 | '2.23.42.0.49' => 'setct-ErrorTBS', 703 | '2.23.42.0.50' => 'setct-PIDualSignedTBE', 704 | '2.23.42.0.51' => 'setct-PIUnsignedTBE', 705 | '2.23.42.0.52' => 'setct-AuthReqTBE', 706 | '2.23.42.0.53' => 'setct-AuthResTBE', 707 | '2.23.42.0.54' => 'setct-AuthResTBEX', 708 | '2.23.42.0.55' => 'setct-AuthTokenTBE', 709 | '2.23.42.0.56' => 'setct-CapTokenTBE', 710 | '2.23.42.0.57' => 'setct-CapTokenTBEX', 711 | '2.23.42.0.58' => 'setct-AcqCardCodeMsgTBE', 712 | '2.23.42.0.59' => 'setct-AuthRevReqTBE', 713 | '2.23.42.0.60' => 'setct-AuthRevResTBE', 714 | '2.23.42.0.61' => 'setct-AuthRevResTBEB', 715 | '2.23.42.0.62' => 'setct-CapReqTBE', 716 | '2.23.42.0.63' => 'setct-CapReqTBEX', 717 | '2.23.42.0.64' => 'setct-CapResTBE', 718 | '2.23.42.0.65' => 'setct-CapRevReqTBE', 719 | '2.23.42.0.66' => 'setct-CapRevReqTBEX', 720 | '2.23.42.0.67' => 'setct-CapRevResTBE', 721 | '2.23.42.0.68' => 'setct-CredReqTBE', 722 | '2.23.42.0.69' => 'setct-CredReqTBEX', 723 | '2.23.42.0.70' => 'setct-CredResTBE', 724 | '2.23.42.0.71' => 'setct-CredRevReqTBE', 725 | '2.23.42.0.72' => 'setct-CredRevReqTBEX', 726 | '2.23.42.0.73' => 'setct-CredRevResTBE', 727 | '2.23.42.0.74' => 'setct-BatchAdminReqTBE', 728 | '2.23.42.0.75' => 'setct-BatchAdminResTBE', 729 | '2.23.42.0.76' => 'setct-RegFormReqTBE', 730 | '2.23.42.0.77' => 'setct-CertReqTBE', 731 | '2.23.42.0.78' => 'setct-CertReqTBEX', 732 | '2.23.42.0.79' => 'setct-CertResTBE', 733 | '2.23.42.0.80' => 'setct-CRLNotificationTBS', 734 | '2.23.42.0.81' => 'setct-CRLNotificationResTBS', 735 | '2.23.42.0.82' => 'setct-BCIDistributionTBS', 736 | '2.23.42.1.1' => 'generic cryptogram', 737 | '2.23.42.1.3' => 'merchant initiated auth', 738 | '2.23.42.1.4' => 'setext-pinSecure', 739 | '2.23.42.1.5' => 'setext-pinAny', 740 | '2.23.42.1.7' => 'setext-track2', 741 | '2.23.42.1.8' => 'additional verification', 742 | '2.23.42.5.0' => 'set-policy-root', 743 | '2.23.42.7.0' => 'setCext-hashedRoot', 744 | '2.23.42.7.1' => 'setCext-certType', 745 | '2.23.42.7.2' => 'setCext-merchData', 746 | '2.23.42.7.3' => 'setCext-cCertRequired', 747 | '2.23.42.7.4' => 'setCext-tunneling', 748 | '2.23.42.7.5' => 'setCext-setExt', 749 | '2.23.42.7.6' => 'setCext-setQualf', 750 | '2.23.42.7.7' => 'setCext-PGWYcapabilities', 751 | '2.23.42.7.8' => 'setCext-TokenIdentifier', 752 | '2.23.42.7.9' => 'setCext-Track2Data', 753 | '2.23.42.7.10' => 'setCext-TokenType', 754 | '2.23.42.7.11' => 'setCext-IssuerCapabilities', 755 | '2.23.42.3.0' => 'setAttr-Cert', 756 | '2.23.42.3.1' => 'payment gateway capabilities', 757 | '2.23.42.3.2' => 'setAttr-TokenType', 758 | '2.23.42.3.3' => 'issuer capabilities', 759 | '2.23.42.3.0.0' => 'set-rootKeyThumb', 760 | '2.23.42.3.0.1' => 'set-addPolicy', 761 | '2.23.42.3.2.1' => 'setAttr-Token-EMV', 762 | '2.23.42.3.2.2' => 'setAttr-Token-B0Prime', 763 | '2.23.42.3.3.3' => 'setAttr-IssCap-CVM', 764 | '2.23.42.3.3.4' => 'setAttr-IssCap-T2', 765 | '2.23.42.3.3.5' => 'setAttr-IssCap-Sig', 766 | '2.23.42.3.3.3.1' => 'generate cryptogram', 767 | '2.23.42.3.3.4.1' => 'encrypted track 2', 768 | '2.23.42.3.3.4.2' => 'cleartext track 2', 769 | '2.23.42.3.3.5.1' => 'ICC or token signature', 770 | '2.23.42.3.3.5.2' => 'secure device signature', 771 | '2.23.42.8.1' => 'set-brand-IATA-ATA', 772 | '2.23.42.8.30' => 'set-brand-Diners', 773 | '2.23.42.8.34' => 'set-brand-AmericanExpress', 774 | '2.23.42.8.35' => 'set-brand-JCB', 775 | '2.23.42.8.4' => 'set-brand-Visa', 776 | '2.23.42.8.5' => 'set-brand-MasterCard', 777 | '2.23.42.8.6011' => 'set-brand-Novus', 778 | '1.2.840.113549.3.10' => 'des-cdmf', 779 | '1.2.840.113549.1.1.6' => 'rsaOAEPEncryptionSET', 780 | '1.0.10118.3.0.55' => 'whirlpool', 781 | '1.2.643.2.2' => 'cryptopro', 782 | '1.2.643.2.9' => 'cryptocom', 783 | '1.2.643.2.2.3' => 'GOST R 34.11-94 with GOST R 34.10-2001', 784 | '1.2.643.2.2.4' => 'GOST R 34.11-94 with GOST R 34.10-94', 785 | '1.2.643.2.2.9' => 'GOST R 34.11-94', 786 | '1.2.643.2.2.10' => 'HMAC GOST 34.11-94', 787 | '1.2.643.2.2.19' => 'GOST R 34.10-2001', 788 | '1.2.643.2.2.20' => 'GOST R 34.10-94', 789 | '1.2.643.2.2.21' => 'GOST 28147-89', 790 | '1.2.643.2.2.22' => 'GOST 28147-89 MAC', 791 | '1.2.643.2.2.23' => 'GOST R 34.11-94 PRF', 792 | '1.2.643.2.2.98' => 'GOST R 34.10-2001 DH', 793 | '1.2.643.2.2.99' => 'GOST R 34.10-94 DH', 794 | '1.2.643.2.2.14.1' => 'id-Gost28147-89-CryptoPro-KeyMeshing', 795 | '1.2.643.2.2.14.0' => 'id-Gost28147-89-None-KeyMeshing', 796 | '1.2.643.2.2.30.0' => 'id-GostR3411-94-TestParamSet', 797 | '1.2.643.2.2.30.1' => 'id-GostR3411-94-CryptoProParamSet', 798 | '1.2.643.2.2.31.0' => 'id-Gost28147-89-TestParamSet', 799 | '1.2.643.2.2.31.1' => 'id-Gost28147-89-CryptoPro-A-ParamSet', 800 | '1.2.643.2.2.31.2' => 'id-Gost28147-89-CryptoPro-B-ParamSet', 801 | '1.2.643.2.2.31.3' => 'id-Gost28147-89-CryptoPro-C-ParamSet', 802 | '1.2.643.2.2.31.4' => 'id-Gost28147-89-CryptoPro-D-ParamSet', 803 | '1.2.643.2.2.31.5' => 'id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet', 804 | '1.2.643.2.2.31.6' => 'id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet', 805 | '1.2.643.2.2.31.7' => 'id-Gost28147-89-CryptoPro-RIC-1-ParamSet', 806 | '1.2.643.2.2.32.0' => 'id-GostR3410-94-TestParamSet', 807 | '1.2.643.2.2.32.2' => 'id-GostR3410-94-CryptoPro-A-ParamSet', 808 | '1.2.643.2.2.32.3' => 'id-GostR3410-94-CryptoPro-B-ParamSet', 809 | '1.2.643.2.2.32.4' => 'id-GostR3410-94-CryptoPro-C-ParamSet', 810 | '1.2.643.2.2.32.5' => 'id-GostR3410-94-CryptoPro-D-ParamSet', 811 | '1.2.643.2.2.33.1' => 'id-GostR3410-94-CryptoPro-XchA-ParamSet', 812 | '1.2.643.2.2.33.2' => 'id-GostR3410-94-CryptoPro-XchB-ParamSet', 813 | '1.2.643.2.2.33.3' => 'id-GostR3410-94-CryptoPro-XchC-ParamSet', 814 | '1.2.643.2.2.35.0' => 'id-GostR3410-2001-TestParamSet', 815 | '1.2.643.2.2.35.1' => 'id-GostR3410-2001-CryptoPro-A-ParamSet', 816 | '1.2.643.2.2.35.2' => 'id-GostR3410-2001-CryptoPro-B-ParamSet', 817 | '1.2.643.2.2.35.3' => 'id-GostR3410-2001-CryptoPro-C-ParamSet', 818 | '1.2.643.2.2.36.0' => 'id-GostR3410-2001-CryptoPro-XchA-ParamSet', 819 | '1.2.643.2.2.36.1' => 'id-GostR3410-2001-CryptoPro-XchB-ParamSet', 820 | '1.2.643.2.2.20.1' => 'id-GostR3410-94-a', 821 | '1.2.643.2.2.20.2' => 'id-GostR3410-94-aBis', 822 | '1.2.643.2.2.20.3' => 'id-GostR3410-94-b', 823 | '1.2.643.2.2.20.4' => 'id-GostR3410-94-bBis', 824 | '1.2.643.2.9.1.6.1' => 'GOST 28147-89 Cryptocom ParamSet', 825 | '1.2.643.2.9.1.5.3' => 'GOST 34.10-94 Cryptocom', 826 | '1.2.643.2.9.1.5.4' => 'GOST 34.10-2001 Cryptocom', 827 | '1.2.643.2.9.1.3.3' => 'GOST R 34.11-94 with GOST R 34.10-94 Cryptocom', 828 | '1.2.643.2.9.1.3.4' => 'GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom', 829 | '1.2.643.2.9.1.8.1' => 'GOST R 3410-2001 Parameter Set Cryptocom', 830 | '1.2.392.200011.61.1.1.1.2' => 'camellia-128-cbc', 831 | '1.2.392.200011.61.1.1.1.3' => 'camellia-192-cbc', 832 | '1.2.392.200011.61.1.1.1.4' => 'camellia-256-cbc', 833 | '1.2.392.200011.61.1.1.3.2' => 'id-camellia128-wrap', 834 | '1.2.392.200011.61.1.1.3.3' => 'id-camellia192-wrap', 835 | '1.2.392.200011.61.1.1.3.4' => 'id-camellia256-wrap', 836 | '0.3.4401.5' => 'ntt-ds', 837 | '0.3.4401.5.3.1.9' => 'camellia', 838 | '0.3.4401.5.3.1.9.1' => 'camellia-128-ecb', 839 | '0.3.4401.5.3.1.9.3' => 'camellia-128-ofb', 840 | '0.3.4401.5.3.1.9.4' => 'camellia-128-cfb', 841 | '0.3.4401.5.3.1.9.6' => 'camellia-128-gcm', 842 | '0.3.4401.5.3.1.9.7' => 'camellia-128-ccm', 843 | '0.3.4401.5.3.1.9.9' => 'camellia-128-ctr', 844 | '0.3.4401.5.3.1.9.10' => 'camellia-128-cmac', 845 | '0.3.4401.5.3.1.9.21' => 'camellia-192-ecb', 846 | '0.3.4401.5.3.1.9.23' => 'camellia-192-ofb', 847 | '0.3.4401.5.3.1.9.24' => 'camellia-192-cfb', 848 | '0.3.4401.5.3.1.9.26' => 'camellia-192-gcm', 849 | '0.3.4401.5.3.1.9.27' => 'camellia-192-ccm', 850 | '0.3.4401.5.3.1.9.29' => 'camellia-192-ctr', 851 | '0.3.4401.5.3.1.9.30' => 'camellia-192-cmac', 852 | '0.3.4401.5.3.1.9.41' => 'camellia-256-ecb', 853 | '0.3.4401.5.3.1.9.43' => 'camellia-256-ofb', 854 | '0.3.4401.5.3.1.9.44' => 'camellia-256-cfb', 855 | '0.3.4401.5.3.1.9.46' => 'camellia-256-gcm', 856 | '0.3.4401.5.3.1.9.47' => 'camellia-256-ccm', 857 | '0.3.4401.5.3.1.9.49' => 'camellia-256-ctr', 858 | '0.3.4401.5.3.1.9.50' => 'camellia-256-cmac', 859 | '1.2.410.200004' => 'kisa', 860 | '1.2.410.200004.1.3' => 'seed-ecb', 861 | '1.2.410.200004.1.4' => 'seed-cbc', 862 | '1.2.410.200004.1.5' => 'seed-cfb', 863 | '1.2.410.200004.1.6' => 'seed-ofb', 864 | '1.2.840.10046.2.1' => 'X9.42 DH', 865 | '1.3.36.3.3.2.8.1.1.1' => 'brainpoolP160r1', 866 | '1.3.36.3.3.2.8.1.1.2' => 'brainpoolP160t1', 867 | '1.3.36.3.3.2.8.1.1.3' => 'brainpoolP192r1', 868 | '1.3.36.3.3.2.8.1.1.4' => 'brainpoolP192t1', 869 | '1.3.36.3.3.2.8.1.1.5' => 'brainpoolP224r1', 870 | '1.3.36.3.3.2.8.1.1.6' => 'brainpoolP224t1', 871 | '1.3.36.3.3.2.8.1.1.7' => 'brainpoolP256r1', 872 | '1.3.36.3.3.2.8.1.1.8' => 'brainpoolP256t1', 873 | '1.3.36.3.3.2.8.1.1.9' => 'brainpoolP320r1', 874 | '1.3.36.3.3.2.8.1.1.10' => 'brainpoolP320t1', 875 | '1.3.36.3.3.2.8.1.1.11' => 'brainpoolP384r1', 876 | '1.3.36.3.3.2.8.1.1.12' => 'brainpoolP384t1', 877 | '1.3.36.3.3.2.8.1.1.13' => 'brainpoolP512r1', 878 | '1.3.36.3.3.2.8.1.1.14' => 'brainpoolP512t1', 879 | '1.3.133.16.840.63.0' => 'x9-63-scheme', 880 | '1.3.132.1' => 'secg-scheme', 881 | '1.3.133.16.840.63.0.2' => 'dhSinglePass-stdDH-sha1kdf-scheme', 882 | '1.3.132.1.11.0' => 'dhSinglePass-stdDH-sha224kdf-scheme', 883 | '1.3.132.1.11.1' => 'dhSinglePass-stdDH-sha256kdf-scheme', 884 | '1.3.132.1.11.2' => 'dhSinglePass-stdDH-sha384kdf-scheme', 885 | '1.3.132.1.11.3' => 'dhSinglePass-stdDH-sha512kdf-scheme', 886 | '1.3.133.16.840.63.0.3' => 'dhSinglePass-cofactorDH-sha1kdf-scheme', 887 | '1.3.132.1.14.0' => 'dhSinglePass-cofactorDH-sha224kdf-scheme', 888 | '1.3.132.1.14.1' => 'dhSinglePass-cofactorDH-sha256kdf-scheme', 889 | '1.3.132.1.14.2' => 'dhSinglePass-cofactorDH-sha384kdf-scheme', 890 | '1.3.132.1.14.3' => 'dhSinglePass-cofactorDH-sha512kdf-scheme', 891 | '1.3.6.1.4.1.11129.2.4.2' => 'CT Precertificate SCTs', 892 | '1.3.6.1.4.1.11129.2.4.3' => 'CT Precertificate Poison', 893 | '1.3.6.1.4.1.11129.2.4.4' => 'CT Precertificate Signer', 894 | '1.3.6.1.4.1.11129.2.4.5' => 'CT Certificate SCTs', 895 | '1.3.6.1.4.1.311.60.2.1.1' => 'jurisdictionLocalityName', 896 | '1.3.6.1.4.1.311.60.2.1.2' => 'jurisdictionStateOrProvinceName', 897 | '1.3.6.1.4.1.311.60.2.1.3' => 'jurisdictionCountryName', 898 | '1.3.6.1.4.1.11591.4.11' => 'id-scrypt', 899 | ]; 900 | 901 | if (array_key_exists($oidString, $oids)) { 902 | return $oids[$oidString]; 903 | } 904 | 905 | switch ($oidString) { 906 | case self::RSA_ENCRYPTION: 907 | return 'RSA Encryption'; 908 | case self::MD5_WITH_RSA_ENCRYPTION: 909 | return 'MD5 with RSA Encryption'; 910 | case self::SHA1_WITH_RSA_SIGNATURE: 911 | return 'SHA-1 with RSA Signature'; 912 | 913 | case self::PKCS9_EMAIL: 914 | return 'PKCS #9 Email Address'; 915 | case self::PKCS9_UNSTRUCTURED_NAME: 916 | return 'PKCS #9 Unstructured Name'; 917 | case self::PKCS9_CONTENT_TYPE: 918 | return 'PKCS #9 Content Type'; 919 | case self::PKCS9_MESSAGE_DIGEST: 920 | return 'PKCS #9 Message Digest'; 921 | case self::PKCS9_SIGNING_TIME: 922 | return 'PKCS #9 Signing Time'; 923 | 924 | case self::COMMON_NAME: 925 | return 'Common Name'; 926 | case self::SURNAME: 927 | return 'Surname'; 928 | case self::SERIAL_NUMBER: 929 | return 'Serial Number'; 930 | case self::COUNTRY_NAME: 931 | return 'Country Name'; 932 | case self::LOCALITY_NAME: 933 | return 'Locality Name'; 934 | case self::STATE_OR_PROVINCE_NAME: 935 | return 'State or Province Name'; 936 | case self::STREET_ADDRESS: 937 | return 'Street Address'; 938 | case self::ORGANIZATION_NAME: 939 | return 'Organization Name'; 940 | case self::OU_NAME: 941 | return 'Organization Unit Name'; 942 | case self::TITLE: 943 | return 'Title'; 944 | case self::DESCRIPTION: 945 | return 'Description'; 946 | case self::POSTAL_ADDRESS: 947 | return 'Postal Address'; 948 | case self::POSTAL_CODE: 949 | return 'Postal Code'; 950 | case self::AUTHORITY_REVOCATION_LIST: 951 | return 'Authority Revocation List'; 952 | 953 | case self::CERT_EXT_SUBJECT_DIRECTORY_ATTR: 954 | return 'Subject directory attributes'; 955 | case self::CERT_EXT_SUBJECT_KEY_IDENTIFIER: 956 | return 'Subject key identifier'; 957 | case self::CERT_EXT_KEY_USAGE: 958 | return 'Key usage certificate extension'; 959 | case self::CERT_EXT_PRIVATE_KEY_USAGE_PERIOD: 960 | return 'Private key usage'; 961 | case self::CERT_EXT_SUBJECT_ALT_NAME: 962 | return 'Subject alternative name (SAN)'; 963 | case self::CERT_EXT_ISSUER_ALT_NAME: 964 | return 'Issuer alternative name'; 965 | case self::CERT_EXT_BASIC_CONSTRAINTS: 966 | return 'Basic constraints'; 967 | case self::CERT_EXT_CRL_NUMBER: 968 | return 'CRL number'; 969 | case self::CERT_EXT_REASON_CODE: 970 | return 'Reason code'; 971 | case self::CERT_EXT_INVALIDITY_DATE: 972 | return 'Invalidity code'; 973 | case self::CERT_EXT_DELTA_CRL_INDICATOR: 974 | return 'Delta CRL indicator'; 975 | case self::CERT_EXT_ISSUING_DIST_POINT: 976 | return 'Issuing distribution point'; 977 | case self::CERT_EXT_CERT_ISSUER: 978 | return 'Certificate issuer'; 979 | case self::CERT_EXT_NAME_CONSTRAINTS: 980 | return 'Name constraints'; 981 | case self::CERT_EXT_CRL_DISTRIBUTION_POINTS: 982 | return 'CRL distribution points'; 983 | case self::CERT_EXT_CERT_POLICIES: 984 | return 'Certificate policies '; 985 | case self::CERT_EXT_AUTHORITY_KEY_IDENTIFIER: 986 | return 'Authority key identifier'; 987 | case self::CERT_EXT_EXTENDED_KEY_USAGE: 988 | return 'Extended key usage'; 989 | case self::AUTHORITY_INFORMATION_ACCESS: 990 | return 'Certificate Authority Information Access (AIA)'; 991 | 992 | default: 993 | if ($loadFromWeb) { 994 | return self::loadFromWeb($oidString); 995 | } else { 996 | return $oidString; 997 | } 998 | } 999 | } 1000 | 1001 | public static function loadFromWeb($oidString) 1002 | { 1003 | $ch = curl_init("http://oid-info.com/get/{$oidString}"); 1004 | 1005 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 1006 | curl_setopt($ch, CURLOPT_HEADER, 0); 1007 | 1008 | $contents = curl_exec($ch); 1009 | curl_close($ch); 1010 | 1011 | // This pattern needs to be updated as soon as the website layout of oid-info.com changes 1012 | preg_match_all('#(.+)\(\d+\)#si', $contents, $oidName); 1013 | 1014 | if (empty($oidName[1])) { 1015 | return "{$oidString} (unknown)"; 1016 | } 1017 | 1018 | $oidName = ucfirst(strtolower(preg_replace('/([A-Z][a-z])/', ' $1', $oidName[1][0]))); 1019 | $oidName = str_replace('-', ' ', $oidName); 1020 | 1021 | return "{$oidName} ({$oidString})"; 1022 | } 1023 | } 1024 | -------------------------------------------------------------------------------- /lib/ASN1/Parsable.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use FG\ASN1\Exception\ParserException; 14 | 15 | /** 16 | * The Parsable interface describes classes that can be parsed from their binary DER representation. 17 | */ 18 | interface Parsable 19 | { 20 | /** 21 | * Parse an instance of this class from its binary DER encoded representation. 22 | * 23 | * @param string $binaryData 24 | * @param int $offsetIndex the offset at which parsing of the $binaryData is started. This parameter ill be modified 25 | * to contain the offset index of the next object after this object has been parsed 26 | * 27 | * @throws ParserException if the given binary data is either invalid or not currently supported 28 | * 29 | * @return static 30 | */ 31 | public static function fromBinary(&$binaryData, &$offsetIndex = null); 32 | } 33 | -------------------------------------------------------------------------------- /lib/ASN1/TemplateParser.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | use Exception; 14 | use FG\ASN1\Exception\ParserException; 15 | use FG\ASN1\Universal\Sequence; 16 | 17 | class TemplateParser 18 | { 19 | /** 20 | * @param string $data 21 | * @param array $template 22 | * @return \FG\ASN1\ASNObject|Sequence 23 | * @throws ParserException if there was an issue parsing 24 | */ 25 | public function parseBase64($data, array $template) 26 | { 27 | // TODO test with invalid data 28 | return $this->parseBinary(base64_decode($data), $template); 29 | } 30 | 31 | /** 32 | * @param string $binary 33 | * @param array $template 34 | * @return \FG\ASN1\ASNObject|Sequence 35 | * @throws ParserException if there was an issue parsing 36 | */ 37 | public function parseBinary($binary, array $template) 38 | { 39 | $parsedObject = ASNObject::fromBinary($binary); 40 | 41 | foreach ($template as $key => $value) { 42 | $this->validate($parsedObject, $key, $value); 43 | } 44 | 45 | return $parsedObject; 46 | } 47 | 48 | private function validate(ASNObject $object, $key, $value) 49 | { 50 | if (is_array($value)) { 51 | $this->assertTypeId($key, $object); 52 | 53 | /* @var Construct $object */ 54 | foreach ($value as $key => $child) { 55 | $this->validate($object->current(), $key, $child); 56 | $object->next(); 57 | } 58 | } else { 59 | $this->assertTypeId($value, $object); 60 | } 61 | } 62 | 63 | private function assertTypeId($expectedTypeId, ASNObject $object) 64 | { 65 | $actualType = $object->getType(); 66 | if ($expectedTypeId != $actualType) { 67 | throw new Exception("Expected type ($expectedTypeId) does not match actual type ($actualType"); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/BMPString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class BMPString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 BMP String. 20 | * 21 | * BMPString is a subtype of UniversalString that has its own 22 | * unique tag and contains only the characters in the 23 | * Basic Multilingual Plane (those corresponding to the first 24 | * 64K-2 cells, less cells whose encoding is used to address 25 | * characters outside the Basic Multilingual Plane) of ISO/IEC 10646-1. 26 | * 27 | * TODO The encodable characters of this type are not yet checked. 28 | * 29 | * @param string $string 30 | */ 31 | public function __construct($string) 32 | { 33 | $this->value = $string; 34 | $this->allowAll(); 35 | } 36 | 37 | public function getType() 38 | { 39 | return Identifier::BMP_STRING; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/BitString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use Exception; 14 | use FG\ASN1\Exception\ParserException; 15 | use FG\ASN1\Parsable; 16 | use FG\ASN1\Identifier; 17 | 18 | class BitString extends OctetString implements Parsable 19 | { 20 | private $nrOfUnusedBits; 21 | 22 | /** 23 | * Creates a new ASN.1 BitString object. 24 | * 25 | * @param string|int $value Either the hexadecimal value as a string (spaces are allowed - leading 0x is optional) or a numeric value 26 | * @param int $nrOfUnusedBits the number of unused bits in the last octet [optional]. 27 | * 28 | * @throws Exception if the second parameter is no positive numeric value 29 | */ 30 | public function __construct($value, $nrOfUnusedBits = 0) 31 | { 32 | parent::__construct($value); 33 | 34 | if (!is_numeric($nrOfUnusedBits) || $nrOfUnusedBits < 0) { 35 | throw new Exception('BitString: second parameter needs to be a positive number (or zero)!'); 36 | } 37 | 38 | $this->nrOfUnusedBits = $nrOfUnusedBits; 39 | } 40 | 41 | public function getType() 42 | { 43 | return Identifier::BITSTRING; 44 | } 45 | 46 | protected function calculateContentLength() 47 | { 48 | // add one to the length for the first octet which encodes the number of unused bits in the last octet 49 | return parent::calculateContentLength() + 1; 50 | } 51 | 52 | protected function getEncodedValue() 53 | { 54 | // the first octet determines the number of unused bits 55 | $nrOfUnusedBitsOctet = chr($this->nrOfUnusedBits); 56 | $actualContent = parent::getEncodedValue(); 57 | 58 | return $nrOfUnusedBitsOctet.$actualContent; 59 | } 60 | 61 | public function getNumberOfUnusedBits() 62 | { 63 | return $this->nrOfUnusedBits; 64 | } 65 | 66 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 67 | { 68 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::BITSTRING, $offsetIndex++); 69 | $contentLength = self::parseContentLength($binaryData, $offsetIndex, 2); 70 | 71 | $nrOfUnusedBits = ord($binaryData[$offsetIndex]); 72 | $value = substr($binaryData, $offsetIndex + 1, $contentLength - 1); 73 | 74 | if ($nrOfUnusedBits > 7 || // no less than 1 used, otherwise non-minimal 75 | ($contentLength - 1) == 1 && $nrOfUnusedBits > 0 || // content length only 1, no 76 | (ord($value[strlen($value)-1])&((1<<$nrOfUnusedBits)-1)) != 0 // unused bits set 77 | ) { 78 | throw new ParserException("Can not parse bit string with invalid padding", $offsetIndex); 79 | } 80 | 81 | $offsetIndex += $contentLength; 82 | 83 | $parsedObject = new self(bin2hex($value), $nrOfUnusedBits); 84 | $parsedObject->setContentLength($contentLength); 85 | 86 | return $parsedObject; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/Boolean.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\ASNObject; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Identifier; 16 | use FG\ASN1\Exception\ParserException; 17 | 18 | class Boolean extends ASNObject implements Parsable 19 | { 20 | private $value; 21 | 22 | /** 23 | * @param bool $value 24 | */ 25 | public function __construct($value) 26 | { 27 | $this->value = $value; 28 | } 29 | 30 | public function getType() 31 | { 32 | return Identifier::BOOLEAN; 33 | } 34 | 35 | protected function calculateContentLength() 36 | { 37 | return 1; 38 | } 39 | 40 | protected function getEncodedValue() 41 | { 42 | if ($this->value == false) { 43 | return chr(0x00); 44 | } else { 45 | return chr(0xFF); 46 | } 47 | } 48 | 49 | public function getContent() 50 | { 51 | if ($this->value == true) { 52 | return 'TRUE'; 53 | } else { 54 | return 'FALSE'; 55 | } 56 | } 57 | 58 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 59 | { 60 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::BOOLEAN, $offsetIndex++); 61 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 62 | 63 | if ($contentLength != 1) { 64 | throw new ParserException("An ASN.1 Boolean should not have a length other than one. Extracted length was {$contentLength}", $offsetIndex); 65 | } 66 | 67 | $value = ord($binaryData[$offsetIndex++]); 68 | $booleanValue = $value == 0xFF ? true : false; 69 | 70 | $parsedObject = new self($booleanValue); 71 | $parsedObject->setContentLength($contentLength); 72 | 73 | return $parsedObject; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/CharacterString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class CharacterString extends AbstractString 17 | { 18 | public function __construct($string) 19 | { 20 | $this->value = $string; 21 | $this->allowAll(); 22 | } 23 | 24 | public function getType() 25 | { 26 | return Identifier::CHARACTER_STRING; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/Enumerated.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\Identifier; 14 | 15 | class Enumerated extends Integer 16 | { 17 | public function getType() 18 | { 19 | return Identifier::ENUMERATED; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/GeneralString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class GeneralString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 GeneralString. 20 | * TODO The encodable characters of this type are not yet checked. 21 | * 22 | * @param string $string 23 | */ 24 | public function __construct($string) 25 | { 26 | $this->value = $string; 27 | $this->allowAll(); 28 | } 29 | 30 | public function getType() 31 | { 32 | return Identifier::GENERAL_STRING; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/GeneralizedTime.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractTime; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Identifier; 16 | use FG\ASN1\Exception\ParserException; 17 | 18 | /** 19 | * This ASN.1 universal type contains date and time information according to ISO 8601. 20 | * 21 | * The type consists of values representing: 22 | * a) a calendar date, as defined in ISO 8601; and 23 | * b) a time of day, to any of the precisions defined in ISO 8601, except for the hours value 24 which shall not be used; and 24 | * c) the local time differential factor as defined in ISO 8601. 25 | * 26 | * Decoding of this type will accept the Basic Encoding Rules (BER) 27 | * The encoding will comply with the Distinguished Encoding Rules (DER). 28 | */ 29 | class GeneralizedTime extends AbstractTime implements Parsable 30 | { 31 | private $microseconds; 32 | 33 | public function __construct($dateTime = null, $dateTimeZone = 'UTC') 34 | { 35 | parent::__construct($dateTime, $dateTimeZone); 36 | $this->microseconds = $this->value->format('u'); 37 | if ($this->containsFractionalSecondsElement()) { 38 | // DER requires us to remove trailing zeros 39 | $this->microseconds = preg_replace('/([1-9]+)0+$/', '$1', $this->microseconds); 40 | } 41 | } 42 | 43 | public function getType() 44 | { 45 | return Identifier::GENERALIZED_TIME; 46 | } 47 | 48 | protected function calculateContentLength() 49 | { 50 | $contentSize = 15; // YYYYMMDDHHmmSSZ 51 | 52 | if ($this->containsFractionalSecondsElement()) { 53 | $contentSize += 1 + strlen($this->microseconds); 54 | } 55 | 56 | return $contentSize; 57 | } 58 | 59 | public function containsFractionalSecondsElement() 60 | { 61 | return intval($this->microseconds) > 0; 62 | } 63 | 64 | protected function getEncodedValue() 65 | { 66 | $encodedContent = $this->value->format('YmdHis'); 67 | if ($this->containsFractionalSecondsElement()) { 68 | $encodedContent .= ".{$this->microseconds}"; 69 | } 70 | 71 | return $encodedContent.'Z'; 72 | } 73 | 74 | public function __toString() 75 | { 76 | if ($this->containsFractionalSecondsElement()) { 77 | return $this->value->format("Y-m-d\tH:i:s.uP"); 78 | } else { 79 | return $this->value->format("Y-m-d\tH:i:sP"); 80 | } 81 | } 82 | 83 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 84 | { 85 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::GENERALIZED_TIME, $offsetIndex++); 86 | $lengthOfMinimumTimeString = 14; // YYYYMMDDHHmmSS 87 | $contentLength = self::parseContentLength($binaryData, $offsetIndex, $lengthOfMinimumTimeString); 88 | $maximumBytesToRead = $contentLength; 89 | 90 | $format = 'YmdGis'; 91 | $content = substr($binaryData, $offsetIndex, $contentLength); 92 | $dateTimeString = substr($content, 0, $lengthOfMinimumTimeString); 93 | $offsetIndex += $lengthOfMinimumTimeString; 94 | $maximumBytesToRead -= $lengthOfMinimumTimeString; 95 | 96 | if ($contentLength == $lengthOfMinimumTimeString) { 97 | $localTimeZone = new \DateTimeZone(date_default_timezone_get()); 98 | $dateTime = \DateTime::createFromFormat($format, $dateTimeString, $localTimeZone); 99 | } else { 100 | if ($binaryData[$offsetIndex] == '.') { 101 | $maximumBytesToRead--; // account for the '.' 102 | $nrOfFractionalSecondElements = 1; // account for the '.' 103 | 104 | while ($maximumBytesToRead > 0 105 | && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '+' 106 | && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '-' 107 | && $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != 'Z') { 108 | $nrOfFractionalSecondElements++; 109 | $maximumBytesToRead--; 110 | } 111 | 112 | $dateTimeString .= substr($binaryData, $offsetIndex, $nrOfFractionalSecondElements); 113 | $offsetIndex += $nrOfFractionalSecondElements; 114 | $format .= '.u'; 115 | } 116 | 117 | $dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC')); 118 | 119 | if ($maximumBytesToRead > 0) { 120 | if ($binaryData[$offsetIndex] == '+' 121 | || $binaryData[$offsetIndex] == '-') { 122 | $dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime); 123 | } elseif ($binaryData[$offsetIndex++] != 'Z') { 124 | throw new ParserException('Invalid ISO 8601 Time String', $offsetIndex); 125 | } 126 | } 127 | } 128 | 129 | $parsedObject = new self($dateTime); 130 | $parsedObject->setContentLength($contentLength); 131 | 132 | return $parsedObject; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/GraphicString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class GraphicString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 Graphic String. 20 | * TODO The encodable characters of this type are not yet checked. 21 | * 22 | * @param string $string 23 | */ 24 | public function __construct($string) 25 | { 26 | $this->value = $string; 27 | $this->allowAll(); 28 | } 29 | 30 | public function getType() 31 | { 32 | return Identifier::GRAPHIC_STRING; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/IA5String.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | /** 17 | * The International Alphabet No.5 (IA5) references the encoding of the ASCII characters. 18 | * 19 | * Each character in the data is encoded as 1 byte. 20 | */ 21 | class IA5String extends AbstractString 22 | { 23 | public function __construct($string) 24 | { 25 | parent::__construct($string); 26 | for ($i = 1; $i < 128; $i++) { 27 | $this->allowCharacter(chr($i)); 28 | } 29 | } 30 | 31 | public function getType() 32 | { 33 | return Identifier::IA5_STRING; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/Integer.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use Exception; 14 | use FG\Utility\BigInteger; 15 | use FG\ASN1\Exception\ParserException; 16 | use FG\ASN1\ASNObject; 17 | use FG\ASN1\Parsable; 18 | use FG\ASN1\Identifier; 19 | 20 | class Integer extends ASNObject implements Parsable 21 | { 22 | /** @var int */ 23 | private $value; 24 | 25 | /** 26 | * @param int $value 27 | * 28 | * @throws Exception if the value is not numeric 29 | */ 30 | public function __construct($value) 31 | { 32 | if (is_numeric($value) == false) { 33 | throw new Exception("Invalid VALUE [{$value}] for ASN1_INTEGER"); 34 | } 35 | $this->value = $value; 36 | } 37 | 38 | public function getType() 39 | { 40 | return Identifier::INTEGER; 41 | } 42 | 43 | public function getContent() 44 | { 45 | return $this->value; 46 | } 47 | 48 | protected function calculateContentLength() 49 | { 50 | return strlen($this->getEncodedValue()); 51 | } 52 | 53 | protected function getEncodedValue() 54 | { 55 | $value = BigInteger::create($this->value, 10); 56 | $negative = $value->compare(0) < 0; 57 | if ($negative) { 58 | $value = $value->absoluteValue(); 59 | $limit = 0x80; 60 | } else { 61 | $limit = 0x7f; 62 | } 63 | 64 | $mod = 0xff+1; 65 | $values = []; 66 | while($value->compare($limit) > 0) { 67 | $values[] = $value->modulus($mod)->toInteger(); 68 | $value = $value->shiftRight(8); 69 | } 70 | 71 | $values[] = $value->modulus($mod)->toInteger(); 72 | $numValues = count($values); 73 | 74 | if ($negative) { 75 | for ($i = 0; $i < $numValues; $i++) { 76 | $values[$i] = 0xff - $values[$i]; 77 | } 78 | for ($i = 0; $i < $numValues; $i++) { 79 | $values[$i] += 1; 80 | if ($values[$i] <= 0xff) { 81 | break; 82 | } 83 | assert($i != $numValues - 1); 84 | $values[$i] = 0; 85 | } 86 | if ($values[$numValues - 1] == 0x7f) { 87 | $values[] = 0xff; 88 | } 89 | } 90 | $values = array_reverse($values); 91 | $r = pack("C*", ...$values); 92 | return $r; 93 | } 94 | 95 | private static function ensureMinimalEncoding($binaryData, $offsetIndex) 96 | { 97 | // All the first nine bits cannot equal 0 or 1, which would 98 | // be non-minimal encoding for positive and negative integers respectively 99 | if ((ord($binaryData[$offsetIndex]) == 0x00 && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0) || 100 | (ord($binaryData[$offsetIndex]) == 0xff && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0x80)) { 101 | throw new ParserException("Integer not minimally encoded", $offsetIndex); 102 | } 103 | } 104 | 105 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 106 | { 107 | $parsedObject = new static(0); 108 | self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++); 109 | $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); 110 | 111 | if ($contentLength > 1) { 112 | self::ensureMinimalEncoding($binaryData, $offsetIndex); 113 | } 114 | $isNegative = (ord($binaryData[$offsetIndex]) & 0x80) != 0x00; 115 | $number = BigInteger::create(ord($binaryData[$offsetIndex++]) & 0x7F); 116 | 117 | for ($i = 0; $i < $contentLength - 1; $i++) { 118 | $number = $number->multiply(0x100)->add(ord($binaryData[$offsetIndex++])); 119 | } 120 | 121 | if ($isNegative) { 122 | $number = $number->subtract(BigInteger::create(2)->toPower(8 * $contentLength - 1)); 123 | } 124 | 125 | $parsedObject = new static((string)$number); 126 | $parsedObject->setContentLength($contentLength); 127 | 128 | return $parsedObject; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/NullObject.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\ASNObject; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Identifier; 16 | use FG\ASN1\Exception\ParserException; 17 | 18 | class NullObject extends ASNObject implements Parsable 19 | { 20 | public function getType() 21 | { 22 | return Identifier::NULL; 23 | } 24 | 25 | protected function calculateContentLength() 26 | { 27 | return 0; 28 | } 29 | 30 | protected function getEncodedValue() 31 | { 32 | return null; 33 | } 34 | 35 | public function getContent() 36 | { 37 | return 'NULL'; 38 | } 39 | 40 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 41 | { 42 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::NULL, $offsetIndex++); 43 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 44 | 45 | if ($contentLength != 0) { 46 | throw new ParserException("An ASN.1 Null should not have a length other than zero. Extracted length was {$contentLength}", $offsetIndex); 47 | } 48 | 49 | $parsedObject = new self(); 50 | $parsedObject->setContentLength(0); 51 | 52 | return $parsedObject; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/NumericString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class NumericString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 NumericString. 20 | * 21 | * The following characters are permitted: 22 | * Digits 0,1, ... 9 23 | * SPACE (space) 24 | * 25 | * @param string $string 26 | */ 27 | public function __construct($string) 28 | { 29 | $this->value = $string; 30 | $this->allowNumbers(); 31 | $this->allowSpaces(); 32 | } 33 | 34 | public function getType() 35 | { 36 | return Identifier::NUMERIC_STRING; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/ObjectDescriptor.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\Identifier; 14 | 15 | class ObjectDescriptor extends GraphicString 16 | { 17 | public function __construct($objectDescription) 18 | { 19 | parent::__construct($objectDescription); 20 | } 21 | 22 | public function getType() 23 | { 24 | return Identifier::OBJECT_DESCRIPTOR; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/ObjectIdentifier.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use Exception; 14 | use FG\ASN1\Base128; 15 | use FG\ASN1\OID; 16 | use FG\ASN1\ASNObject; 17 | use FG\ASN1\Parsable; 18 | use FG\ASN1\Identifier; 19 | use FG\ASN1\Exception\ParserException; 20 | 21 | class ObjectIdentifier extends ASNObject implements Parsable 22 | { 23 | protected $subIdentifiers; 24 | protected $value; 25 | 26 | public function __construct($value) 27 | { 28 | $this->subIdentifiers = explode('.', $value); 29 | $nrOfSubIdentifiers = count($this->subIdentifiers); 30 | 31 | for ($i = 0; $i < $nrOfSubIdentifiers; $i++) { 32 | if (is_numeric($this->subIdentifiers[$i])) { 33 | // enforce the integer type 34 | $this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]); 35 | } else { 36 | throw new Exception("[{$value}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!'); 37 | } 38 | } 39 | 40 | // Merge the first to arcs of the OID registration tree (per ASN definition!) 41 | if ($nrOfSubIdentifiers >= 2) { 42 | $this->subIdentifiers[1] = ($this->subIdentifiers[0] * 40) + $this->subIdentifiers[1]; 43 | unset($this->subIdentifiers[0]); 44 | } 45 | 46 | $this->value = $value; 47 | } 48 | 49 | public function getContent() 50 | { 51 | return $this->value; 52 | } 53 | 54 | public function getType() 55 | { 56 | return Identifier::OBJECT_IDENTIFIER; 57 | } 58 | 59 | protected function calculateContentLength() 60 | { 61 | $length = 0; 62 | foreach ($this->subIdentifiers as $subIdentifier) { 63 | do { 64 | $subIdentifier = $subIdentifier >> 7; 65 | $length++; 66 | } while ($subIdentifier > 0); 67 | } 68 | 69 | return $length; 70 | } 71 | 72 | protected function getEncodedValue() 73 | { 74 | $encodedValue = ''; 75 | foreach ($this->subIdentifiers as $subIdentifier) { 76 | $encodedValue .= Base128::encode($subIdentifier); 77 | } 78 | 79 | return $encodedValue; 80 | } 81 | 82 | public function __toString() 83 | { 84 | return OID::getName($this->value); 85 | } 86 | 87 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 88 | { 89 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::OBJECT_IDENTIFIER, $offsetIndex++); 90 | $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); 91 | 92 | $firstOctet = ord($binaryData[$offsetIndex++]); 93 | $oidString = floor($firstOctet / 40).'.'.($firstOctet % 40); 94 | $oidString .= '.'.self::parseOid($binaryData, $offsetIndex, $contentLength - 1); 95 | 96 | $parsedObject = new self($oidString); 97 | $parsedObject->setContentLength($contentLength); 98 | 99 | return $parsedObject; 100 | } 101 | 102 | /** 103 | * Parses an object identifier except for the first octet, which is parsed 104 | * differently. This way relative object identifiers can also be parsed 105 | * using this. 106 | * 107 | * @param $binaryData 108 | * @param $offsetIndex 109 | * @param $octetsToRead 110 | * 111 | * @throws ParserException 112 | * 113 | * @return string 114 | */ 115 | protected static function parseOid(&$binaryData, &$offsetIndex, $octetsToRead) 116 | { 117 | $oid = ''; 118 | 119 | while ($octetsToRead > 0) { 120 | $octets = ''; 121 | 122 | do { 123 | if (0 === $octetsToRead) { 124 | throw new ParserException('Malformed ASN.1 Object Identifier', $offsetIndex - 1); 125 | } 126 | 127 | $octetsToRead--; 128 | $octet = $binaryData[$offsetIndex++]; 129 | $octets .= $octet; 130 | } while (ord($octet) & 0x80); 131 | 132 | $oid .= sprintf('%d.', Base128::decode($octets)); 133 | } 134 | 135 | // Remove trailing '.' 136 | return substr($oid, 0, -1) ?: ''; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/OctetString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use Exception; 14 | use FG\ASN1\ASNObject; 15 | use FG\ASN1\Parsable; 16 | use FG\ASN1\Identifier; 17 | 18 | class OctetString extends ASNObject implements Parsable 19 | { 20 | protected $value; 21 | 22 | public function __construct($value) 23 | { 24 | if (is_string($value)) { 25 | // remove gaps between hex digits 26 | $value = preg_replace('/\s|0x/', '', $value); 27 | } elseif (is_numeric($value)) { 28 | $value = dechex($value); 29 | } elseif ($value === null) { 30 | return; 31 | } else { 32 | throw new Exception('OctetString: unrecognized input type!'); 33 | } 34 | 35 | if (strlen($value) % 2 != 0) { 36 | // transform values like 1F2 to 01F2 37 | $value = '0'.$value; 38 | } 39 | 40 | $this->value = $value; 41 | } 42 | 43 | public function getType() 44 | { 45 | return Identifier::OCTETSTRING; 46 | } 47 | 48 | protected function calculateContentLength() 49 | { 50 | return strlen($this->value) / 2; 51 | } 52 | 53 | protected function getEncodedValue() 54 | { 55 | $value = $this->value; 56 | $result = ''; 57 | 58 | //Actual content 59 | while (strlen($value) >= 2) { 60 | // get the hex value byte by byte from the string and and add it to binary result 61 | $result .= chr(hexdec(substr($value, 0, 2))); 62 | $value = substr($value, 2); 63 | } 64 | 65 | return $result; 66 | } 67 | 68 | public function getContent() 69 | { 70 | return strtoupper($this->value); 71 | } 72 | 73 | public function getBinaryContent() 74 | { 75 | return $this->getEncodedValue(); 76 | } 77 | 78 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 79 | { 80 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++); 81 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 82 | 83 | $value = substr($binaryData, $offsetIndex, $contentLength); 84 | $offsetIndex += $contentLength; 85 | 86 | $parsedObject = new self(bin2hex($value)); 87 | $parsedObject->setContentLength($contentLength); 88 | 89 | return $parsedObject; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/PrintableString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class PrintableString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 PrintableString. 20 | * 21 | * The ITU-T X.680 Table 8 permits the following characters: 22 | * Latin capital letters A,B, ... Z 23 | * Latin small letters a,b, ... z 24 | * Digits 0,1, ... 9 25 | * SPACE (space) 26 | * APOSTROPHE ' 27 | * LEFT PARENTHESIS ( 28 | * RIGHT PARENTHESIS ) 29 | * PLUS SIGN + 30 | * COMMA , 31 | * HYPHEN-MINUS - 32 | * FULL STOP . 33 | * SOLIDUS / 34 | * COLON : 35 | * EQUALS SIGN = 36 | * QUESTION MARK ? 37 | * 38 | * @param string $string 39 | */ 40 | public function __construct($string) 41 | { 42 | $this->value = $string; 43 | $this->allowNumbers(); 44 | $this->allowAllLetters(); 45 | $this->allowSpaces(); 46 | $this->allowCharacters("'", '(', ')', '+', '-', '.', ',', '/', ':', '=', '?'); 47 | } 48 | 49 | public function getType() 50 | { 51 | return Identifier::PRINTABLE_STRING; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/RelativeObjectIdentifier.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use Exception; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Identifier; 16 | use FG\ASN1\Exception\ParserException; 17 | 18 | class RelativeObjectIdentifier extends ObjectIdentifier implements Parsable 19 | { 20 | public function __construct($subIdentifiers) 21 | { 22 | $this->value = $subIdentifiers; 23 | $this->subIdentifiers = explode('.', $subIdentifiers); 24 | $nrOfSubIdentifiers = count($this->subIdentifiers); 25 | 26 | for ($i = 0; $i < $nrOfSubIdentifiers; $i++) { 27 | if (is_numeric($this->subIdentifiers[$i])) { 28 | // enforce the integer type 29 | $this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]); 30 | } else { 31 | throw new Exception("[{$subIdentifiers}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!'); 32 | } 33 | } 34 | } 35 | 36 | public function getType() 37 | { 38 | return Identifier::RELATIVE_OID; 39 | } 40 | 41 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 42 | { 43 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::RELATIVE_OID, $offsetIndex++); 44 | $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1); 45 | 46 | try { 47 | $oidString = self::parseOid($binaryData, $offsetIndex, $contentLength); 48 | } catch (ParserException $e) { 49 | throw new ParserException('Malformed ASN.1 Relative Object Identifier', $e->getOffset()); 50 | } 51 | 52 | $parsedObject = new self($oidString); 53 | $parsedObject->setContentLength($contentLength); 54 | 55 | return $parsedObject; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/Sequence.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\Construct; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Identifier; 16 | 17 | class Sequence extends Construct implements Parsable 18 | { 19 | public function getType() 20 | { 21 | return Identifier::SEQUENCE; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/Set.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\Identifier; 14 | 15 | class Set extends Sequence 16 | { 17 | public function getType() 18 | { 19 | return Identifier::SET; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/T61String.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class T61String extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 T61 String. 20 | * TODO The encodable characters of this type are not yet checked. 21 | * 22 | * @see http://en.wikipedia.org/wiki/ITU_T.61 23 | * 24 | * @param string $string 25 | */ 26 | public function __construct($string) 27 | { 28 | $this->value = $string; 29 | $this->allowAll(); 30 | } 31 | 32 | public function getType() 33 | { 34 | return Identifier::T61_STRING; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/UTCTime.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractTime; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Identifier; 16 | use FG\ASN1\Exception\ParserException; 17 | 18 | /** 19 | * This ASN.1 universal type contains the calendar date and time. 20 | * 21 | * The precision is one minute or one second and optionally a 22 | * local time differential from coordinated universal time. 23 | * 24 | * Decoding of this type will accept the Basic Encoding Rules (BER) 25 | * The encoding will comply with the Distinguished Encoding Rules (DER). 26 | */ 27 | class UTCTime extends AbstractTime implements Parsable 28 | { 29 | public function getType() 30 | { 31 | return Identifier::UTC_TIME; 32 | } 33 | 34 | protected function calculateContentLength() 35 | { 36 | return 13; // Content is a string o the following format: YYMMDDhhmmssZ (13 octets) 37 | } 38 | 39 | protected function getEncodedValue() 40 | { 41 | return $this->value->format('ymdHis').'Z'; 42 | } 43 | 44 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 45 | { 46 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::UTC_TIME, $offsetIndex++); 47 | $contentLength = self::parseContentLength($binaryData, $offsetIndex, 11); 48 | 49 | $format = 'ymdGi'; 50 | $dateTimeString = substr($binaryData, $offsetIndex, 10); 51 | $offsetIndex += 10; 52 | 53 | // extract optional seconds part 54 | if ($binaryData[$offsetIndex] != 'Z' 55 | && $binaryData[$offsetIndex] != '+' 56 | && $binaryData[$offsetIndex] != '-') { 57 | $dateTimeString .= substr($binaryData, $offsetIndex, 2); 58 | $offsetIndex += 2; 59 | $format .= 's'; 60 | } 61 | 62 | $dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC')); 63 | 64 | // extract time zone settings 65 | if ($binaryData[$offsetIndex] == '+' 66 | || $binaryData[$offsetIndex] == '-') { 67 | $dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime); 68 | } elseif ($binaryData[$offsetIndex++] != 'Z') { 69 | throw new ParserException('Invalid UTC String', $offsetIndex); 70 | } 71 | 72 | $parsedObject = new self($dateTime); 73 | $parsedObject->setContentLength($contentLength); 74 | 75 | return $parsedObject; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/UTF8String.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class UTF8String extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 Universal String. 20 | * TODO The encodable characters of this type are not yet checked. 21 | * 22 | * @param string $string 23 | */ 24 | public function __construct($string) 25 | { 26 | $this->value = $string; 27 | $this->allowAll(); 28 | } 29 | 30 | public function getType() 31 | { 32 | return Identifier::UTF8_STRING; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/UniversalString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class UniversalString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 Universal String. 20 | * TODO The encodable characters of this type are not yet checked. 21 | * 22 | * @see http://en.wikipedia.org/wiki/Universal_Character_Set 23 | * 24 | * @param string $string 25 | */ 26 | public function __construct($string) 27 | { 28 | $this->value = $string; 29 | $this->allowAll(); 30 | } 31 | 32 | public function getType() 33 | { 34 | return Identifier::UNIVERSAL_STRING; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/ASN1/Universal/VisibleString.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1\Universal; 12 | 13 | use FG\ASN1\AbstractString; 14 | use FG\ASN1\Identifier; 15 | 16 | class VisibleString extends AbstractString 17 | { 18 | /** 19 | * Creates a new ASN.1 Visible String. 20 | * TODO The encodable characters of this type are not yet checked. 21 | * 22 | * @param string $string 23 | */ 24 | public function __construct($string) 25 | { 26 | $this->value = $string; 27 | $this->allowAll(); 28 | } 29 | 30 | public function getType() 31 | { 32 | return Identifier::VISIBLE_STRING; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/ASN1/UnknownConstructedObject.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | class UnknownConstructedObject extends Construct 14 | { 15 | private $identifier; 16 | private $contentLength; 17 | 18 | /** 19 | * @param string $binaryData 20 | * @param int $offsetIndex 21 | * 22 | * @throws \FG\ASN1\Exception\ParserException 23 | */ 24 | public function __construct($binaryData, &$offsetIndex) 25 | { 26 | $this->identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex); 27 | $this->contentLength = self::parseContentLength($binaryData, $offsetIndex); 28 | 29 | $children = []; 30 | $octetsToRead = $this->contentLength; 31 | while ($octetsToRead > 0) { 32 | $newChild = ASNObject::fromBinary($binaryData, $offsetIndex); 33 | $octetsToRead -= $newChild->getObjectLength(); 34 | $children[] = $newChild; 35 | } 36 | 37 | parent::__construct(...$children); 38 | } 39 | 40 | public function getType() 41 | { 42 | return ord($this->identifier); 43 | } 44 | 45 | public function getIdentifier() 46 | { 47 | return $this->identifier; 48 | } 49 | 50 | protected function calculateContentLength() 51 | { 52 | return $this->contentLength; 53 | } 54 | 55 | protected function getEncodedValue() 56 | { 57 | return ''; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/ASN1/UnknownObject.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\ASN1; 12 | 13 | class UnknownObject extends ASNObject 14 | { 15 | /** @var string */ 16 | private $value; 17 | 18 | private $identifier; 19 | 20 | /** 21 | * @param string|int $identifier Either the first identifier octet as int or all identifier bytes as a string 22 | * @param int $contentLength 23 | */ 24 | public function __construct($identifier, $contentLength) 25 | { 26 | if (is_int($identifier)) { 27 | $identifier = chr($identifier); 28 | } 29 | 30 | $this->identifier = $identifier; 31 | $this->value = "Unparsable Object ({$contentLength} bytes)"; 32 | $this->setContentLength($contentLength); 33 | } 34 | 35 | public function getContent() 36 | { 37 | return $this->value; 38 | } 39 | 40 | public function getType() 41 | { 42 | return ord($this->identifier[0]); 43 | } 44 | 45 | public function getIdentifier() 46 | { 47 | return $this->identifier; 48 | } 49 | 50 | protected function calculateContentLength() 51 | { 52 | return $this->getContentLength(); 53 | } 54 | 55 | protected function getEncodedValue() 56 | { 57 | return ''; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/Utility/BigInteger.php: -------------------------------------------------------------------------------- 1 | _fromInteger($val); 68 | } 69 | else { 70 | // convert to string, if not already one 71 | $val = (string)$val; 72 | 73 | // validate string 74 | if (!preg_match('/^-?[0-9]+$/', $val)) { 75 | throw new \InvalidArgumentException('Expects a string representation of an integer.'); 76 | } 77 | $ret->_fromString($val); 78 | } 79 | 80 | return $ret; 81 | } 82 | 83 | /** 84 | * BigInteger constructor. 85 | * Prevent directly instantiating object, use BigInteger::create instead. 86 | */ 87 | protected function __construct() 88 | { 89 | 90 | } 91 | 92 | /** 93 | * Subclasses must provide clone functionality. 94 | * @return BigInteger 95 | */ 96 | abstract public function __clone(); 97 | 98 | /** 99 | * Assign the instance value from base 10 string. 100 | * @param string $str 101 | */ 102 | abstract protected function _fromString($str); 103 | 104 | /** 105 | * Assign the instance value from an integer type. 106 | * @param int $integer 107 | */ 108 | abstract protected function _fromInteger($integer); 109 | 110 | /** 111 | * Must provide string implementation that returns base 10 number. 112 | * @return string 113 | */ 114 | abstract public function __toString(); 115 | 116 | /* INFORMATIONAL FUNCTIONS */ 117 | 118 | /** 119 | * Return integer, if possible. Throws an exception if the number can not be represented as a native integer. 120 | * @return int 121 | * @throws \OverflowException 122 | */ 123 | abstract public function toInteger(); 124 | 125 | /** 126 | * Is represented integer negative? 127 | * @return bool 128 | */ 129 | abstract public function isNegative(); 130 | 131 | /** 132 | * Compare the integer with $number, returns a negative integer if $this is less than number, returns 0 if $this is 133 | * equal to number and returns a positive integer if $this is greater than number. 134 | * @param BigInteger|string|int $number 135 | * @return int 136 | */ 137 | abstract public function compare($number); 138 | 139 | /* MODIFY */ 140 | 141 | /** 142 | * Add another integer $b and returns the result. 143 | * @param BigInteger|string|int $b 144 | * @return BigInteger 145 | */ 146 | abstract public function add($b); 147 | 148 | /** 149 | * Subtract $b from $this and returns the result. 150 | * @param BigInteger|string|int $b 151 | * @return BigInteger 152 | */ 153 | abstract public function subtract($b); 154 | 155 | /** 156 | * Multiply value. 157 | * @param BigInteger|string|int $b 158 | * @return BigInteger 159 | */ 160 | abstract public function multiply($b); 161 | 162 | /** 163 | * The value $this modulus $b. 164 | * @param BigInteger|string|int $b 165 | * @return BigInteger 166 | */ 167 | abstract public function modulus($b); 168 | 169 | /** 170 | * Raise $this to the power of $b and returns the result. 171 | * @param BigInteger|string|int $b 172 | * @return BigInteger 173 | */ 174 | abstract public function toPower($b); 175 | 176 | /** 177 | * Shift the value to the right by a set number of bits and returns the result. 178 | * @param int $bits 179 | * @return BigInteger 180 | */ 181 | abstract public function shiftRight($bits = 8); 182 | 183 | /** 184 | * Shift the value to the left by a set number of bits and returns the result. 185 | * @param int $bits 186 | * @return BigInteger 187 | */ 188 | abstract public function shiftLeft($bits = 8); 189 | 190 | /** 191 | * Returns the absolute value. 192 | * @return BigInteger 193 | */ 194 | abstract public function absoluteValue(); 195 | } 196 | -------------------------------------------------------------------------------- /lib/Utility/BigIntegerBcmath.php: -------------------------------------------------------------------------------- 1 | _str = (string)$str; 29 | } 30 | 31 | protected function _fromInteger($integer) 32 | { 33 | $this->_str = (string)$integer; 34 | } 35 | 36 | public function __toString() 37 | { 38 | return $this->_str; 39 | } 40 | 41 | public function toInteger() 42 | { 43 | if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) { 44 | throw new \OverflowException(sprintf('Can not represent %s as integer.', $this->_str)); 45 | } 46 | return (int)$this->_str; 47 | } 48 | 49 | public function isNegative() 50 | { 51 | return bccomp($this->_str, '0', 0) < 0; 52 | } 53 | 54 | protected function _unwrap($number) 55 | { 56 | if ($number instanceof self) { 57 | return $number->_str; 58 | } 59 | return $number; 60 | } 61 | 62 | public function compare($number) 63 | { 64 | return bccomp($this->_str, $this->_unwrap($number), 0); 65 | } 66 | 67 | public function add($b) 68 | { 69 | $ret = new self(); 70 | $ret->_str = bcadd($this->_str, $this->_unwrap($b), 0); 71 | return $ret; 72 | } 73 | 74 | public function subtract($b) 75 | { 76 | $ret = new self(); 77 | $ret->_str = bcsub($this->_str, $this->_unwrap($b), 0); 78 | return $ret; 79 | } 80 | 81 | public function multiply($b) 82 | { 83 | $ret = new self(); 84 | $ret->_str = bcmul($this->_str, $this->_unwrap($b), 0); 85 | return $ret; 86 | } 87 | 88 | public function modulus($b) 89 | { 90 | $ret = new self(); 91 | if ($this->isNegative()) { 92 | // bcmod handles negative numbers differently 93 | $b = $this->_unwrap($b); 94 | $ret->_str = bcsub($b, bcmod(bcsub('0', $this->_str, 0), $b), 0); 95 | } 96 | else { 97 | $ret->_str = bcmod($this->_str, $this->_unwrap($b)); 98 | } 99 | return $ret; 100 | } 101 | 102 | public function toPower($b) 103 | { 104 | $ret = new self(); 105 | $ret->_str = bcpow($this->_str, $this->_unwrap($b), 0); 106 | return $ret; 107 | } 108 | 109 | public function shiftRight($bits = 8) 110 | { 111 | $ret = new self(); 112 | $ret->_str = bcdiv($this->_str, bcpow('2', $bits)); 113 | return $ret; 114 | } 115 | 116 | public function shiftLeft($bits = 8) { 117 | $ret = new self(); 118 | $ret->_str = bcmul($this->_str, bcpow('2', $bits)); 119 | return $ret; 120 | } 121 | 122 | public function absoluteValue() 123 | { 124 | $ret = new self(); 125 | if (-1 === bccomp($this->_str, '0', 0)) { 126 | $ret->_str = bcsub('0', $this->_str, 0); 127 | } 128 | else { 129 | $ret->_str = $this->_str; 130 | } 131 | return $ret; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /lib/Utility/BigIntegerGmp.php: -------------------------------------------------------------------------------- 1 | _rh = gmp_add($this->_rh, 0); 28 | } 29 | 30 | protected function _fromString($str) 31 | { 32 | $this->_rh = gmp_init($str, 10); 33 | } 34 | 35 | protected function _fromInteger($integer) 36 | { 37 | $this->_rh = gmp_init($integer, 10); 38 | } 39 | 40 | public function __toString() 41 | { 42 | return gmp_strval($this->_rh, 10); 43 | } 44 | 45 | public function toInteger() 46 | { 47 | if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) { 48 | throw new \OverflowException(sprintf('Can not represent %s as integer.', $this)); 49 | } 50 | return gmp_intval($this->_rh); 51 | } 52 | 53 | public function isNegative() 54 | { 55 | return gmp_sign($this->_rh) === -1; 56 | } 57 | 58 | protected function _unwrap($number) 59 | { 60 | if ($number instanceof self) { 61 | return $number->_rh; 62 | } 63 | return $number; 64 | } 65 | 66 | public function compare($number) 67 | { 68 | return gmp_cmp($this->_rh, $this->_unwrap($number)); 69 | } 70 | 71 | public function add($b) 72 | { 73 | $ret = new self(); 74 | $ret->_rh = gmp_add($this->_rh, $this->_unwrap($b)); 75 | return $ret; 76 | } 77 | 78 | public function subtract($b) 79 | { 80 | $ret = new self(); 81 | $ret->_rh = gmp_sub($this->_rh, $this->_unwrap($b)); 82 | return $ret; 83 | } 84 | 85 | public function multiply($b) 86 | { 87 | $ret = new self(); 88 | $ret->_rh = gmp_mul($this->_rh, $this->_unwrap($b)); 89 | return $ret; 90 | } 91 | 92 | public function modulus($b) 93 | { 94 | $ret = new self(); 95 | $ret->_rh = gmp_mod($this->_rh, $this->_unwrap($b)); 96 | return $ret; 97 | } 98 | 99 | public function toPower($b) 100 | { 101 | if ($b instanceof self) { 102 | // gmp_pow accepts just an integer 103 | if ($b->compare(PHP_INT_MAX) > 0) { 104 | throw new \UnexpectedValueException('Unable to raise to power greater than PHP_INT_MAX.'); 105 | } 106 | $b = gmp_intval($b->_rh); 107 | } 108 | $ret = new self(); 109 | $ret->_rh = gmp_pow($this->_rh, $b); 110 | return $ret; 111 | } 112 | 113 | public function shiftRight($bits=8) 114 | { 115 | $ret = new self(); 116 | $ret->_rh = gmp_div($this->_rh, gmp_pow(2, $bits)); 117 | return $ret; 118 | } 119 | 120 | public function shiftLeft($bits=8) 121 | { 122 | $ret = new self(); 123 | $ret->_rh = gmp_mul($this->_rh, gmp_pow(2, $bits)); 124 | return $ret; 125 | } 126 | 127 | public function absoluteValue() 128 | { 129 | $ret = new self(); 130 | $ret->_rh = gmp_abs($this->_rh); 131 | return $ret; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /lib/X509/AlgorithmIdentifier.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509; 12 | 13 | use FG\ASN1\Universal\NullObject; 14 | use FG\ASN1\Composite\AttributeTypeAndValue; 15 | 16 | class AlgorithmIdentifier extends AttributeTypeAndValue 17 | { 18 | public function __construct($objectIdentifierString) 19 | { 20 | parent::__construct($objectIdentifierString, new NullObject()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/X509/CSR/Attributes.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509\CSR; 12 | 13 | use FG\ASN1\ASNObject; 14 | use FG\X509\CertificateExtensions; 15 | use FG\ASN1\OID; 16 | use FG\ASN1\Parsable; 17 | use FG\ASN1\Construct; 18 | use FG\ASN1\Identifier; 19 | use FG\ASN1\Universal\Set; 20 | use FG\ASN1\Universal\Sequence; 21 | use FG\ASN1\Universal\ObjectIdentifier; 22 | 23 | class Attributes extends Construct implements Parsable 24 | { 25 | public function getType() 26 | { 27 | return 0xA0; 28 | } 29 | 30 | public function addAttribute($objectIdentifier, Set $attribute) 31 | { 32 | if (is_string($objectIdentifier)) { 33 | $objectIdentifier = new ObjectIdentifier($objectIdentifier); 34 | } 35 | $attributeSequence = new Sequence($objectIdentifier, $attribute); 36 | $attributeSequence->getNumberOfLengthOctets(); // length and number of length octets is calculated 37 | $this->addChild($attributeSequence); 38 | } 39 | 40 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 41 | { 42 | self::parseIdentifier($binaryData[$offsetIndex], 0xA0, $offsetIndex++); 43 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 44 | $octetsToRead = $contentLength; 45 | 46 | $parsedObject = new self(); 47 | while ($octetsToRead > 0) { 48 | $initialOffset = $offsetIndex; // used to calculate how much bits have been read 49 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++); 50 | self::parseContentLength($binaryData, $offsetIndex); 51 | 52 | $objectIdentifier = ObjectIdentifier::fromBinary($binaryData, $offsetIndex); 53 | $oidString = $objectIdentifier->getContent(); 54 | if ($oidString == OID::PKCS9_EXTENSION_REQUEST) { 55 | $attribute = CertificateExtensions::fromBinary($binaryData, $offsetIndex); 56 | } else { 57 | $attribute = ASNObject::fromBinary($binaryData, $offsetIndex); 58 | } 59 | 60 | $parsedObject->addAttribute($objectIdentifier, $attribute); 61 | $octetsToRead -= ($offsetIndex - $initialOffset); 62 | } 63 | 64 | $parsedObject->setContentLength($contentLength); 65 | 66 | return $parsedObject; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/X509/CSR/CSR.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509\CSR; 12 | 13 | use FG\ASN1\OID; 14 | use FG\ASN1\Universal\Integer; 15 | use FG\ASN1\Universal\BitString; 16 | use FG\ASN1\Universal\Sequence; 17 | use FG\X509\CertificateSubject; 18 | use FG\X509\AlgorithmIdentifier; 19 | use FG\X509\PublicKey; 20 | 21 | class CSR extends Sequence 22 | { 23 | const CSR_VERSION_NR = 0; 24 | 25 | protected $subject; 26 | protected $publicKey; 27 | protected $signature; 28 | protected $signatureAlgorithm; 29 | 30 | protected $startSequence; 31 | 32 | /** 33 | * @param string $commonName 34 | * @param string $email 35 | * @param string $organization 36 | * @param string $locality 37 | * @param string $state 38 | * @param string $country 39 | * @param string $organizationalUnit 40 | * @param string $publicKey 41 | * @param string $signature 42 | * @param string $signatureAlgorithm 43 | */ 44 | public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit, $publicKey, $signature = null, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE) 45 | { 46 | $this->subject = new CertificateSubject( 47 | $commonName, 48 | $email, 49 | $organization, 50 | $locality, 51 | $state, 52 | $country, 53 | $organizationalUnit 54 | ); 55 | $this->publicKey = $publicKey; 56 | $this->signature = $signature; 57 | $this->signatureAlgorithm = $signatureAlgorithm; 58 | 59 | if (isset($signature)) { 60 | $this->createCSRSequence(); 61 | } 62 | } 63 | 64 | protected function createCSRSequence() 65 | { 66 | $versionNr = new Integer(self::CSR_VERSION_NR); 67 | $publicKey = new PublicKey($this->publicKey); 68 | $signature = new BitString($this->signature); 69 | $signatureAlgorithm = new AlgorithmIdentifier($this->signatureAlgorithm); 70 | 71 | $certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey); 72 | 73 | // Clear the underlying Construct 74 | $this->rewind(); 75 | $this->children = []; 76 | $this->addChild($certRequestInfo); 77 | $this->addChild($signatureAlgorithm); 78 | $this->addChild($signature); 79 | } 80 | 81 | public function getSignatureSubject() 82 | { 83 | $versionNr = new Integer(self::CSR_VERSION_NR); 84 | $publicKey = new PublicKey($this->publicKey); 85 | 86 | $certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey); 87 | return $certRequestInfo->getBinary(); 88 | } 89 | 90 | public function setSignature($signature, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE) 91 | { 92 | $this->signature = $signature; 93 | $this->signatureAlgorithm = $signatureAlgorithm; 94 | 95 | $this->createCSRSequence(); 96 | } 97 | 98 | public function __toString() 99 | { 100 | $tmp = base64_encode($this->getBinary()); 101 | 102 | for ($i = 0; $i < strlen($tmp); $i++) { 103 | if (($i + 2) % 65 == 0) { 104 | $tmp = substr($tmp, 0, $i + 1)."\n".substr($tmp, $i + 1); 105 | } 106 | } 107 | 108 | $result = '-----BEGIN CERTIFICATE REQUEST-----'.PHP_EOL; 109 | $result .= $tmp.PHP_EOL; 110 | $result .= '-----END CERTIFICATE REQUEST-----'; 111 | 112 | return $result; 113 | } 114 | 115 | public function getVersion() 116 | { 117 | return self::CSR_VERSION_NR; 118 | } 119 | 120 | public function getOrganizationName() 121 | { 122 | return $this->subject->getOrganization(); 123 | } 124 | 125 | public function getLocalName() 126 | { 127 | return $this->subject->getLocality(); 128 | } 129 | 130 | public function getState() 131 | { 132 | return $this->subject->getState(); 133 | } 134 | 135 | public function getCountry() 136 | { 137 | return $this->subject->getCountry(); 138 | } 139 | 140 | public function getOrganizationalUnit() 141 | { 142 | return $this->subject->getOrganizationalUnit(); 143 | } 144 | 145 | public function getPublicKey() 146 | { 147 | return $this->publicKey; 148 | } 149 | 150 | public function getSignature() 151 | { 152 | return $this->signature; 153 | } 154 | 155 | public function getSignatureAlgorithm() 156 | { 157 | return $this->signatureAlgorithm; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /lib/X509/CertificateExtensions.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509; 12 | 13 | use FG\ASN1\Exception\ParserException; 14 | use FG\ASN1\OID; 15 | use FG\ASN1\ASNObject; 16 | use FG\ASN1\Parsable; 17 | use FG\ASN1\Identifier; 18 | use FG\ASN1\Universal\OctetString; 19 | use FG\ASN1\Universal\Set; 20 | use FG\ASN1\Universal\Sequence; 21 | use FG\ASN1\Universal\ObjectIdentifier; 22 | use FG\X509\SAN\SubjectAlternativeNames; 23 | 24 | class CertificateExtensions extends Set implements Parsable 25 | { 26 | private $innerSequence; 27 | private $extensions = []; 28 | 29 | public function __construct() 30 | { 31 | $this->innerSequence = new Sequence(); 32 | parent::__construct($this->innerSequence); 33 | } 34 | 35 | public function addSubjectAlternativeNames(SubjectAlternativeNames $sans) 36 | { 37 | $this->addExtension(OID::CERT_EXT_SUBJECT_ALT_NAME, $sans); 38 | } 39 | 40 | private function addExtension($oidString, ASNObject $extension) 41 | { 42 | $sequence = new Sequence(); 43 | $sequence->addChild(new ObjectIdentifier($oidString)); 44 | $sequence->addChild($extension); 45 | 46 | $this->innerSequence->addChild($sequence); 47 | $this->extensions[] = $extension; 48 | } 49 | 50 | public function getContent() 51 | { 52 | return $this->extensions; 53 | } 54 | 55 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 56 | { 57 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::SET, $offsetIndex++); 58 | self::parseContentLength($binaryData, $offsetIndex); 59 | 60 | $tmpOffset = $offsetIndex; 61 | $extensions = Sequence::fromBinary($binaryData, $offsetIndex); 62 | $tmpOffset += 1 + $extensions->getNumberOfLengthOctets(); 63 | 64 | $parsedObject = new self(); 65 | foreach ($extensions as $extension) { 66 | if ($extension->getType() != Identifier::SEQUENCE) { 67 | //FIXME wrong offset index 68 | throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Sequence but got '.$extension->getTypeName(), $offsetIndex); 69 | } 70 | 71 | $tmpOffset += 1 + $extension->getNumberOfLengthOctets(); 72 | $children = $extension->getChildren(); 73 | if (count($children) < 2) { 74 | throw new ParserException('Could not parse Certificate Extensions: Needs at least two child elements per extension sequence (object identifier and octet string)', $tmpOffset); 75 | } 76 | /** @var \FG\ASN1\ASNObject $objectIdentifier */ 77 | $objectIdentifier = $children[0]; 78 | 79 | /** @var OctetString $octetString */ 80 | $octetString = $children[1]; 81 | 82 | if ($objectIdentifier->getType() != Identifier::OBJECT_IDENTIFIER) { 83 | throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Object Identifier but got '.$extension->getTypeName(), $tmpOffset); 84 | } 85 | 86 | $tmpOffset += $objectIdentifier->getObjectLength(); 87 | 88 | if ($objectIdentifier->getContent() == OID::CERT_EXT_SUBJECT_ALT_NAME) { 89 | $sans = SubjectAlternativeNames::fromBinary($binaryData, $tmpOffset); 90 | $parsedObject->addSubjectAlternativeNames($sans); 91 | } else { 92 | // can now only parse SANs. There might be more in the future 93 | $tmpOffset += $octetString->getObjectLength(); 94 | } 95 | } 96 | 97 | $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ ) 98 | return $parsedObject; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/X509/CertificateSubject.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509; 12 | 13 | use FG\ASN1\Composite\RelativeDistinguishedName; 14 | use FG\ASN1\Identifier; 15 | use FG\ASN1\OID; 16 | use FG\ASN1\Parsable; 17 | use FG\ASN1\Composite\RDNString; 18 | use FG\ASN1\Universal\Sequence; 19 | 20 | class CertificateSubject extends Sequence implements Parsable 21 | { 22 | private $commonName; 23 | private $email; 24 | private $organization; 25 | private $locality; 26 | private $state; 27 | private $country; 28 | private $organizationalUnit; 29 | 30 | /** 31 | * @param string $commonName 32 | * @param string $email 33 | * @param string $organization 34 | * @param string $locality 35 | * @param string $state 36 | * @param string $country 37 | * @param string $organizationalUnit 38 | */ 39 | public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit) 40 | { 41 | parent::__construct( 42 | new RDNString(OID::COUNTRY_NAME, $country), 43 | new RDNString(OID::STATE_OR_PROVINCE_NAME, $state), 44 | new RDNString(OID::LOCALITY_NAME, $locality), 45 | new RDNString(OID::ORGANIZATION_NAME, $organization), 46 | new RDNString(OID::OU_NAME, $organizationalUnit), 47 | new RDNString(OID::COMMON_NAME, $commonName), 48 | new RDNString(OID::PKCS9_EMAIL, $email) 49 | ); 50 | 51 | $this->commonName = $commonName; 52 | $this->email = $email; 53 | $this->organization = $organization; 54 | $this->locality = $locality; 55 | $this->state = $state; 56 | $this->country = $country; 57 | $this->organizationalUnit = $organizationalUnit; 58 | } 59 | 60 | public function getCommonName() 61 | { 62 | return $this->commonName; 63 | } 64 | 65 | public function getEmail() 66 | { 67 | return $this->email; 68 | } 69 | 70 | public function getOrganization() 71 | { 72 | return $this->organization; 73 | } 74 | 75 | public function getLocality() 76 | { 77 | return $this->locality; 78 | } 79 | 80 | public function getState() 81 | { 82 | return $this->state; 83 | } 84 | 85 | public function getCountry() 86 | { 87 | return $this->country; 88 | } 89 | 90 | public function getOrganizationalUnit() 91 | { 92 | return $this->organizationalUnit; 93 | } 94 | 95 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 96 | { 97 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++); 98 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 99 | 100 | $names = []; 101 | $octetsToRead = $contentLength; 102 | while ($octetsToRead > 0) { 103 | $relativeDistinguishedName = RelativeDistinguishedName::fromBinary($binaryData, $offsetIndex); 104 | $octetsToRead -= $relativeDistinguishedName->getObjectLength(); 105 | $names[] = $relativeDistinguishedName; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /lib/X509/PrivateKey.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509; 12 | 13 | use FG\ASN1\OID; 14 | use FG\ASN1\Universal\NullObject; 15 | use FG\ASN1\Universal\Sequence; 16 | use FG\ASN1\Universal\BitString; 17 | use FG\ASN1\Universal\ObjectIdentifier; 18 | 19 | class PrivateKey extends Sequence 20 | { 21 | /** 22 | * @param string $hexKey 23 | * @param \FG\ASN1\ASNObject|string $algorithmIdentifierString 24 | */ 25 | public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION) 26 | { 27 | parent::__construct( 28 | new Sequence( 29 | new ObjectIdentifier($algorithmIdentifierString), 30 | new NullObject() 31 | ), 32 | new BitString($hexKey) 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/X509/PublicKey.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509; 12 | 13 | use FG\ASN1\OID; 14 | use FG\ASN1\Universal\NullObject; 15 | use FG\ASN1\Universal\Sequence; 16 | use FG\ASN1\Universal\BitString; 17 | use FG\ASN1\Universal\ObjectIdentifier; 18 | 19 | class PublicKey extends Sequence 20 | { 21 | /** 22 | * @param string $hexKey 23 | * @param \FG\ASN1\ASNObject|string $algorithmIdentifierString 24 | */ 25 | public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION) 26 | { 27 | parent::__construct( 28 | new Sequence( 29 | new ObjectIdentifier($algorithmIdentifierString), 30 | new NullObject() 31 | ), 32 | new BitString($hexKey) 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/X509/SAN/DNSName.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509\SAN; 12 | 13 | use FG\ASN1\Universal\GeneralString; 14 | 15 | class DNSName extends GeneralString 16 | { 17 | const IDENTIFIER = 0x82; // not sure yet why this is the identifier used in SAN extensions 18 | 19 | public function __construct($dnsNameString) 20 | { 21 | parent::__construct($dnsNameString); 22 | } 23 | 24 | public function getType() 25 | { 26 | return self::IDENTIFIER; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/X509/SAN/IPAddress.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509\SAN; 12 | 13 | use FG\ASN1\ASNObject; 14 | use FG\ASN1\Parsable; 15 | use FG\ASN1\Exception\ParserException; 16 | 17 | class IPAddress extends ASNObject implements Parsable 18 | { 19 | const IDENTIFIER = 0x87; // not sure yet why this is the identifier used in SAN extensions 20 | 21 | /** @var string */ 22 | private $value; 23 | 24 | public function __construct($ipAddressString) 25 | { 26 | $this->value = $ipAddressString; 27 | } 28 | 29 | public function getType() 30 | { 31 | return self::IDENTIFIER; 32 | } 33 | 34 | public function getContent() 35 | { 36 | return $this->value; 37 | } 38 | 39 | protected function calculateContentLength() 40 | { 41 | return 4; 42 | } 43 | 44 | protected function getEncodedValue() 45 | { 46 | $ipParts = explode('.', $this->value); 47 | $binary = chr($ipParts[0]); 48 | $binary .= chr($ipParts[1]); 49 | $binary .= chr($ipParts[2]); 50 | $binary .= chr($ipParts[3]); 51 | 52 | return $binary; 53 | } 54 | 55 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 56 | { 57 | self::parseIdentifier($binaryData[$offsetIndex], self::IDENTIFIER, $offsetIndex++); 58 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 59 | if ($contentLength != 4) { 60 | throw new ParserException("A FG\\X509\SAN\IPAddress should have a content length of 4. Extracted length was {$contentLength}", $offsetIndex); 61 | } 62 | 63 | $ipAddressString = ord($binaryData[$offsetIndex++]).'.'; 64 | $ipAddressString .= ord($binaryData[$offsetIndex++]).'.'; 65 | $ipAddressString .= ord($binaryData[$offsetIndex++]).'.'; 66 | $ipAddressString .= ord($binaryData[$offsetIndex++]); 67 | 68 | $parsedObject = new self($ipAddressString); 69 | $parsedObject->getObjectLength(); 70 | 71 | return $parsedObject; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/X509/SAN/SubjectAlternativeNames.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace FG\X509\SAN; 12 | 13 | use FG\ASN1\Exception\ParserException; 14 | use FG\ASN1\ASNObject; 15 | use FG\ASN1\OID; 16 | use FG\ASN1\Parsable; 17 | use FG\ASN1\Identifier; 18 | use FG\ASN1\Universal\Sequence; 19 | 20 | /** 21 | * See section 8.3.2.1 of ITU-T X.509. 22 | */ 23 | class SubjectAlternativeNames extends ASNObject implements Parsable 24 | { 25 | private $alternativeNamesSequence; 26 | 27 | public function __construct() 28 | { 29 | $this->alternativeNamesSequence = new Sequence(); 30 | } 31 | 32 | protected function calculateContentLength() 33 | { 34 | return $this->alternativeNamesSequence->getObjectLength(); 35 | } 36 | 37 | public function getType() 38 | { 39 | return Identifier::OCTETSTRING; 40 | } 41 | 42 | public function addDomainName(DNSName $domainName) 43 | { 44 | $this->alternativeNamesSequence->addChild($domainName); 45 | } 46 | 47 | public function addIP(IPAddress $ip) 48 | { 49 | $this->alternativeNamesSequence->addChild($ip); 50 | } 51 | 52 | public function getContent() 53 | { 54 | return $this->alternativeNamesSequence->getContent(); 55 | } 56 | 57 | protected function getEncodedValue() 58 | { 59 | return $this->alternativeNamesSequence->getBinary(); 60 | } 61 | 62 | public static function fromBinary(&$binaryData, &$offsetIndex = 0) 63 | { 64 | self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++); 65 | $contentLength = self::parseContentLength($binaryData, $offsetIndex); 66 | 67 | if ($contentLength < 2) { 68 | throw new ParserException('Can not parse Subject Alternative Names: The Sequence within the octet string after the Object identifier '.OID::CERT_EXT_SUBJECT_ALT_NAME." is too short ({$contentLength} octets)", $offsetIndex); 69 | } 70 | 71 | $offsetOfSequence = $offsetIndex; 72 | $sequence = Sequence::fromBinary($binaryData, $offsetIndex); 73 | $offsetOfSequence += $sequence->getNumberOfLengthOctets() + 1; 74 | 75 | if ($sequence->getObjectLength() != $contentLength) { 76 | throw new ParserException('Can not parse Subject Alternative Names: The Sequence length does not match the length of the surrounding octet string', $offsetIndex); 77 | } 78 | 79 | $parsedObject = new self(); 80 | /** @var \FG\ASN1\ASNObject $object */ 81 | foreach ($sequence as $object) { 82 | if ($object->getType() == DNSName::IDENTIFIER) { 83 | $domainName = DNSName::fromBinary($binaryData, $offsetOfSequence); 84 | $parsedObject->addDomainName($domainName); 85 | } elseif ($object->getType() == IPAddress::IDENTIFIER) { 86 | $ip = IPAddress::fromBinary($binaryData, $offsetOfSequence); 87 | $parsedObject->addIP($ip); 88 | } else { 89 | throw new ParserException('Could not parse Subject Alternative Name: Only DNSName and IP SANs are currently supported', $offsetIndex); 90 | } 91 | } 92 | 93 | $parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ ) 94 | return $parsedObject; 95 | } 96 | } 97 | --------------------------------------------------------------------------------