ASN1.php 55 KB

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