PageRenderTime 71ms CodeModel.GetById 5ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/phpseclib/File/ASN1.php

https://github.com/KenjiOhtsuka/core
PHP | 1340 lines | 835 code | 102 blank | 403 comment | 191 complexity | 4dcfc32c6ab099c99059505f044115e9 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. namespace PHPSecLib;
  4. /**
  5. * Pure-PHP ASN.1 Parser
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * ASN.1 provides the semantics for data encoded using various schemes. The most commonly
  10. * utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
  11. * DER blobs.
  12. *
  13. * File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
  14. *
  15. * Uses the 1988 ASN.1 syntax.
  16. *
  17. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  18. * of this software and associated documentation files (the "Software"), to deal
  19. * in the Software without restriction, including without limitation the rights
  20. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  21. * copies of the Software, and to permit persons to whom the Software is
  22. * furnished to do so, subject to the following conditions:
  23. *
  24. * The above copyright notice and this permission notice shall be included in
  25. * all copies or substantial portions of the Software.
  26. *
  27. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  30. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  31. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  32. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  33. * THE SOFTWARE.
  34. *
  35. * @category File
  36. * @package File_ASN1
  37. * @author Jim Wigginton <terrafrost@php.net>
  38. * @copyright MMXII Jim Wigginton
  39. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  40. * @link http://phpseclib.sourceforge.net
  41. */
  42. use \PHPSecLib\Math\BigInteger;
  43. /**#@+
  44. * Tag Classes
  45. *
  46. * @access private
  47. * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
  48. */
  49. define('FILE_ASN1_CLASS_UNIVERSAL', 0);
  50. define('FILE_ASN1_CLASS_APPLICATION', 1);
  51. define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
  52. define('FILE_ASN1_CLASS_PRIVATE', 3);
  53. /**#@-*/
  54. /**#@+
  55. * Tag Classes
  56. *
  57. * @access private
  58. * @link http://www.obj-sys.com/asn1tutorial/node124.html
  59. */
  60. define('FILE_ASN1_TYPE_BOOLEAN', 1);
  61. define('FILE_ASN1_TYPE_INTEGER', 2);
  62. define('FILE_ASN1_TYPE_BIT_STRING', 3);
  63. define('FILE_ASN1_TYPE_OCTET_STRING', 4);
  64. define('FILE_ASN1_TYPE_NULL', 5);
  65. define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
  66. //define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
  67. //define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
  68. define('FILE_ASN1_TYPE_REAL', 9);
  69. define('FILE_ASN1_TYPE_ENUMERATED', 10);
  70. //define('FILE_ASN1_TYPE_EMBEDDED', 11);
  71. define('FILE_ASN1_TYPE_UTF8_STRING', 12);
  72. //define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
  73. define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
  74. define('FILE_ASN1_TYPE_SET', 17); // SET OF
  75. /**#@-*/
  76. /**#@+
  77. * More Tag Classes
  78. *
  79. * @access private
  80. * @link http://www.obj-sys.com/asn1tutorial/node10.html
  81. */
  82. define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
  83. define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
  84. define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
  85. define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
  86. define('FILE_ASN1_TYPE_IA5_STRING', 22);
  87. define('FILE_ASN1_TYPE_UTC_TIME', 23);
  88. define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
  89. define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
  90. define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
  91. define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
  92. define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
  93. //define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
  94. define('FILE_ASN1_TYPE_BMP_STRING', 30);
  95. /**#@-*/
  96. /**#@+
  97. * Tag Aliases
  98. *
  99. * These tags are kinda place holders for other tags.
  100. *
  101. * @access private
  102. */
  103. define('FILE_ASN1_TYPE_CHOICE', -1);
  104. define('FILE_ASN1_TYPE_ANY', -2);
  105. /**#@-*/
  106. /**
  107. * ASN.1 Element
  108. *
  109. * Bypass normal encoding rules in File_ASN1::encodeDER()
  110. *
  111. * @package File_ASN1
  112. * @author Jim Wigginton <terrafrost@php.net>
  113. * @access public
  114. */
  115. class File_ASN1_Element
  116. {
  117. /**
  118. * Raw element value
  119. *
  120. * @var String
  121. * @access private
  122. */
  123. var $element;
  124. /**
  125. * Constructor
  126. *
  127. * @param String $encoded
  128. * @return File_ASN1_Element
  129. * @access public
  130. */
  131. function __construct($encoded)
  132. {
  133. $this->element = $encoded;
  134. }
  135. }
  136. /**
  137. * Pure-PHP ASN.1 Parser
  138. *
  139. * @package File_ASN1
  140. * @author Jim Wigginton <terrafrost@php.net>
  141. * @access public
  142. */
  143. class File_ASN1
  144. {
  145. /**
  146. * ASN.1 object identifier
  147. *
  148. * @var Array
  149. * @access private
  150. * @link http://en.wikipedia.org/wiki/Object_identifier
  151. */
  152. var $oids = array();
  153. /**
  154. * Default date format
  155. *
  156. * @var String
  157. * @access private
  158. * @link http://php.net/class.datetime
  159. */
  160. var $format = 'D, d M Y H:i:s O';
  161. /**
  162. * Default date format
  163. *
  164. * @var Array
  165. * @access private
  166. * @see File_ASN1::setTimeFormat()
  167. * @see File_ASN1::asn1map()
  168. * @link http://php.net/class.datetime
  169. */
  170. var $encoded;
  171. /**
  172. * Filters
  173. *
  174. * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
  175. *
  176. * @var Array
  177. * @access private
  178. * @see File_ASN1::_encode_der()
  179. */
  180. var $filters;
  181. /**
  182. * Type mapping table for the ANY type.
  183. *
  184. * Structured or unknown types are mapped to a FILE_ASN1_Element.
  185. * Unambiguous types get the direct mapping (int/real/bool).
  186. * Others are mapped as a choice, with an extra indexing level.
  187. *
  188. * @var Array
  189. * @access public
  190. */
  191. var $ANYmap = array(
  192. FILE_ASN1_TYPE_BOOLEAN => true,
  193. FILE_ASN1_TYPE_INTEGER => true,
  194. FILE_ASN1_TYPE_BIT_STRING => 'bitString',
  195. FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
  196. FILE_ASN1_TYPE_NULL => 'null',
  197. FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
  198. FILE_ASN1_TYPE_REAL => true,
  199. FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
  200. FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
  201. FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
  202. FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
  203. FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
  204. FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
  205. FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
  206. FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
  207. FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
  208. FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
  209. FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
  210. FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
  211. FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
  212. //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
  213. FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
  214. );
  215. /**
  216. * String type to character size mapping table.
  217. *
  218. * Non-convertable types are absent from this table.
  219. * size == 0 indicates variable length encoding.
  220. *
  221. * @var Array
  222. * @access public
  223. */
  224. var $stringTypeSize = array(
  225. FILE_ASN1_TYPE_UTF8_STRING => 0,
  226. FILE_ASN1_TYPE_BMP_STRING => 2,
  227. FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
  228. FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
  229. FILE_ASN1_TYPE_TELETEX_STRING => 1,
  230. FILE_ASN1_TYPE_IA5_STRING => 1,
  231. FILE_ASN1_TYPE_VISIBLE_STRING => 1,
  232. );
  233. /**
  234. * Parse BER-encoding
  235. *
  236. * Serves a similar purpose to openssl's asn1parse
  237. *
  238. * @param String $encoded
  239. * @return Array
  240. * @access public
  241. */
  242. function decodeBER($encoded)
  243. {
  244. if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
  245. $encoded = $encoded->element;
  246. }
  247. $this->encoded = $encoded;
  248. // encapsulate in an array for BC with the old decodeBER
  249. return array($this->_decode_ber($encoded));
  250. }
  251. /**
  252. * Parse BER-encoding (Helper function)
  253. *
  254. * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
  255. * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
  256. * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
  257. *
  258. * @param String $encoded
  259. * @param Integer $start
  260. * @return Array
  261. * @access private
  262. */
  263. function _decode_ber($encoded, $start = 0)
  264. {
  265. $current = array('start' => $start);
  266. $type = ord($this->_string_shift($encoded));
  267. $start++;
  268. $constructed = ($type >> 5) & 1;
  269. $tag = $type & 0x1F;
  270. if ($tag == 0x1F) {
  271. $tag = 0;
  272. // process septets (since the eighth bit is ignored, it's not an octet)
  273. do {
  274. $loop = ord($encoded[0]) >> 7;
  275. $tag <<= 7;
  276. $tag |= ord($this->_string_shift($encoded)) & 0x7F;
  277. $start++;
  278. } while ( $loop );
  279. }
  280. // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
  281. $length = ord($this->_string_shift($encoded));
  282. $start++;
  283. if ( $length == 0x80 ) { // indefinite length
  284. // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
  285. // immediately available." -- paragraph 8.1.3.2.c
  286. $length = strlen($encoded);
  287. } elseif ( $length & 0x80 ) { // definite length, long form
  288. // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
  289. // support it up to four.
  290. $length&= 0x7F;
  291. $temp = $this->_string_shift($encoded, $length);
  292. // tags of indefinte length don't really have a header length; this length includes the tag
  293. $current+= array('headerlength' => $length + 2);
  294. $start+= $length;
  295. extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
  296. } else {
  297. $current+= array('headerlength' => 2);
  298. }
  299. $content = $this->_string_shift($encoded, $length);
  300. // at this point $length can be overwritten. it's only accurate for definite length things as is
  301. /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
  302. built-in types. It defines an application-independent data type that must be distinguishable from all other
  303. data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
  304. have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
  305. a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
  306. alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
  307. data type; the term CONTEXT-SPECIFIC does not appear.
  308. -- http://www.obj-sys.com/asn1tutorial/node12.html */
  309. $class = ($type >> 6) & 3;
  310. switch ($class) {
  311. case FILE_ASN1_CLASS_APPLICATION:
  312. case FILE_ASN1_CLASS_PRIVATE:
  313. case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
  314. if ($constructed) {
  315. $newcontent = $this->_decode_ber($content, $start);
  316. $length = $newcontent['length'];
  317. if (substr($content, $length, 2) == "\0\0") {
  318. $length+= 2;
  319. }
  320. // the array encapsulation is for BC with the old format
  321. $content = array($newcontent);
  322. }
  323. $start+= $length;
  324. return array(
  325. 'type' => $class,
  326. 'constant' => $tag,
  327. // the array encapsulation is for BC with the old format
  328. 'content' => $content,
  329. // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
  330. // the absence of $content['headerlength'] is how we know if something is indefinite or not.
  331. // technically, it could be defined to be 2 and then another indicator could be used but whatever.
  332. 'length' => $start - $current['start']
  333. ) + $current;
  334. }
  335. $current+= array('type' => $tag);
  336. // decode UNIVERSAL tags
  337. switch ($tag) {
  338. case FILE_ASN1_TYPE_BOOLEAN:
  339. // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
  340. //if (strlen($content) != 1) {
  341. // return false;
  342. //}
  343. $current['content'] = (bool) ord($content[0]);
  344. break;
  345. case FILE_ASN1_TYPE_INTEGER:
  346. case FILE_ASN1_TYPE_ENUMERATED:
  347. $current['content'] = new BigInteger($content, -256);
  348. break;
  349. case FILE_ASN1_TYPE_REAL: // not currently supported
  350. return false;
  351. case FILE_ASN1_TYPE_BIT_STRING:
  352. // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
  353. // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
  354. // seven.
  355. if (!$constructed) {
  356. $current['content'] = $content;
  357. } else {
  358. $temp = $this->_decode_ber($content, $start);
  359. $length-= strlen($content);
  360. $last = count($temp) - 1;
  361. for ($i = 0; $i < $last; $i++) {
  362. // all subtags should be bit strings
  363. //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
  364. // return false;
  365. //}
  366. $current['content'].= substr($temp[$i]['content'], 1);
  367. }
  368. // all subtags should be bit strings
  369. //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
  370. // return false;
  371. //}
  372. $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
  373. }
  374. break;
  375. case FILE_ASN1_TYPE_OCTET_STRING:
  376. if (!$constructed) {
  377. $current['content'] = $content;
  378. } else {
  379. $current['content'] = '';
  380. $length = 0;
  381. while (substr($content, 0, 2) != "\0\0") {
  382. $temp = $this->_decode_ber($content, $length + $start);
  383. $this->_string_shift($content, $temp['length']);
  384. // all subtags should be octet strings
  385. //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
  386. // return false;
  387. //}
  388. $current['content'].= $temp['content'];
  389. $length+= $temp['length'];
  390. }
  391. if (substr($content, 0, 2) == "\0\0") {
  392. $length+= 2; // +2 for the EOC
  393. }
  394. }
  395. break;
  396. case FILE_ASN1_TYPE_NULL:
  397. // "The contents octets shall not contain any octets." -- paragraph 8.8.2
  398. //if (strlen($content)) {
  399. // return false;
  400. //}
  401. break;
  402. case FILE_ASN1_TYPE_SEQUENCE:
  403. case FILE_ASN1_TYPE_SET:
  404. $offset = 0;
  405. $current['content'] = array();
  406. while (strlen($content)) {
  407. // if indefinite length construction was used and we have an end-of-content string next
  408. // 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
  409. if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") {
  410. $length = $offset + 2; // +2 for the EOC
  411. break 2;
  412. }
  413. $temp = $this->_decode_ber($content, $start + $offset);
  414. $this->_string_shift($content, $temp['length']);
  415. $current['content'][] = $temp;
  416. $offset+= $temp['length'];
  417. }
  418. break;
  419. case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
  420. $temp = ord($this->_string_shift($content));
  421. $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
  422. $valuen = 0;
  423. // process septets
  424. while (strlen($content)) {
  425. $temp = ord($this->_string_shift($content));
  426. $valuen <<= 7;
  427. $valuen |= $temp & 0x7F;
  428. if (~$temp & 0x80) {
  429. $current['content'].= ".$valuen";
  430. $valuen = 0;
  431. }
  432. }
  433. // the eighth bit of the last byte should not be 1
  434. //if ($temp >> 7) {
  435. // return false;
  436. //}
  437. break;
  438. /* Each character string type shall be encoded as if it had been declared:
  439. [UNIVERSAL x] IMPLICIT OCTET STRING
  440. -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
  441. Per that, we're not going to do any validation. If there are any illegal characters in the string,
  442. we don't really care */
  443. case FILE_ASN1_TYPE_NUMERIC_STRING:
  444. // 0,1,2,3,4,5,6,7,8,9, and space
  445. case FILE_ASN1_TYPE_PRINTABLE_STRING:
  446. // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
  447. // hyphen, full stop, solidus, colon, equal sign, question mark
  448. case FILE_ASN1_TYPE_TELETEX_STRING:
  449. // The Teletex character set in CCITT's T61, space, and delete
  450. // see http://en.wikipedia.org/wiki/Teletex#Character_sets
  451. case FILE_ASN1_TYPE_VIDEOTEX_STRING:
  452. // The Videotex character set in CCITT's T.100 and T.101, space, and delete
  453. case FILE_ASN1_TYPE_VISIBLE_STRING:
  454. // Printing character sets of international ASCII, and space
  455. case FILE_ASN1_TYPE_IA5_STRING:
  456. // International Alphabet 5 (International ASCII)
  457. case FILE_ASN1_TYPE_GRAPHIC_STRING:
  458. // All registered G sets, and space
  459. case FILE_ASN1_TYPE_GENERAL_STRING:
  460. // All registered C and G sets, space and delete
  461. case FILE_ASN1_TYPE_UTF8_STRING:
  462. // ????
  463. case FILE_ASN1_TYPE_BMP_STRING:
  464. $current['content'] = $content;
  465. break;
  466. case FILE_ASN1_TYPE_UTC_TIME:
  467. case FILE_ASN1_TYPE_GENERALIZED_TIME:
  468. $current['content'] = $this->_decodeTime($content, $tag);
  469. default:
  470. }
  471. $start+= $length;
  472. // ie. length is the length of the full TLV encoding - it's not just the length of the value
  473. return $current + array('length' => $start - $current['start']);
  474. }
  475. /**
  476. * ASN.1 Map
  477. *
  478. * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
  479. *
  480. * "Special" mappings may be applied on a per tag-name basis via $special.
  481. *
  482. * @param Array $decoded
  483. * @param Array $mapping
  484. * @param Array $special
  485. * @return Array
  486. * @access public
  487. */
  488. function asn1map($decoded, $mapping, $special = array())
  489. {
  490. if (isset($mapping['explicit']) && is_array($decoded['content'])) {
  491. $decoded = $decoded['content'][0];
  492. }
  493. switch (true) {
  494. case $mapping['type'] == FILE_ASN1_TYPE_ANY:
  495. $intype = $decoded['type'];
  496. if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || ($this->encoded[$decoded['start']] & 0x20)) {
  497. return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
  498. }
  499. $inmap = $this->ANYmap[$intype];
  500. if (is_string($inmap)) {
  501. return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
  502. }
  503. break;
  504. case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
  505. foreach ($mapping['children'] as $key => $option) {
  506. switch (true) {
  507. case isset($option['constant']) && $option['constant'] == $decoded['constant']:
  508. case !isset($option['constant']) && $option['type'] == $decoded['type']:
  509. $value = $this->asn1map($decoded, $option, $special);
  510. break;
  511. case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
  512. $v = $this->asn1map($decoded, $option, $special);
  513. if (isset($v)) {
  514. $value = $v;
  515. }
  516. }
  517. if (isset($value)) {
  518. if (isset($special[$key])) {
  519. $value = call_user_func($special[$key], $value);
  520. }
  521. return array($key => $value);
  522. }
  523. }
  524. return null;
  525. case isset($mapping['implicit']):
  526. case isset($mapping['explicit']):
  527. case $decoded['type'] == $mapping['type']:
  528. break;
  529. default:
  530. // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
  531. // let it through
  532. switch (true) {
  533. case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
  534. case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
  535. case $mapping['type'] < 18:
  536. case $mapping['type'] > 30:
  537. return null;
  538. }
  539. }
  540. if (isset($mapping['implicit'])) {
  541. $decoded['type'] = $mapping['type'];
  542. }
  543. switch ($decoded['type']) {
  544. case FILE_ASN1_TYPE_SEQUENCE:
  545. $map = array();
  546. // ignore the min and max
  547. if (isset($mapping['min']) && isset($mapping['max'])) {
  548. $child = $mapping['children'];
  549. foreach ($decoded['content'] as $content) {
  550. if (($map[] = $this->asn1map($content, $child, $special)) === null) {
  551. return null;
  552. }
  553. }
  554. return $map;
  555. }
  556. $n = count($decoded['content']);
  557. $i = 0;
  558. foreach ($mapping['children'] as $key => $child) {
  559. $maymatch = $i < $n; // Match only existing input.
  560. if ($maymatch) {
  561. $temp = $decoded['content'][$i];
  562. if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
  563. // Get the mapping and input class & constant.
  564. $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
  565. $constant = null;
  566. if (isset($temp['constant'])) {
  567. $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
  568. }
  569. if (isset($child['class'])) {
  570. $childClass = $child['class'];
  571. $constant = $child['cast'];
  572. } elseif (isset($child['constant'])) {
  573. $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
  574. $constant = $child['constant'];
  575. }
  576. if (isset($constant) && isset($temp['constant'])) {
  577. // Can only match if constants and class match.
  578. $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
  579. } else {
  580. // Can only match if no constant expected and type matches or is generic.
  581. $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
  582. }
  583. }
  584. }
  585. if ($maymatch) {
  586. // Attempt submapping.
  587. $candidate = $this->asn1map($temp, $child, $special);
  588. $maymatch = $candidate !== null;
  589. }
  590. if ($maymatch) {
  591. // Got the match: use it.
  592. if (isset($special[$key])) {
  593. $candidate = call_user_func($special[$key], $candidate);
  594. }
  595. $map[$key] = $candidate;
  596. $i++;
  597. } elseif (isset($child['default'])) {
  598. $map[$key] = $child['default']; // Use default.
  599. } elseif (!isset($child['optional'])) {
  600. return null; // Syntax error.
  601. }
  602. }
  603. // Fail mapping if all input items have not been consumed.
  604. return $i < $n? null: $map;
  605. // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
  606. case FILE_ASN1_TYPE_SET:
  607. $map = array();
  608. // ignore the min and max
  609. if (isset($mapping['min']) && isset($mapping['max'])) {
  610. $child = $mapping['children'];
  611. foreach ($decoded['content'] as $content) {
  612. if (($map[] = $this->asn1map($content, $child, $special)) === null) {
  613. return null;
  614. }
  615. }
  616. return $map;
  617. }
  618. for ($i = 0; $i < count($decoded['content']); $i++) {
  619. $temp = $decoded['content'][$i];
  620. $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
  621. if (isset($temp['constant'])) {
  622. $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
  623. }
  624. foreach ($mapping['children'] as $key => $child) {
  625. if (isset($map[$key])) {
  626. continue;
  627. }
  628. $maymatch = true;
  629. if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
  630. $childClass = FILE_ASN1_CLASS_UNIVERSAL;
  631. $constant = null;
  632. if (isset($child['class'])) {
  633. $childClass = $child['class'];
  634. $constant = $child['cast'];
  635. } elseif (isset($child['constant'])) {
  636. $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
  637. $constant = $child['constant'];
  638. }
  639. if (isset($constant) && isset($temp['constant'])) {
  640. // Can only match if constants and class match.
  641. $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
  642. } else {
  643. // Can only match if no constant expected and type matches or is generic.
  644. $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
  645. }
  646. }
  647. if ($maymatch) {
  648. // Attempt submapping.
  649. $candidate = $this->asn1map($temp, $child, $special);
  650. $maymatch = $candidate !== null;
  651. }
  652. if (!$maymatch) {
  653. break;
  654. }
  655. // Got the match: use it.
  656. if (isset($special[$key])) {
  657. $candidate = call_user_func($special[$key], $candidate);
  658. }
  659. $map[$key] = $candidate;
  660. break;
  661. }
  662. }
  663. foreach ($mapping['children'] as $key => $child) {
  664. if (!isset($map[$key])) {
  665. if (isset($child['default'])) {
  666. $map[$key] = $child['default'];
  667. } elseif (!isset($child['optional'])) {
  668. return null;
  669. }
  670. }
  671. }
  672. return $map;
  673. case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
  674. return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
  675. case FILE_ASN1_TYPE_UTC_TIME:
  676. case FILE_ASN1_TYPE_GENERALIZED_TIME:
  677. if (isset($mapping['implicit'])) {
  678. $decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
  679. }
  680. return @date($this->format, $decoded['content']);
  681. case FILE_ASN1_TYPE_BIT_STRING:
  682. if (isset($mapping['mapping'])) {
  683. $offset = ord($decoded['content'][0]);
  684. $size = (strlen($decoded['content']) - 1) * 8 - $offset;
  685. /*
  686. From X.680-0207.pdf#page=46 (21.7):
  687. "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
  688. arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
  689. therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
  690. 0 bits."
  691. */
  692. $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
  693. for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
  694. $current = ord($decoded['content'][$i]);
  695. for ($j = $offset; $j < 8; $j++) {
  696. $bits[] = (bool) ($current & (1 << $j));
  697. }
  698. $offset = 0;
  699. }
  700. $values = array();
  701. $map = array_reverse($mapping['mapping']);
  702. foreach ($map as $i => $value) {
  703. if ($bits[$i]) {
  704. $values[] = $value;
  705. }
  706. }
  707. return $values;
  708. }
  709. case FILE_ASN1_TYPE_OCTET_STRING:
  710. return base64_encode($decoded['content']);
  711. case FILE_ASN1_TYPE_NULL:
  712. return '';
  713. case FILE_ASN1_TYPE_BOOLEAN:
  714. return $decoded['content'];
  715. case FILE_ASN1_TYPE_NUMERIC_STRING:
  716. case FILE_ASN1_TYPE_PRINTABLE_STRING:
  717. case FILE_ASN1_TYPE_TELETEX_STRING:
  718. case FILE_ASN1_TYPE_VIDEOTEX_STRING:
  719. case FILE_ASN1_TYPE_IA5_STRING:
  720. case FILE_ASN1_TYPE_GRAPHIC_STRING:
  721. case FILE_ASN1_TYPE_VISIBLE_STRING:
  722. case FILE_ASN1_TYPE_GENERAL_STRING:
  723. case FILE_ASN1_TYPE_UNIVERSAL_STRING:
  724. case FILE_ASN1_TYPE_UTF8_STRING:
  725. case FILE_ASN1_TYPE_BMP_STRING:
  726. return $decoded['content'];
  727. case FILE_ASN1_TYPE_INTEGER:
  728. case FILE_ASN1_TYPE_ENUMERATED:
  729. $temp = $decoded['content'];
  730. if (isset($mapping['implicit'])) {
  731. $temp = new BigInteger($decoded['content'], -256);
  732. }
  733. if (isset($mapping['mapping'])) {
  734. $temp = (int) $temp->toString();
  735. return isset($mapping['mapping'][$temp]) ?
  736. $mapping['mapping'][$temp] :
  737. false;
  738. }
  739. return $temp;
  740. }
  741. }
  742. /**
  743. * ASN.1 Encode
  744. *
  745. * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
  746. * an ASN.1 compiler.
  747. *
  748. * "Special" mappings can be applied via $special.
  749. *
  750. * @param String $source
  751. * @param String $mapping
  752. * @param Integer $idx
  753. * @return String
  754. * @access public
  755. */
  756. function encodeDER($source, $mapping, $special = array())
  757. {
  758. $this->location = array();
  759. return $this->_encode_der($source, $mapping, null, $special);
  760. }
  761. /**
  762. * ASN.1 Encode (Helper function)
  763. *
  764. * @param String $source
  765. * @param String $mapping
  766. * @param Integer $idx
  767. * @return String
  768. * @access private
  769. */
  770. function _encode_der($source, $mapping, $idx = null, $special = array())
  771. {
  772. if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
  773. return $source->element;
  774. }
  775. // do not encode (implicitly optional) fields with value set to default
  776. if (isset($mapping['default']) && $source === $mapping['default']) {
  777. return '';
  778. }
  779. if (isset($idx)) {
  780. if (isset($special[$idx])) {
  781. $source = call_user_func($special[$idx], $source);
  782. }
  783. $this->location[] = $idx;
  784. }
  785. $tag = $mapping['type'];
  786. switch ($tag) {
  787. case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
  788. case FILE_ASN1_TYPE_SEQUENCE:
  789. $tag|= 0x20; // set the constructed bit
  790. $value = '';
  791. // ignore the min and max
  792. if (isset($mapping['min']) && isset($mapping['max'])) {
  793. $child = $mapping['children'];
  794. foreach ($source as $content) {
  795. $temp = $this->_encode_der($content, $child, null, $special);
  796. if ($temp === false) {
  797. return false;
  798. }
  799. $value.= $temp;
  800. }
  801. break;
  802. }
  803. foreach ($mapping['children'] as $key => $child) {
  804. if (!isset($source[$key])) {
  805. if (!isset($child['optional'])) {
  806. return false;
  807. }
  808. continue;
  809. }
  810. $temp = $this->_encode_der($source[$key], $child, $key, $special);
  811. if ($temp === false) {
  812. return false;
  813. }
  814. // An empty child encoding means it has been optimized out.
  815. // Else we should have at least one tag byte.
  816. if ($temp === '') {
  817. continue;
  818. }
  819. // if isset($child['constant']) is true then isset($child['optional']) should be true as well
  820. if (isset($child['constant'])) {
  821. /*
  822. From X.680-0207.pdf#page=58 (30.6):
  823. "The tagging construction specifies explicit tagging if any of the following holds:
  824. ...
  825. c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
  826. AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
  827. an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
  828. */
  829. if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
  830. $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
  831. $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
  832. } else {
  833. $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
  834. $temp = $subtag . substr($temp, 1);
  835. }
  836. }
  837. $value.= $temp;
  838. }
  839. break;
  840. case FILE_ASN1_TYPE_CHOICE:
  841. $temp = false;
  842. foreach ($mapping['children'] as $key => $child) {
  843. if (!isset($source[$key])) {
  844. continue;
  845. }
  846. $temp = $this->_encode_der($source[$key], $child, $key, $special);
  847. if ($temp === false) {
  848. return false;
  849. }
  850. // An empty child encoding means it has been optimized out.
  851. // Else we should have at least one tag byte.
  852. if ($temp === '') {
  853. continue;
  854. }
  855. $tag = ord($temp[0]);
  856. // if isset($child['constant']) is true then isset($child['optional']) should be true as well
  857. if (isset($child['constant'])) {
  858. if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
  859. $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
  860. $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
  861. } else {
  862. $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
  863. $temp = $subtag . substr($temp, 1);
  864. }
  865. }
  866. }
  867. if (isset($idx)) {
  868. array_pop($this->location);
  869. }
  870. if ($temp && isset($mapping['cast'])) {
  871. $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
  872. }
  873. return $temp;
  874. case FILE_ASN1_TYPE_INTEGER:
  875. case FILE_ASN1_TYPE_ENUMERATED:
  876. if (!isset($mapping['mapping'])) {
  877. if (is_numeric($source)) {
  878. $source = new BigInteger($source);
  879. }
  880. $value = $source->toBytes(true);
  881. } else {
  882. $value = array_search($source, $mapping['mapping']);
  883. if ($value === false) {
  884. return false;
  885. }
  886. $value = new BigInteger($value);
  887. $value = $value->toBytes(true);
  888. }
  889. if (!strlen($value)) {
  890. $value = chr(0);
  891. }
  892. break;
  893. case FILE_ASN1_TYPE_UTC_TIME:
  894. case FILE_ASN1_TYPE_GENERALIZED_TIME:
  895. $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
  896. $format.= 'mdHis';
  897. $value = @gmdate($format, strtotime($source)) . 'Z';
  898. break;
  899. case FILE_ASN1_TYPE_BIT_STRING:
  900. if (isset($mapping['mapping'])) {
  901. $bits = array_fill(0, count($mapping['mapping']), 0);
  902. $size = 0;
  903. for ($i = 0; $i < count($mapping['mapping']); $i++) {
  904. if (in_array($mapping['mapping'][$i], $source)) {
  905. $bits[$i] = 1;
  906. $size = $i;
  907. }
  908. }
  909. if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
  910. $size = $mapping['min'] - 1;
  911. }
  912. $offset = 8 - (($size + 1) & 7);
  913. $offset = $offset !== 8 ? $offset : 0;
  914. $value = chr($offset);
  915. for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
  916. unset($bits[$i]);
  917. }
  918. $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
  919. $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
  920. foreach ($bytes as $byte) {
  921. $value.= chr(bindec($byte));
  922. }
  923. break;
  924. }
  925. case FILE_ASN1_TYPE_OCTET_STRING:
  926. /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
  927. the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
  928. -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
  929. $value = base64_decode($source);
  930. break;
  931. case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
  932. $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
  933. if ($oid === false) {
  934. user_error('Invalid OID');
  935. return false;
  936. }
  937. $value = '';
  938. $parts = explode('.', $oid);
  939. $value = chr(40 * $parts[0] + $parts[1]);
  940. for ($i = 2; $i < count($parts); $i++) {
  941. $temp = '';
  942. if (!$parts[$i]) {
  943. $temp = "\0";
  944. } else {
  945. while ($parts[$i]) {
  946. $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
  947. $parts[$i] >>= 7;
  948. }
  949. $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
  950. }
  951. $value.= $temp;
  952. }
  953. break;
  954. case FILE_ASN1_TYPE_ANY:
  955. $loc = $this->location;
  956. if (isset($idx)) {
  957. array_pop($this->location);
  958. }
  959. switch (true) {
  960. case !isset($source):
  961. return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
  962. case is_int($source):
  963. case $source instanceof \phpseclib\Math\BigInteger:
  964. return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
  965. case is_float($source):
  966. return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
  967. case is_bool($source):
  968. return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
  969. case is_array($source) && count($source) == 1:
  970. $typename = implode('', array_keys($source));
  971. $outtype = array_search($typename, $this->ANYmap, true);
  972. if ($outtype !== false) {
  973. return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
  974. }
  975. }
  976. $filters = $this->filters;
  977. foreach ($loc as $part) {
  978. if (!isset($filters[$part])) {
  979. $filters = false;
  980. break;
  981. }
  982. $filters = $filters[$part];
  983. }
  984. if ($filters === false) {
  985. user_error('No filters defined for ' . implode('/', $loc));
  986. return false;
  987. }
  988. return $this->_encode_der($source, $filters + $mapping, null, $special);
  989. case FILE_ASN1_TYPE_NULL:
  990. $value = '';
  991. break;
  992. case FILE_ASN1_TYPE_NUMERIC_STRING:
  993. case FILE_ASN1_TYPE_TELETEX_STRING:
  994. case FILE_ASN1_TYPE_PRINTABLE_STRING:
  995. case FILE_ASN1_TYPE_UNIVERSAL_STRING:
  996. case FILE_ASN1_TYPE_UTF8_STRING:
  997. case FILE_ASN1_TYPE_BMP_STRING:
  998. case FILE_ASN1_TYPE_IA5_STRING:
  999. case FILE_ASN1_TYPE_VISIBLE_STRING:
  1000. case FILE_ASN1_TYPE_VIDEOTEX_STRING:
  1001. case FILE_ASN1_TYPE_GRAPHIC_STRING:
  1002. case FILE_ASN1_TYPE_GENERAL_STRING:
  1003. $value = $source;
  1004. break;
  1005. case FILE_ASN1_TYPE_BOOLEAN:
  1006. $value = $source ? "\xFF" : "\x00";
  1007. break;
  1008. default:
  1009. user_error('Mapping provides no type definition for ' . implode('/', $this->location));
  1010. return false;
  1011. }
  1012. if (isset($idx)) {
  1013. array_pop($this->location);
  1014. }
  1015. if (isset($mapping['cast'])) {
  1016. if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
  1017. $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
  1018. $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
  1019. } else {
  1020. $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
  1021. }
  1022. }
  1023. return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
  1024. }
  1025. /**
  1026. * DER-encode the length
  1027. *
  1028. * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
  1029. * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
  1030. *
  1031. * @access private
  1032. * @param Integer $length
  1033. * @return String
  1034. */
  1035. function _encodeLength($length)
  1036. {
  1037. if ($length <= 0x7F) {
  1038. return chr($length);
  1039. }
  1040. $temp = ltrim(pack('N', $length), chr(0));
  1041. return pack('Ca*', 0x80 | strlen($temp), $temp);
  1042. }
  1043. /**
  1044. * BER-decode the time
  1045. *
  1046. * Called by _decode_ber() and in the case of implicit tags asn1map().
  1047. *
  1048. * @access private
  1049. * @param String $content
  1050. * @param Integer $tag
  1051. * @return String
  1052. */
  1053. function _decodeTime($content, $tag)
  1054. {
  1055. /* UTCTime:
  1056. http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
  1057. http://www.obj-sys.com/asn1tutorial/node15.html
  1058. GeneralizedTime:
  1059. http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
  1060. http://www.obj-sys.com/asn1tutorial/node14.html */
  1061. $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
  1062. '#(..)(..)(..)(..)(..)(..)(.*)#' :
  1063. '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
  1064. preg_match($pattern, $content, $matches);
  1065. list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
  1066. if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
  1067. $year = $year >= 50 ? "19$year" : "20$year";
  1068. }
  1069. if ($timezone == 'Z') {
  1070. $mktime = 'gmmktime';
  1071. $timezone = 0;
  1072. } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
  1073. $mktime = 'gmmktime';
  1074. $timezone = 60 * $matches[3] + 3600 * $matches[2];
  1075. if ($matches[1] == '-') {
  1076. $timezone = -$timezone;
  1077. }
  1078. } else {
  1079. $mktime = 'mktime';
  1080. $timezone = 0;
  1081. }
  1082. return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
  1083. }
  1084. /**
  1085. * Set the time format
  1086. *
  1087. * Sets the time / date format for asn1map().
  1088. *
  1089. * @access public
  1090. * @param String $format
  1091. */
  1092. function setTimeFormat($format)
  1093. {
  1094. $this->format = $format;
  1095. }
  1096. /**
  1097. * Load OIDs
  1098. *
  1099. * Load the relevant OIDs for a particular ASN.1 semantic mapping.
  1100. *
  1101. * @access public
  1102. * @param Array $oids
  1103. */
  1104. function loadOIDs($oids)
  1105. {
  1106. $this->oids = $oids;
  1107. }
  1108. /**
  1109. * Load filters
  1110. *
  1111. * See File_X509, etc, for an example.
  1112. *
  1113. * @access public
  1114. * @param Array $filters
  1115. */
  1116. function loadFilters($filters)
  1117. {
  1118. $this->filters = $filters;
  1119. }
  1120. /**
  1121. * String Shift
  1122. *
  1123. * Inspired by array_shift

Large files files are truncated, but you can click here to view the full file