Subversion Repositories oidplus

Rev

Rev 846 | Rev 1042 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /**
  4.  * Pure-PHP ASN.1 Parser
  5.  *
  6.  * PHP version 5
  7.  *
  8.  * ASN.1 provides the semantics for data encoded using various schemes.  The most commonly
  9.  * utilized scheme is DER or the "Distinguished Encoding Rules".  PEM's are base64 encoded
  10.  * DER blobs.
  11.  *
  12.  * \phpseclib3\File\ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
  13.  *
  14.  * Uses the 1988 ASN.1 syntax.
  15.  *
  16.  * @category  File
  17.  * @package   ASN1
  18.  * @author    Jim Wigginton <terrafrost@php.net>
  19.  * @copyright 2012 Jim Wigginton
  20.  * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  21.  * @link      http://phpseclib.sourceforge.net
  22.  */
  23.  
  24. namespace phpseclib3\File;
  25.  
  26. use DateTime;
  27. use ParagonIE\ConstantTime\Base64;
  28. use phpseclib3\Common\Functions\Strings;
  29. use phpseclib3\File\ASN1\Element;
  30. use phpseclib3\Math\BigInteger;
  31.  
  32. /**
  33.  * Pure-PHP ASN.1 Parser
  34.  *
  35.  * @package ASN1
  36.  * @author  Jim Wigginton <terrafrost@php.net>
  37.  * @access  public
  38.  */
  39. abstract class ASN1
  40. {
  41.     // Tag Classes
  42.     // http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
  43.     const CLASS_UNIVERSAL        = 0;
  44.     const CLASS_APPLICATION      = 1;
  45.     const CLASS_CONTEXT_SPECIFIC = 2;
  46.     const CLASS_PRIVATE          = 3;
  47.  
  48.     // Tag Classes
  49.     // http://www.obj-sys.com/asn1tutorial/node124.html
  50.     const TYPE_BOOLEAN           = 1;
  51.     const TYPE_INTEGER           = 2;
  52.     const TYPE_BIT_STRING        = 3;
  53.     const TYPE_OCTET_STRING      = 4;
  54.     const TYPE_NULL              = 5;
  55.     const TYPE_OBJECT_IDENTIFIER = 6;
  56.     //const TYPE_OBJECT_DESCRIPTOR = 7;
  57.     //const TYPE_INSTANCE_OF       = 8; // EXTERNAL
  58.     const TYPE_REAL              = 9;
  59.     const TYPE_ENUMERATED        = 10;
  60.     //const TYPE_EMBEDDED          = 11;
  61.     const TYPE_UTF8_STRING       = 12;
  62.     //const TYPE_RELATIVE_OID      = 13;
  63.     const TYPE_SEQUENCE          = 16; // SEQUENCE OF
  64.     const TYPE_SET               = 17; // SET OF
  65.  
  66.     // More Tag Classes
  67.     // http://www.obj-sys.com/asn1tutorial/node10.html
  68.     const TYPE_NUMERIC_STRING   = 18;
  69.     const TYPE_PRINTABLE_STRING = 19;
  70.     const TYPE_TELETEX_STRING   = 20; // T61String
  71.     const TYPE_VIDEOTEX_STRING  = 21;
  72.     const TYPE_IA5_STRING       = 22;
  73.     const TYPE_UTC_TIME         = 23;
  74.     const TYPE_GENERALIZED_TIME = 24;
  75.     const TYPE_GRAPHIC_STRING   = 25;
  76.     const TYPE_VISIBLE_STRING   = 26; // ISO646String
  77.     const TYPE_GENERAL_STRING   = 27;
  78.     const TYPE_UNIVERSAL_STRING = 28;
  79.     //const TYPE_CHARACTER_STRING = 29;
  80.     const TYPE_BMP_STRING       = 30;
  81.  
  82.     // Tag Aliases
  83.     // These tags are kinda place holders for other tags.
  84.     const TYPE_CHOICE = -1;
  85.     const TYPE_ANY    = -2;
  86.  
  87.     /**
  88.      * ASN.1 object identifiers
  89.      *
  90.      * @var array
  91.      * @access private
  92.      * @link http://en.wikipedia.org/wiki/Object_identifier
  93.      */
  94.     private static $oids = [];
  95.  
  96.     /**
  97.      * ASN.1 object identifier reverse mapping
  98.      *
  99.      * @var array
  100.      * @access private
  101.      */
  102.     private static $reverseOIDs = [];
  103.  
  104.     /**
  105.      * Default date format
  106.      *
  107.      * @var string
  108.      * @access private
  109.      * @link http://php.net/class.datetime
  110.      */
  111.     private static $format = 'D, d M Y H:i:s O';
  112.  
  113.     /**
  114.      * Filters
  115.      *
  116.      * If the mapping type is self::TYPE_ANY what do we actually encode it as?
  117.      *
  118.      * @var array
  119.      * @access private
  120.      * @see self::encode_der()
  121.      */
  122.     private static $filters;
  123.  
  124.     /**
  125.      * Current Location of most recent ASN.1 encode process
  126.      *
  127.      * Useful for debug purposes
  128.      *
  129.      * @var array
  130.      * @access private
  131.      * @see self::encode_der()
  132.      */
  133.     private static $location;
  134.  
  135.     /**
  136.      * DER Encoded String
  137.      *
  138.      * In case we need to create ASN1\Element object's..
  139.      *
  140.      * @var string
  141.      * @access private
  142.      * @see self::decodeDER()
  143.      */
  144.     private static $encoded;
  145.  
  146.     /**
  147.      * Type mapping table for the ANY type.
  148.      *
  149.      * Structured or unknown types are mapped to a \phpseclib3\File\ASN1\Element.
  150.      * Unambiguous types get the direct mapping (int/real/bool).
  151.      * Others are mapped as a choice, with an extra indexing level.
  152.      *
  153.      * @var array
  154.      * @access public
  155.      */
  156.     const ANY_MAP = [
  157.         self::TYPE_BOOLEAN              => true,
  158.         self::TYPE_INTEGER              => true,
  159.         self::TYPE_BIT_STRING           => 'bitString',
  160.         self::TYPE_OCTET_STRING         => 'octetString',
  161.         self::TYPE_NULL                 => 'null',
  162.         self::TYPE_OBJECT_IDENTIFIER    => 'objectIdentifier',
  163.         self::TYPE_REAL                 => true,
  164.         self::TYPE_ENUMERATED           => 'enumerated',
  165.         self::TYPE_UTF8_STRING          => 'utf8String',
  166.         self::TYPE_NUMERIC_STRING       => 'numericString',
  167.         self::TYPE_PRINTABLE_STRING     => 'printableString',
  168.         self::TYPE_TELETEX_STRING       => 'teletexString',
  169.         self::TYPE_VIDEOTEX_STRING      => 'videotexString',
  170.         self::TYPE_IA5_STRING           => 'ia5String',
  171.         self::TYPE_UTC_TIME             => 'utcTime',
  172.         self::TYPE_GENERALIZED_TIME     => 'generalTime',
  173.         self::TYPE_GRAPHIC_STRING       => 'graphicString',
  174.         self::TYPE_VISIBLE_STRING       => 'visibleString',
  175.         self::TYPE_GENERAL_STRING       => 'generalString',
  176.         self::TYPE_UNIVERSAL_STRING     => 'universalString',
  177.         //self::TYPE_CHARACTER_STRING     => 'characterString',
  178.         self::TYPE_BMP_STRING           => 'bmpString'
  179.     ];
  180.  
  181.     /**
  182.      * String type to character size mapping table.
  183.      *
  184.      * Non-convertable types are absent from this table.
  185.      * size == 0 indicates variable length encoding.
  186.      *
  187.      * @var array
  188.      * @access public
  189.      */
  190.     const STRING_TYPE_SIZE = [
  191.         self::TYPE_UTF8_STRING      => 0,
  192.         self::TYPE_BMP_STRING       => 2,
  193.         self::TYPE_UNIVERSAL_STRING => 4,
  194.         self::TYPE_PRINTABLE_STRING => 1,
  195.         self::TYPE_TELETEX_STRING   => 1,
  196.         self::TYPE_IA5_STRING       => 1,
  197.         self::TYPE_VISIBLE_STRING   => 1,
  198.     ];
  199.  
  200.     /**
  201.      * Parse BER-encoding
  202.      *
  203.      * Serves a similar purpose to openssl's asn1parse
  204.      *
  205.      * @param Element|string $encoded
  206.      * @return array
  207.      * @access public
  208.      */
  209.     public static function decodeBER($encoded)
  210.     {
  211.         if ($encoded instanceof Element) {
  212.             $encoded = $encoded->element;
  213.         }
  214.  
  215.         self::$encoded = $encoded;
  216.  
  217.         $decoded = [self::decode_ber($encoded)];
  218.  
  219.         // encapsulate in an array for BC with the old decodeBER
  220.         return $decoded;
  221.     }
  222.  
  223.     /**
  224.      * Parse BER-encoding (Helper function)
  225.      *
  226.      * Sometimes we want to get the BER encoding of a particular tag.  $start lets us do that without having to reencode.
  227.      * $encoded is passed by reference for the recursive calls done for self::TYPE_BIT_STRING and
  228.      * self::TYPE_OCTET_STRING. In those cases, the indefinite length is used.
  229.      *
  230.      * @param string $encoded
  231.      * @param int $start
  232.      * @param int $encoded_pos
  233.      * @return array|bool
  234.      * @access private
  235.      */
  236.     private static function decode_ber($encoded, $start = 0, $encoded_pos = 0)
  237.     {
  238.         $current = ['start' => $start];
  239.  
  240.         if (!isset($encoded[$encoded_pos])) {
  241.             return false;
  242.         }
  243.         $type = ord($encoded[$encoded_pos++]);
  244.         $startOffset = 1;
  245.  
  246.         $constructed = ($type >> 5) & 1;
  247.  
  248.         $tag = $type & 0x1F;
  249.         if ($tag == 0x1F) {
  250.             $tag = 0;
  251.             // process septets (since the eighth bit is ignored, it's not an octet)
  252.             do {
  253.                 if (!isset($encoded[$encoded_pos])) {
  254.                     return false;
  255.                 }
  256.                 $temp = ord($encoded[$encoded_pos++]);
  257.                 $startOffset++;
  258.                 $loop = $temp >> 7;
  259.                 $tag <<= 7;
  260.                 $temp &= 0x7F;
  261.                 // "bits 7 to 1 of the first subsequent octet shall not all be zero"
  262.                 if ($startOffset == 2 && $temp == 0) {
  263.                     return false;
  264.                 }
  265.                 $tag |= $temp;
  266.             } while ($loop);
  267.         }
  268.  
  269.         $start += $startOffset;
  270.  
  271.         // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
  272.         if (!isset($encoded[$encoded_pos])) {
  273.             return false;
  274.         }
  275.         $length = ord($encoded[$encoded_pos++]);
  276.         $start++;
  277.         if ($length == 0x80) { // indefinite length
  278.             // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
  279.             //  immediately available." -- paragraph 8.1.3.2.c
  280.             $length = strlen($encoded) - $encoded_pos;
  281.         } elseif ($length & 0x80) { // definite length, long form
  282.             // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
  283.             // support it up to four.
  284.             $length &= 0x7F;
  285.             $temp = substr($encoded, $encoded_pos, $length);
  286.             $encoded_pos += $length;
  287.             // tags of indefinte length don't really have a header length; this length includes the tag
  288.             $current += ['headerlength' => $length + 2];
  289.             $start += $length;
  290.             extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
  291.             /** @var integer $length */
  292.         } else {
  293.             $current += ['headerlength' => 2];
  294.         }
  295.  
  296.         if ($length > (strlen($encoded) - $encoded_pos)) {
  297.             return false;
  298.         }
  299.  
  300.         $content = substr($encoded, $encoded_pos, $length);
  301.         $content_pos = 0;
  302.  
  303.         // at this point $length can be overwritten. it's only accurate for definite length things as is
  304.  
  305.         /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
  306.            built-in types. It defines an application-independent data type that must be distinguishable from all other
  307.            data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
  308.            have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
  309.            a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
  310.            alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
  311.            data type; the term CONTEXT-SPECIFIC does not appear.
  312.  
  313.              -- http://www.obj-sys.com/asn1tutorial/node12.html */
  314.         $class = ($type >> 6) & 3;
  315.         switch ($class) {
  316.             case self::CLASS_APPLICATION:
  317.             case self::CLASS_PRIVATE:
  318.             case self::CLASS_CONTEXT_SPECIFIC:
  319.                 if (!$constructed) {
  320.                     return [
  321.                         'type'     => $class,
  322.                         'constant' => $tag,
  323.                         'content'  => $content,
  324.                         'length'   => $length + $start - $current['start']
  325.                     ] + $current;
  326.                 }
  327.  
  328.                 $newcontent = [];
  329.                 $remainingLength = $length;
  330.                 while ($remainingLength > 0) {
  331.                     $temp = self::decode_ber($content, $start, $content_pos);
  332.                     if ($temp === false) {
  333.                         break;
  334.                     }
  335.                     $length = $temp['length'];
  336.                     // end-of-content octets - see paragraph 8.1.5
  337.                     if (substr($content, $content_pos + $length, 2) == "\0\0") {
  338.                         $length += 2;
  339.                         $start += $length;
  340.                         $newcontent[] = $temp;
  341.                         break;
  342.                     }
  343.                     $start += $length;
  344.                     $remainingLength -= $length;
  345.                     $newcontent[] = $temp;
  346.                     $content_pos += $length;
  347.                 }
  348.  
  349.                 return [
  350.                     'type'     => $class,
  351.                     'constant' => $tag,
  352.                     // the array encapsulation is for BC with the old format
  353.                     'content'  => $newcontent,
  354.                     // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
  355.                     // the absence of $content['headerlength'] is how we know if something is indefinite or not.
  356.                     // technically, it could be defined to be 2 and then another indicator could be used but whatever.
  357.                     'length'   => $start - $current['start']
  358.                 ] + $current;
  359.         }
  360.  
  361.         $current += ['type' => $tag];
  362.  
  363.         // decode UNIVERSAL tags
  364.         switch ($tag) {
  365.             case self::TYPE_BOOLEAN:
  366.                 // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
  367.                 if ($constructed || strlen($content) != 1) {
  368.                     return false;
  369.                 }
  370.                 $current['content'] = (bool) ord($content[$content_pos]);
  371.                 break;
  372.             case self::TYPE_INTEGER:
  373.             case self::TYPE_ENUMERATED:
  374.                 if ($constructed) {
  375.                     return false;
  376.                 }
  377.                 $current['content'] = new BigInteger(substr($content, $content_pos), -256);
  378.                 break;
  379.             case self::TYPE_REAL: // not currently supported
  380.                 return false;
  381.             case self::TYPE_BIT_STRING:
  382.                 // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
  383.                 // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
  384.                 // seven.
  385.                 if (!$constructed) {
  386.                     $current['content'] = substr($content, $content_pos);
  387.                 } else {
  388.                     $temp = self::decode_ber($content, $start, $content_pos);
  389.                     if ($temp === false) {
  390.                         return false;
  391.                     }
  392.                     $length -= (strlen($content) - $content_pos);
  393.                     $last = count($temp) - 1;
  394.                     for ($i = 0; $i < $last; $i++) {
  395.                         // all subtags should be bit strings
  396.                         if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
  397.                             return false;
  398.                         }
  399.                         $current['content'] .= substr($temp[$i]['content'], 1);
  400.                     }
  401.                     // all subtags should be bit strings
  402.                     if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
  403.                         return false;
  404.                     }
  405.                     $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
  406.                 }
  407.                 break;
  408.             case self::TYPE_OCTET_STRING:
  409.                 if (!$constructed) {
  410.                     $current['content'] = substr($content, $content_pos);
  411.                 } else {
  412.                     $current['content'] = '';
  413.                     $length = 0;
  414.                     while (substr($content, $content_pos, 2) != "\0\0") {
  415.                         $temp = self::decode_ber($content, $length + $start, $content_pos);
  416.                         if ($temp === false) {
  417.                             return false;
  418.                         }
  419.                         $content_pos += $temp['length'];
  420.                         // all subtags should be octet strings
  421.                         if ($temp['type'] != self::TYPE_OCTET_STRING) {
  422.                             return false;
  423.                         }
  424.                         $current['content'] .= $temp['content'];
  425.                         $length += $temp['length'];
  426.                     }
  427.                     if (substr($content, $content_pos, 2) == "\0\0") {
  428.                         $length += 2; // +2 for the EOC
  429.                     }
  430.                 }
  431.                 break;
  432.             case self::TYPE_NULL:
  433.                 // "The contents octets shall not contain any octets." -- paragraph 8.8.2
  434.                 if ($constructed || strlen($content)) {
  435.                     return false;
  436.                 }
  437.                 break;
  438.             case self::TYPE_SEQUENCE:
  439.             case self::TYPE_SET:
  440.                 if (!$constructed) {
  441.                     return false;
  442.                 }
  443.                 $offset = 0;
  444.                 $current['content'] = [];
  445.                 $content_len = strlen($content);
  446.                 while ($content_pos < $content_len) {
  447.                     // if indefinite length construction was used and we have an end-of-content string next
  448.                     // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
  449.                     if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
  450.                         $length = $offset + 2; // +2 for the EOC
  451.                         break 2;
  452.                     }
  453.                     $temp = self::decode_ber($content, $start + $offset, $content_pos);
  454.                     if ($temp === false) {
  455.                         return false;
  456.                     }
  457.                     $content_pos += $temp['length'];
  458.                     $current['content'][] = $temp;
  459.                     $offset += $temp['length'];
  460.                 }
  461.                 break;
  462.             case self::TYPE_OBJECT_IDENTIFIER:
  463.                 if ($constructed) {
  464.                     return false;
  465.                 }
  466.                 $current['content'] = self::decodeOID(substr($content, $content_pos));
  467.                 if ($current['content'] === false) {
  468.                     return false;
  469.                 }
  470.                 break;
  471.             /* Each character string type shall be encoded as if it had been declared:
  472.                [UNIVERSAL x] IMPLICIT OCTET STRING
  473.  
  474.                  -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
  475.  
  476.                Per that, we're not going to do any validation.  If there are any illegal characters in the string,
  477.                we don't really care */
  478.             case self::TYPE_NUMERIC_STRING:
  479.                 // 0,1,2,3,4,5,6,7,8,9, and space
  480.             case self::TYPE_PRINTABLE_STRING:
  481.                 // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
  482.                 // hyphen, full stop, solidus, colon, equal sign, question mark
  483.             case self::TYPE_TELETEX_STRING:
  484.                 // The Teletex character set in CCITT's T61, space, and delete
  485.                 // see http://en.wikipedia.org/wiki/Teletex#Character_sets
  486.             case self::TYPE_VIDEOTEX_STRING:
  487.                 // The Videotex character set in CCITT's T.100 and T.101, space, and delete
  488.             case self::TYPE_VISIBLE_STRING:
  489.                 // Printing character sets of international ASCII, and space
  490.             case self::TYPE_IA5_STRING:
  491.                 // International Alphabet 5 (International ASCII)
  492.             case self::TYPE_GRAPHIC_STRING:
  493.                 // All registered G sets, and space
  494.             case self::TYPE_GENERAL_STRING:
  495.                 // All registered C and G sets, space and delete
  496.             case self::TYPE_UTF8_STRING:
  497.                 // ????
  498.             case self::TYPE_BMP_STRING:
  499.                 if ($constructed) {
  500.                     return false;
  501.                 }
  502.                 $current['content'] = substr($content, $content_pos);
  503.                 break;
  504.             case self::TYPE_UTC_TIME:
  505.             case self::TYPE_GENERALIZED_TIME:
  506.                 if ($constructed) {
  507.                     return false;
  508.                 }
  509.                 $current['content'] = self::decodeTime(substr($content, $content_pos), $tag);
  510.                 break;
  511.             default:
  512.                 return false;
  513.         }
  514.  
  515.         $start += $length;
  516.  
  517.         // ie. length is the length of the full TLV encoding - it's not just the length of the value
  518.         return $current + ['length' => $start - $current['start']];
  519.     }
  520.  
  521.     /**
  522.      * ASN.1 Map
  523.      *
  524.      * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
  525.      *
  526.      * "Special" mappings may be applied on a per tag-name basis via $special.
  527.      *
  528.      * @param array $decoded
  529.      * @param array $mapping
  530.      * @param array $special
  531.      * @return array|bool|Element|string|null
  532.      * @access public
  533.      */
  534.     public static function asn1map($decoded, $mapping, $special = [])
  535.     {
  536.         if (!is_array($decoded)) {
  537.             return false;
  538.         }
  539.  
  540.         if (isset($mapping['explicit']) && is_array($decoded['content'])) {
  541.             $decoded = $decoded['content'][0];
  542.         }
  543.  
  544.         switch (true) {
  545.             case $mapping['type'] == self::TYPE_ANY:
  546.                 $intype = $decoded['type'];
  547.                 // !isset(self::ANY_MAP[$intype]) produces a fatal error on PHP 5.6
  548.                 if (isset($decoded['constant']) || !array_key_exists($intype, self::ANY_MAP) || (ord(self::$encoded[$decoded['start']]) & 0x20)) {
  549.                     return new Element(substr(self::$encoded, $decoded['start'], $decoded['length']));
  550.                 }
  551.                 $inmap = self::ANY_MAP[$intype];
  552.                 if (is_string($inmap)) {
  553.                     return [$inmap => self::asn1map($decoded, ['type' => $intype] + $mapping, $special)];
  554.                 }
  555.                 break;
  556.             case $mapping['type'] == self::TYPE_CHOICE:
  557.                 foreach ($mapping['children'] as $key => $option) {
  558.                     switch (true) {
  559.                         case isset($option['constant']) && $option['constant'] == $decoded['constant']:
  560.                         case !isset($option['constant']) && $option['type'] == $decoded['type']:
  561.                             $value = self::asn1map($decoded, $option, $special);
  562.                             break;
  563.                         case !isset($option['constant']) && $option['type'] == self::TYPE_CHOICE:
  564.                             $v = self::asn1map($decoded, $option, $special);
  565.                             if (isset($v)) {
  566.                                 $value = $v;
  567.                             }
  568.                     }
  569.                     if (isset($value)) {
  570.                         if (isset($special[$key])) {
  571.                             $value = $special[$key]($value);
  572.                         }
  573.                         return [$key => $value];
  574.                     }
  575.                 }
  576.                 return null;
  577.             case isset($mapping['implicit']):
  578.             case isset($mapping['explicit']):
  579.             case $decoded['type'] == $mapping['type']:
  580.                 break;
  581.             default:
  582.                 // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
  583.                 // let it through
  584.                 switch (true) {
  585.                     case $decoded['type'] < 18: // self::TYPE_NUMERIC_STRING == 18
  586.                     case $decoded['type'] > 30: // self::TYPE_BMP_STRING == 30
  587.                     case $mapping['type'] < 18:
  588.                     case $mapping['type'] > 30:
  589.                         return null;
  590.                 }
  591.         }
  592.  
  593.         if (isset($mapping['implicit'])) {
  594.             $decoded['type'] = $mapping['type'];
  595.         }
  596.  
  597.         switch ($decoded['type']) {
  598.             case self::TYPE_SEQUENCE:
  599.                 $map = [];
  600.  
  601.                 // ignore the min and max
  602.                 if (isset($mapping['min']) && isset($mapping['max'])) {
  603.                     $child = $mapping['children'];
  604.                     foreach ($decoded['content'] as $content) {
  605.                         if (($map[] = self::asn1map($content, $child, $special)) === null) {
  606.                             return null;
  607.                         }
  608.                     }
  609.  
  610.                     return $map;
  611.                 }
  612.  
  613.                 $n = count($decoded['content']);
  614.                 $i = 0;
  615.  
  616.                 foreach ($mapping['children'] as $key => $child) {
  617.                     $maymatch = $i < $n; // Match only existing input.
  618.                     if ($maymatch) {
  619.                         $temp = $decoded['content'][$i];
  620.  
  621.                         if ($child['type'] != self::TYPE_CHOICE) {
  622.                             // Get the mapping and input class & constant.
  623.                             $childClass = $tempClass = self::CLASS_UNIVERSAL;
  624.                             $constant = null;
  625.                             if (isset($temp['constant'])) {
  626.                                 $tempClass = $temp['type'];
  627.                             }
  628.                             if (isset($child['class'])) {
  629.                                 $childClass = $child['class'];
  630.                                 $constant = $child['cast'];
  631.                             } elseif (isset($child['constant'])) {
  632.                                 $childClass = self::CLASS_CONTEXT_SPECIFIC;
  633.                                 $constant = $child['constant'];
  634.                             }
  635.  
  636.                             if (isset($constant) && isset($temp['constant'])) {
  637.                                 // Can only match if constants and class match.
  638.                                 $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
  639.                             } else {
  640.                                 // Can only match if no constant expected and type matches or is generic.
  641.                                 $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false;
  642.                             }
  643.                         }
  644.                     }
  645.  
  646.                     if ($maymatch) {
  647.                         // Attempt submapping.
  648.                         $candidate = self::asn1map($temp, $child, $special);
  649.                         $maymatch = $candidate !== null;
  650.                     }
  651.  
  652.                     if ($maymatch) {
  653.                         // Got the match: use it.
  654.                         if (isset($special[$key])) {
  655.                             $candidate = $special[$key]($candidate);
  656.                         }
  657.                         $map[$key] = $candidate;
  658.                         $i++;
  659.                     } elseif (isset($child['default'])) {
  660.                         $map[$key] = $child['default'];
  661.                     } elseif (!isset($child['optional'])) {
  662.                         return null; // Syntax error.
  663.                     }
  664.                 }
  665.  
  666.                 // Fail mapping if all input items have not been consumed.
  667.                 return $i < $n ? null : $map;
  668.  
  669.             // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
  670.             case self::TYPE_SET:
  671.                 $map = [];
  672.  
  673.                 // ignore the min and max
  674.                 if (isset($mapping['min']) && isset($mapping['max'])) {
  675.                     $child = $mapping['children'];
  676.                     foreach ($decoded['content'] as $content) {
  677.                         if (($map[] = self::asn1map($content, $child, $special)) === null) {
  678.                             return null;
  679.                         }
  680.                     }
  681.  
  682.                     return $map;
  683.                 }
  684.  
  685.                 for ($i = 0; $i < count($decoded['content']); $i++) {
  686.                     $temp = $decoded['content'][$i];
  687.                     $tempClass = self::CLASS_UNIVERSAL;
  688.                     if (isset($temp['constant'])) {
  689.                         $tempClass = $temp['type'];
  690.                     }
  691.  
  692.                     foreach ($mapping['children'] as $key => $child) {
  693.                         if (isset($map[$key])) {
  694.                             continue;
  695.                         }
  696.                         $maymatch = true;
  697.                         if ($child['type'] != self::TYPE_CHOICE) {
  698.                             $childClass = self::CLASS_UNIVERSAL;
  699.                             $constant = null;
  700.                             if (isset($child['class'])) {
  701.                                 $childClass = $child['class'];
  702.                                 $constant = $child['cast'];
  703.                             } elseif (isset($child['constant'])) {
  704.                                 $childClass = self::CLASS_CONTEXT_SPECIFIC;
  705.                                 $constant = $child['constant'];
  706.                             }
  707.  
  708.                             if (isset($constant) && isset($temp['constant'])) {
  709.                                 // Can only match if constants and class match.
  710.                                 $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
  711.                             } else {
  712.                                 // Can only match if no constant expected and type matches or is generic.
  713.                                 $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false;
  714.                             }
  715.                         }
  716.  
  717.                         if ($maymatch) {
  718.                             // Attempt submapping.
  719.                             $candidate = self::asn1map($temp, $child, $special);
  720.                             $maymatch = $candidate !== null;
  721.                         }
  722.  
  723.                         if (!$maymatch) {
  724.                             break;
  725.                         }
  726.  
  727.                         // Got the match: use it.
  728.                         if (isset($special[$key])) {
  729.                             $candidate = $special[$key]($candidate);
  730.                         }
  731.                         $map[$key] = $candidate;
  732.                         break;
  733.                     }
  734.                 }
  735.  
  736.                 foreach ($mapping['children'] as $key => $child) {
  737.                     if (!isset($map[$key])) {
  738.                         if (isset($child['default'])) {
  739.                             $map[$key] = $child['default'];
  740.                         } elseif (!isset($child['optional'])) {
  741.                             return null;
  742.                         }
  743.                     }
  744.                 }
  745.                 return $map;
  746.             case self::TYPE_OBJECT_IDENTIFIER:
  747.                 return isset(self::$oids[$decoded['content']]) ? self::$oids[$decoded['content']] : $decoded['content'];
  748.             case self::TYPE_UTC_TIME:
  749.             case self::TYPE_GENERALIZED_TIME:
  750.                 // for explicitly tagged optional stuff
  751.                 if (is_array($decoded['content'])) {
  752.                     $decoded['content'] = $decoded['content'][0]['content'];
  753.                 }
  754.                 // for implicitly tagged optional stuff
  755.                 // in theory, doing isset($mapping['implicit']) would work but malformed certs do exist
  756.                 // in the wild that OpenSSL decodes without issue so we'll support them as well
  757.                 if (!is_object($decoded['content'])) {
  758.                     $decoded['content'] = self::decodeTime($decoded['content'], $decoded['type']);
  759.                 }
  760.                 return $decoded['content'] ? $decoded['content']->format(self::$format) : false;
  761.             case self::TYPE_BIT_STRING:
  762.                 if (isset($mapping['mapping'])) {
  763.                     $offset = ord($decoded['content'][0]);
  764.                     $size = (strlen($decoded['content']) - 1) * 8 - $offset;
  765.                     /*
  766.                        From X.680-0207.pdf#page=46 (21.7):
  767.  
  768.                        "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
  769.                         arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
  770.                         therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
  771.                         0 bits."
  772.                     */
  773.                     $bits = count($mapping['mapping']) == $size ? [] : array_fill(0, count($mapping['mapping']) - $size, false);
  774.                     for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
  775.                         $current = ord($decoded['content'][$i]);
  776.                         for ($j = $offset; $j < 8; $j++) {
  777.                             $bits[] = (bool) ($current & (1 << $j));
  778.                         }
  779.                         $offset = 0;
  780.                     }
  781.                     $values = [];
  782.                     $map = array_reverse($mapping['mapping']);
  783.                     foreach ($map as $i => $value) {
  784.                         if ($bits[$i]) {
  785.                             $values[] = $value;
  786.                         }
  787.                     }
  788.                     return $values;
  789.                 }
  790.                 // fall-through
  791.             case self::TYPE_OCTET_STRING:
  792.                 return $decoded['content'];
  793.             case self::TYPE_NULL:
  794.                 return '';
  795.             case self::TYPE_BOOLEAN:
  796.             case self::TYPE_NUMERIC_STRING:
  797.             case self::TYPE_PRINTABLE_STRING:
  798.             case self::TYPE_TELETEX_STRING:
  799.             case self::TYPE_VIDEOTEX_STRING:
  800.             case self::TYPE_IA5_STRING:
  801.             case self::TYPE_GRAPHIC_STRING:
  802.             case self::TYPE_VISIBLE_STRING:
  803.             case self::TYPE_GENERAL_STRING:
  804.             case self::TYPE_UNIVERSAL_STRING:
  805.             case self::TYPE_UTF8_STRING:
  806.             case self::TYPE_BMP_STRING:
  807.                 return $decoded['content'];
  808.             case self::TYPE_INTEGER:
  809.             case self::TYPE_ENUMERATED:
  810.                 $temp = $decoded['content'];
  811.                 if (isset($mapping['implicit'])) {
  812.                     $temp = new BigInteger($decoded['content'], -256);
  813.                 }
  814.                 if (isset($mapping['mapping'])) {
  815.                     $temp = (int) $temp->toString();
  816.                     return isset($mapping['mapping'][$temp]) ?
  817.                         $mapping['mapping'][$temp] :
  818.                         false;
  819.                 }
  820.                 return $temp;
  821.         }
  822.     }
  823.  
  824.     /**
  825.      * DER-decode the length
  826.      *
  827.      * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
  828.      * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
  829.      *
  830.      * @access public
  831.      * @param string $string
  832.      * @return int
  833.      */
  834.     public static function decodeLength(&$string)
  835.     {
  836.         $length = ord(Strings::shift($string));
  837.         if ($length & 0x80) { // definite length, long form
  838.             $length &= 0x7F;
  839.             $temp = Strings::shift($string, $length);
  840.             list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
  841.         }
  842.         return $length;
  843.     }
  844.  
  845.     /**
  846.      * ASN.1 Encode
  847.      *
  848.      * DER-encodes an ASN.1 semantic mapping ($mapping).  Some libraries would probably call this function
  849.      * an ASN.1 compiler.
  850.      *
  851.      * "Special" mappings can be applied via $special.
  852.      *
  853.      * @param Element|string|array $source
  854.      * @param array $mapping
  855.      * @param array $special
  856.      * @return string
  857.      * @access public
  858.      */
  859.     public static function encodeDER($source, $mapping, $special = [])
  860.     {
  861.         self::$location = [];
  862.         return self::encode_der($source, $mapping, null, $special);
  863.     }
  864.  
  865.     /**
  866.      * ASN.1 Encode (Helper function)
  867.      *
  868.      * @param Element|string|array|null $source
  869.      * @param array $mapping
  870.      * @param int $idx
  871.      * @param array $special
  872.      * @return string
  873.      * @access private
  874.      */
  875.     private static function encode_der($source, $mapping, $idx = null, $special = [])
  876.     {
  877.         if ($source instanceof Element) {
  878.             return $source->element;
  879.         }
  880.  
  881.         // do not encode (implicitly optional) fields with value set to default
  882.         if (isset($mapping['default']) && $source === $mapping['default']) {
  883.             return '';
  884.         }
  885.  
  886.         if (isset($idx)) {
  887.             if (isset($special[$idx])) {
  888.                 $source = $special[$idx]($source);
  889.             }
  890.             self::$location[] = $idx;
  891.         }
  892.  
  893.         $tag = $mapping['type'];
  894.  
  895.         switch ($tag) {
  896.             case self::TYPE_SET:    // Children order is not important, thus process in sequence.
  897.             case self::TYPE_SEQUENCE:
  898.                 $tag |= 0x20; // set the constructed bit
  899.  
  900.                 // ignore the min and max
  901.                 if (isset($mapping['min']) && isset($mapping['max'])) {
  902.                     $value = [];
  903.                     $child = $mapping['children'];
  904.  
  905.                     foreach ($source as $content) {
  906.                         $temp = self::encode_der($content, $child, null, $special);
  907.                         if ($temp === false) {
  908.                             return false;
  909.                         }
  910.                         $value[] = $temp;
  911.                     }
  912.                     /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
  913.                         as octet strings with the shorter components being padded at their trailing end with 0-octets.
  914.                         NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
  915.  
  916.                        -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf  */
  917.                     if ($mapping['type'] == self::TYPE_SET) {
  918.                         sort($value);
  919.                     }
  920.                     $value = implode('', $value);
  921.                     break;
  922.                 }
  923.  
  924.                 $value = '';
  925.                 foreach ($mapping['children'] as $key => $child) {
  926.                     if (!array_key_exists($key, $source)) {
  927.                         if (!isset($child['optional'])) {
  928.                             return false;
  929.                         }
  930.                         continue;
  931.                     }
  932.  
  933.                     $temp = self::encode_der($source[$key], $child, $key, $special);
  934.                     if ($temp === false) {
  935.                         return false;
  936.                     }
  937.  
  938.                     // An empty child encoding means it has been optimized out.
  939.                     // Else we should have at least one tag byte.
  940.                     if ($temp === '') {
  941.                         continue;
  942.                     }
  943.  
  944.                     // if isset($child['constant']) is true then isset($child['optional']) should be true as well
  945.                     if (isset($child['constant'])) {
  946.                         /*
  947.                            From X.680-0207.pdf#page=58 (30.6):
  948.  
  949.                            "The tagging construction specifies explicit tagging if any of the following holds:
  950.                             ...
  951.                             c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
  952.                             AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
  953.                             an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
  954.                          */
  955.                         if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
  956.                             $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
  957.                             $temp = $subtag . self::encodeLength(strlen($temp)) . $temp;
  958.                         } else {
  959.                             $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
  960.                             $temp = $subtag . substr($temp, 1);
  961.                         }
  962.                     }
  963.                     $value .= $temp;
  964.                 }
  965.                 break;
  966.             case self::TYPE_CHOICE:
  967.                 $temp = false;
  968.  
  969.                 foreach ($mapping['children'] as $key => $child) {
  970.                     if (!isset($source[$key])) {
  971.                         continue;
  972.                     }
  973.  
  974.                     $temp = self::encode_der($source[$key], $child, $key, $special);
  975.                     if ($temp === false) {
  976.                         return false;
  977.                     }
  978.  
  979.                     // An empty child encoding means it has been optimized out.
  980.                     // Else we should have at least one tag byte.
  981.                     if ($temp === '') {
  982.                         continue;
  983.                     }
  984.  
  985.                     $tag = ord($temp[0]);
  986.  
  987.                     // if isset($child['constant']) is true then isset($child['optional']) should be true as well
  988.                     if (isset($child['constant'])) {
  989.                         if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
  990.                             $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
  991.                             $temp = $subtag . self::encodeLength(strlen($temp)) . $temp;
  992.                         } else {
  993.                             $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
  994.                             $temp = $subtag . substr($temp, 1);
  995.                         }
  996.                     }
  997.                 }
  998.  
  999.                 if (isset($idx)) {
  1000.                     array_pop(self::$location);
  1001.                 }
  1002.  
  1003.                 if ($temp && isset($mapping['cast'])) {
  1004.                     $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
  1005.                 }
  1006.  
  1007.                 return $temp;
  1008.             case self::TYPE_INTEGER:
  1009.             case self::TYPE_ENUMERATED:
  1010.                 if (!isset($mapping['mapping'])) {
  1011.                     if (is_numeric($source)) {
  1012.                         $source = new BigInteger($source);
  1013.                     }
  1014.                     $value = $source->toBytes(true);
  1015.                 } else {
  1016.                     $value = array_search($source, $mapping['mapping']);
  1017.                     if ($value === false) {
  1018.                         return false;
  1019.                     }
  1020.                     $value = new BigInteger($value);
  1021.                     $value = $value->toBytes(true);
  1022.                 }
  1023.                 if (!strlen($value)) {
  1024.                     $value = chr(0);
  1025.                 }
  1026.                 break;
  1027.             case self::TYPE_UTC_TIME:
  1028.             case self::TYPE_GENERALIZED_TIME:
  1029.                 $format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
  1030.                 $format .= 'mdHis';
  1031.                 // if $source does _not_ include timezone information within it then assume that the timezone is GMT
  1032.                 $date = new \DateTime($source, new \DateTimeZone('GMT'));
  1033.                 // if $source _does_ include timezone information within it then convert the time to GMT
  1034.                 $date->setTimezone(new \DateTimeZone('GMT'));
  1035.                 $value = $date->format($format) . 'Z';
  1036.                 break;
  1037.             case self::TYPE_BIT_STRING:
  1038.                 if (isset($mapping['mapping'])) {
  1039.                     $bits = array_fill(0, count($mapping['mapping']), 0);
  1040.                     $size = 0;
  1041.                     for ($i = 0; $i < count($mapping['mapping']); $i++) {
  1042.                         if (in_array($mapping['mapping'][$i], $source)) {
  1043.                             $bits[$i] = 1;
  1044.                             $size = $i;
  1045.                         }
  1046.                     }
  1047.  
  1048.                     if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
  1049.                         $size = $mapping['min'] - 1;
  1050.                     }
  1051.  
  1052.                     $offset = 8 - (($size + 1) & 7);
  1053.                     $offset = $offset !== 8 ? $offset : 0;
  1054.  
  1055.                     $value = chr($offset);
  1056.  
  1057.                     for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
  1058.                         unset($bits[$i]);
  1059.                     }
  1060.  
  1061.                     $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
  1062.                     $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
  1063.                     foreach ($bytes as $byte) {
  1064.                         $value .= chr(bindec($byte));
  1065.                     }
  1066.  
  1067.                     break;
  1068.                 }
  1069.                 // fall-through
  1070.             case self::TYPE_OCTET_STRING:
  1071.                 /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
  1072.                    the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
  1073.  
  1074.                    -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
  1075.                 $value = $source;
  1076.                 break;
  1077.             case self::TYPE_OBJECT_IDENTIFIER:
  1078.                 $value = self::encodeOID($source);
  1079.                 break;
  1080.             case self::TYPE_ANY:
  1081.                 $loc = self::$location;
  1082.                 if (isset($idx)) {
  1083.                     array_pop(self::$location);
  1084.                 }
  1085.  
  1086.                 switch (true) {
  1087.                     case !isset($source):
  1088.                         return self::encode_der(null, ['type' => self::TYPE_NULL] + $mapping, null, $special);
  1089.                     case is_int($source):
  1090.                     case $source instanceof BigInteger:
  1091.                         return self::encode_der($source, ['type' => self::TYPE_INTEGER] + $mapping, null, $special);
  1092.                     case is_float($source):
  1093.                         return self::encode_der($source, ['type' => self::TYPE_REAL] + $mapping, null, $special);
  1094.                     case is_bool($source):
  1095.                         return self::encode_der($source, ['type' => self::TYPE_BOOLEAN] + $mapping, null, $special);
  1096.                     case is_array($source) && count($source) == 1:
  1097.                         $typename = implode('', array_keys($source));
  1098.                         $outtype = array_search($typename, self::ANY_MAP, true);
  1099.                         if ($outtype !== false) {
  1100.                             return self::encode_der($source[$typename], ['type' => $outtype] + $mapping, null, $special);
  1101.                         }
  1102.                 }
  1103.  
  1104.                 $filters = self::$filters;
  1105.                 foreach ($loc as $part) {
  1106.                     if (!isset($filters[$part])) {
  1107.                         $filters = false;
  1108.                         break;
  1109.                     }
  1110.                     $filters = $filters[$part];
  1111.                 }
  1112.                 if ($filters === false) {
  1113.                     throw new \RuntimeException('No filters defined for ' . implode('/', $loc));
  1114.                 }
  1115.                 return self::encode_der($source, $filters + $mapping, null, $special);
  1116.             case self::TYPE_NULL:
  1117.                 $value = '';
  1118.                 break;
  1119.             case self::TYPE_NUMERIC_STRING:
  1120.             case self::TYPE_TELETEX_STRING:
  1121.             case self::TYPE_PRINTABLE_STRING:
  1122.             case self::TYPE_UNIVERSAL_STRING:
  1123.             case self::TYPE_UTF8_STRING:
  1124.             case self::TYPE_BMP_STRING:
  1125.             case self::TYPE_IA5_STRING:
  1126.             case self::TYPE_VISIBLE_STRING:
  1127.             case self::TYPE_VIDEOTEX_STRING:
  1128.             case self::TYPE_GRAPHIC_STRING:
  1129.             case self::TYPE_GENERAL_STRING:
  1130.                 $value = $source;
  1131.                 break;
  1132.             case self::TYPE_BOOLEAN:
  1133.                 $value = $source ? "\xFF" : "\x00";
  1134.                 break;
  1135.             default:
  1136.                 throw new \RuntimeException('Mapping provides no type definition for ' . implode('/', self::$location));
  1137.         }
  1138.  
  1139.         if (isset($idx)) {
  1140.             array_pop(self::$location);
  1141.         }
  1142.  
  1143.         if (isset($mapping['cast'])) {
  1144.             if (isset($mapping['explicit']) || $mapping['type'] == self::TYPE_CHOICE) {
  1145.                 $value = chr($tag) . self::encodeLength(strlen($value)) . $value;
  1146.                 $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
  1147.             } else {
  1148.                 $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
  1149.             }
  1150.         }
  1151.  
  1152.         return chr($tag) . self::encodeLength(strlen($value)) . $value;
  1153.     }
  1154.  
  1155.     /**
  1156.      * BER-decode the OID
  1157.      *
  1158.      * Called by _decode_ber()
  1159.      *
  1160.      * @access public
  1161.      * @param string $content
  1162.      * @return string
  1163.      */
  1164.     public static function decodeOID($content)
  1165.     {
  1166.         static $eighty;
  1167.         if (!$eighty) {
  1168.             $eighty = new BigInteger(80);
  1169.         }
  1170.  
  1171.         $oid = [];
  1172.         $pos = 0;
  1173.         $len = strlen($content);
  1174.  
  1175.         if (ord($content[$len - 1]) & 0x80) {
  1176.             return false;
  1177.         }
  1178.  
  1179.         $n = new BigInteger();
  1180.         while ($pos < $len) {
  1181.             $temp = ord($content[$pos++]);
  1182.             $n = $n->bitwise_leftShift(7);
  1183.             $n = $n->bitwise_or(new BigInteger($temp & 0x7F));
  1184.             if (~$temp & 0x80) {
  1185.                 $oid[] = $n;
  1186.                 $n = new BigInteger();
  1187.             }
  1188.         }
  1189.         $part1 = array_shift($oid);
  1190.         $first = floor(ord($content[0]) / 40);
  1191.         /*
  1192.           "This packing of the first two object identifier components recognizes that only three values are allocated from the root
  1193.            node, and at most 39 subsequent values from nodes reached by X = 0 and X = 1."
  1194.  
  1195.           -- https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22
  1196.         */
  1197.         if ($first <= 2) { // ie. 0 <= ord($content[0]) < 120 (0x78)
  1198.             array_unshift($oid, ord($content[0]) % 40);
  1199.             array_unshift($oid, $first);
  1200.         } else {
  1201.             array_unshift($oid, $part1->subtract($eighty));
  1202.             array_unshift($oid, 2);
  1203.         }
  1204.  
  1205.         return implode('.', $oid);
  1206.     }
  1207.  
  1208.     /**
  1209.      * DER-encode the OID
  1210.      *
  1211.      * Called by _encode_der()
  1212.      *
  1213.      * @access public
  1214.      * @param string $source
  1215.      * @return string
  1216.      */
  1217.     public static function encodeOID($source)
  1218.     {
  1219.         static $mask, $zero, $forty;
  1220.         if (!$mask) {
  1221.             $mask = new BigInteger(0x7F);
  1222.             $zero = new BigInteger();
  1223.             $forty = new BigInteger(40);
  1224.         }
  1225.  
  1226.         if (!preg_match('#(?:\d+\.)+#', $source)) {
  1227.             $oid = isset(self::$reverseOIDs[$source]) ? self::$reverseOIDs[$source] : false;
  1228.         } else {
  1229.             $oid = $source;
  1230.         }
  1231.         if ($oid === false) {
  1232.             throw new \RuntimeException('Invalid OID');
  1233.         }
  1234.  
  1235.         $parts = explode('.', $oid);
  1236.         $part1 = array_shift($parts);
  1237.         $part2 = array_shift($parts);
  1238.  
  1239.         $first = new BigInteger($part1);
  1240.         $first = $first->multiply($forty);
  1241.         $first = $first->add(new BigInteger($part2));
  1242.  
  1243.         array_unshift($parts, $first->toString());
  1244.  
  1245.         $value = '';
  1246.         foreach ($parts as $part) {
  1247.             if (!$part) {
  1248.                 $temp = "\0";
  1249.             } else {
  1250.                 $temp = '';
  1251.                 $part = new BigInteger($part);
  1252.                 while (!$part->equals($zero)) {
  1253.                     $submask = $part->bitwise_and($mask);
  1254.                     $submask->setPrecision(8);
  1255.                     $temp = (chr(0x80) | $submask->toBytes()) . $temp;
  1256.                     $part = $part->bitwise_rightShift(7);
  1257.                 }
  1258.                 $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
  1259.             }
  1260.             $value .= $temp;
  1261.         }
  1262.  
  1263.         return $value;
  1264.     }
  1265.  
  1266.     /**
  1267.      * BER-decode the time
  1268.      *
  1269.      * Called by _decode_ber() and in the case of implicit tags asn1map().
  1270.      *
  1271.      * @access private
  1272.      * @param string $content
  1273.      * @param int $tag
  1274.      * @return \DateTime|false
  1275.      */
  1276.     private static function decodeTime($content, $tag)
  1277.     {
  1278.         /* UTCTime:
  1279.            http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
  1280.            http://www.obj-sys.com/asn1tutorial/node15.html
  1281.  
  1282.            GeneralizedTime:
  1283.            http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
  1284.            http://www.obj-sys.com/asn1tutorial/node14.html */
  1285.  
  1286.         $format = 'YmdHis';
  1287.  
  1288.         if ($tag == self::TYPE_UTC_TIME) {
  1289.             // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
  1290.             // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
  1291.             // browsers parse it phpseclib ought to too
  1292.             if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
  1293.                 $content = $matches[1] . '00' . $matches[2];
  1294.             }
  1295.             $prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
  1296.             $content = $prefix . $content;
  1297.         } elseif (strpos($content, '.') !== false) {
  1298.             $format .= '.u';
  1299.         }
  1300.  
  1301.         if ($content[strlen($content) - 1] == 'Z') {
  1302.             $content = substr($content, 0, -1) . '+0000';
  1303.         }
  1304.  
  1305.         if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
  1306.             $format .= 'O';
  1307.         }
  1308.  
  1309.         // error supression isn't necessary as of PHP 7.0:
  1310.         // http://php.net/manual/en/migration70.other-changes.php
  1311.         return @\DateTime::createFromFormat($format, $content);
  1312.     }
  1313.  
  1314.     /**
  1315.      * Set the time format
  1316.      *
  1317.      * Sets the time / date format for asn1map().
  1318.      *
  1319.      * @access public
  1320.      * @param string $format
  1321.      */
  1322.     public static function setTimeFormat($format)
  1323.     {
  1324.         self::$format = $format;
  1325.     }
  1326.  
  1327.     /**
  1328.      * Load OIDs
  1329.      *
  1330.      * Load the relevant OIDs for a particular ASN.1 semantic mapping.
  1331.      * Previously loaded OIDs are retained.
  1332.      *
  1333.      * @access public
  1334.      * @param array $oids
  1335.      */
  1336.     public static function loadOIDs($oids)
  1337.     {
  1338.         self::$reverseOIDs += $oids;
  1339.         self::$oids = array_flip(self::$reverseOIDs);
  1340.     }
  1341.  
  1342.     /**
  1343.      * Set filters
  1344.      *
  1345.      * See \phpseclib3\File\X509, etc, for an example.
  1346.      * Previously loaded filters are not retained.
  1347.      *
  1348.      * @access public
  1349.      * @param array $filters
  1350.      */
  1351.     public static function setFilters($filters)
  1352.     {
  1353.         self::$filters = $filters;
  1354.     }
  1355.  
  1356.     /**
  1357.      * String type conversion
  1358.      *
  1359.      * This is a lazy conversion, dealing only with character size.
  1360.      * No real conversion table is used.
  1361.      *
  1362.      * @param string $in
  1363.      * @param int $from
  1364.      * @param int $to
  1365.      * @return string
  1366.      * @access public
  1367.      */
  1368.     public static function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING)
  1369.     {
  1370.         // isset(self::STRING_TYPE_SIZE[$from] returns a fatal error on PHP 5.6
  1371.         if (!array_key_exists($from, self::STRING_TYPE_SIZE) || !array_key_exists($to, self::STRING_TYPE_SIZE)) {
  1372.             return false;
  1373.         }
  1374.         $insize = self::STRING_TYPE_SIZE[$from];
  1375.         $outsize = self::STRING_TYPE_SIZE[$to];
  1376.         $inlength = strlen($in);
  1377.         $out = '';
  1378.  
  1379.         for ($i = 0; $i < $inlength;) {
  1380.             if ($inlength - $i < $insize) {
  1381.                 return false;
  1382.             }
  1383.  
  1384.             // Get an input character as a 32-bit value.
  1385.             $c = ord($in[$i++]);
  1386.             switch (true) {
  1387.                 case $insize == 4:
  1388.                     $c = ($c << 8) | ord($in[$i++]);
  1389.                     $c = ($c << 8) | ord($in[$i++]);
  1390.                     // fall-through
  1391.                 case $insize == 2:
  1392.                     $c = ($c << 8) | ord($in[$i++]);
  1393.                     // fall-through
  1394.                 case $insize == 1:
  1395.                     break;
  1396.                 case ($c & 0x80) == 0x00:
  1397.                     break;
  1398.                 case ($c & 0x40) == 0x00:
  1399.                     return false;
  1400.                 default:
  1401.                     $bit = 6;
  1402.                     do {
  1403.                         if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
  1404.                             return false;
  1405.                         }
  1406.                         $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
  1407.                         $bit += 5;
  1408.                         $mask = 1 << $bit;
  1409.                     } while ($c & $bit);
  1410.                     $c &= $mask - 1;
  1411.                     break;
  1412.             }
  1413.  
  1414.             // Convert and append the character to output string.
  1415.             $v = '';
  1416.             switch (true) {
  1417.                 case $outsize == 4:
  1418.                     $v .= chr($c & 0xFF);
  1419.                     $c >>= 8;
  1420.                     $v .= chr($c & 0xFF);
  1421.                     $c >>= 8;
  1422.                     // fall-through
  1423.                 case $outsize == 2:
  1424.                     $v .= chr($c & 0xFF);
  1425.                     $c >>= 8;
  1426.                     // fall-through
  1427.                 case $outsize == 1:
  1428.                     $v .= chr($c & 0xFF);
  1429.                     $c >>= 8;
  1430.                     if ($c) {
  1431.                         return false;
  1432.                     }
  1433.                     break;
  1434.                 case ($c & 0x80000000) != 0:
  1435.                     return false;
  1436.                 case $c >= 0x04000000:
  1437.                     $v .= chr(0x80 | ($c & 0x3F));
  1438.                     $c = ($c >> 6) | 0x04000000;
  1439.                     // fall-through
  1440.                 case $c >= 0x00200000:
  1441.                     $v .= chr(0x80 | ($c & 0x3F));
  1442.                     $c = ($c >> 6) | 0x00200000;
  1443.                     // fall-through
  1444.                 case $c >= 0x00010000:
  1445.                     $v .= chr(0x80 | ($c & 0x3F));
  1446.                     $c = ($c >> 6) | 0x00010000;
  1447.                     // fall-through
  1448.                 case $c >= 0x00000800:
  1449.                     $v .= chr(0x80 | ($c & 0x3F));
  1450.                     $c = ($c >> 6) | 0x00000800;
  1451.                     // fall-through
  1452.                 case $c >= 0x00000080:
  1453.                     $v .= chr(0x80 | ($c & 0x3F));
  1454.                     $c = ($c >> 6) | 0x000000C0;
  1455.                     // fall-through
  1456.                 default:
  1457.                     $v .= chr($c);
  1458.                     break;
  1459.             }
  1460.             $out .= strrev($v);
  1461.         }
  1462.         return $out;
  1463.     }
  1464.  
  1465.     /**
  1466.      * Extract raw BER from Base64 encoding
  1467.      *
  1468.      * @access private
  1469.      * @param string $str
  1470.      * @return string
  1471.      */
  1472.     public static function extractBER($str)
  1473.     {
  1474.         /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
  1475.          * above and beyond the ceritificate.
  1476.          * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
  1477.          *
  1478.          * Bag Attributes
  1479.          *     localKeyID: 01 00 00 00
  1480.          * subject=/O=organization/OU=org unit/CN=common name
  1481.          * issuer=/O=organization/CN=common name
  1482.          */
  1483.         if (strlen($str) > ini_get('pcre.backtrack_limit')) {
  1484.             $temp = $str;
  1485.         } else {
  1486.             $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
  1487.             $temp = preg_replace('#-+END.*[\r\n ]*.*#ms', '', $temp, 1);
  1488.         }
  1489.         // remove new lines
  1490.         $temp = str_replace(["\r", "\n", ' '], '', $temp);
  1491.         // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
  1492.         $temp = preg_replace('#^-+[^-]+-+|-+[^-]+-+$#', '', $temp);
  1493.         $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
  1494.         return $temp != false ? $temp : $str;
  1495.     }
  1496.  
  1497.     /**
  1498.      * DER-encode the length
  1499.      *
  1500.      * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
  1501.      * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
  1502.      *
  1503.      * @access public
  1504.      * @param int $length
  1505.      * @return string
  1506.      */
  1507.     public static function encodeLength($length)
  1508.     {
  1509.         if ($length <= 0x7F) {
  1510.             return chr($length);
  1511.         }
  1512.  
  1513.         $temp = ltrim(pack('N', $length), chr(0));
  1514.         return pack('Ca*', 0x80 | strlen($temp), $temp);
  1515.     }
  1516.  
  1517.     /**
  1518.      * Returns the OID corresponding to a name
  1519.      *
  1520.      * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if
  1521.      * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version
  1522.      * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able
  1523.      * to work from version to version.
  1524.      *
  1525.      * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that
  1526.      * what's being passed to it already is an OID and return that instead. A few examples.
  1527.      *
  1528.      * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1'
  1529.      * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1'
  1530.      * getOID('zzz') == 'zzz'
  1531.      *
  1532.      * @access public
  1533.      * @param string $name
  1534.      * @return string
  1535.      */
  1536.     public static function getOID($name)
  1537.     {
  1538.         return isset(self::$reverseOIDs[$name]) ? self::$reverseOIDs[$name] : $name;
  1539.     }
  1540. }
  1541.