ASN1.php 51 KB

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