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