/**
* Pure-PHP ASN.1 Parser
*
- * PHP versions 4 and 5
+ * PHP version 5
*
* ASN.1 provides the semantics for data encoded using various schemes. The most commonly
* utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
* DER blobs.
*
- * File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
+ * \phpseclib\File\ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
*
* Uses the 1988 ASN.1 syntax.
*
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
* @category File
- * @package File_ASN1
+ * @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
-/**#@+
- * Tag Classes
- *
- * @access private
- * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
- */
-define('FILE_ASN1_CLASS_UNIVERSAL', 0);
-define('FILE_ASN1_CLASS_APPLICATION', 1);
-define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
-define('FILE_ASN1_CLASS_PRIVATE', 3);
-/**#@-*/
-
-/**#@+
- * Tag Classes
- *
- * @access private
- * @link http://www.obj-sys.com/asn1tutorial/node124.html
- */
-define('FILE_ASN1_TYPE_BOOLEAN', 1);
-define('FILE_ASN1_TYPE_INTEGER', 2);
-define('FILE_ASN1_TYPE_BIT_STRING', 3);
-define('FILE_ASN1_TYPE_OCTET_STRING', 4);
-define('FILE_ASN1_TYPE_NULL', 5);
-define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
-//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
-//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
-define('FILE_ASN1_TYPE_REAL', 9);
-define('FILE_ASN1_TYPE_ENUMERATED', 10);
-//define('FILE_ASN1_TYPE_EMBEDDED', 11);
-define('FILE_ASN1_TYPE_UTF8_STRING', 12);
-//define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
-define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
-define('FILE_ASN1_TYPE_SET', 17); // SET OF
-/**#@-*/
-/**#@+
- * More Tag Classes
- *
- * @access private
- * @link http://www.obj-sys.com/asn1tutorial/node10.html
- */
-define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
-define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
-define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
-define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
-define('FILE_ASN1_TYPE_IA5_STRING', 22);
-define('FILE_ASN1_TYPE_UTC_TIME', 23);
-define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
-define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
-define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
-define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
-define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
-//define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
-define('FILE_ASN1_TYPE_BMP_STRING', 30);
-/**#@-*/
-
-/**#@+
- * Tag Aliases
- *
- * These tags are kinda place holders for other tags.
- *
- * @access private
- */
-define('FILE_ASN1_TYPE_CHOICE', -1);
-define('FILE_ASN1_TYPE_ANY', -2);
-/**#@-*/
+namespace phpseclib\File;
+
+use phpseclib\File\ASN1\Element;
+use phpseclib\Math\BigInteger;
/**
- * ASN.1 Element
- *
- * Bypass normal encoding rules in File_ASN1::encodeDER()
+ * Pure-PHP ASN.1 Parser
*
- * @package File_ASN1
+ * @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
-class File_ASN1_Element
+class ASN1
{
- /**
- * Raw element value
+ /**#@+
+ * Tag Classes
*
- * @var String
* @access private
+ * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
*/
- var $element;
-
- /**
- * Constructor
+ const CLASS_UNIVERSAL = 0;
+ const CLASS_APPLICATION = 1;
+ const CLASS_CONTEXT_SPECIFIC = 2;
+ const CLASS_PRIVATE = 3;
+ /**#@-*/
+
+ /**#@+
+ * Tag Classes
*
- * @param String $encoded
- * @return File_ASN1_Element
- * @access public
- */
- function File_ASN1_Element($encoded)
- {
- $this->element = $encoded;
- }
-}
+ * @access private
+ * @link http://www.obj-sys.com/asn1tutorial/node124.html
+ */
+ const TYPE_BOOLEAN = 1;
+ const TYPE_INTEGER = 2;
+ const TYPE_BIT_STRING = 3;
+ const TYPE_OCTET_STRING = 4;
+ const TYPE_NULL = 5;
+ const TYPE_OBJECT_IDENTIFIER = 6;
+ //const TYPE_OBJECT_DESCRIPTOR = 7;
+ //const TYPE_INSTANCE_OF = 8; // EXTERNAL
+ const TYPE_REAL = 9;
+ const TYPE_ENUMERATED = 10;
+ //const TYPE_EMBEDDED = 11;
+ const TYPE_UTF8_STRING = 12;
+ //const TYPE_RELATIVE_OID = 13;
+ const TYPE_SEQUENCE = 16; // SEQUENCE OF
+ const TYPE_SET = 17; // SET OF
+ /**#@-*/
+ /**#@+
+ * More Tag Classes
+ *
+ * @access private
+ * @link http://www.obj-sys.com/asn1tutorial/node10.html
+ */
+ const TYPE_NUMERIC_STRING = 18;
+ const TYPE_PRINTABLE_STRING = 19;
+ const TYPE_TELETEX_STRING = 20; // T61String
+ const TYPE_VIDEOTEX_STRING = 21;
+ const TYPE_IA5_STRING = 22;
+ const TYPE_UTC_TIME = 23;
+ const TYPE_GENERALIZED_TIME = 24;
+ const TYPE_GRAPHIC_STRING = 25;
+ const TYPE_VISIBLE_STRING = 26; // ISO646String
+ const TYPE_GENERAL_STRING = 27;
+ const TYPE_UNIVERSAL_STRING = 28;
+ //const TYPE_CHARACTER_STRING = 29;
+ const TYPE_BMP_STRING = 30;
+ /**#@-*/
+
+ /**#@+
+ * Tag Aliases
+ *
+ * These tags are kinda place holders for other tags.
+ *
+ * @access private
+ */
+ const TYPE_CHOICE = -1;
+ const TYPE_ANY = -2;
+ /**#@-*/
-/**
- * Pure-PHP ASN.1 Parser
- *
- * @package File_ASN1
- * @author Jim Wigginton <terrafrost@php.net>
- * @access public
- */
-class File_ASN1
-{
/**
* ASN.1 object identifier
*
- * @var Array
+ * @var array
* @access private
* @link http://en.wikipedia.org/wiki/Object_identifier
*/
/**
* Default date format
*
- * @var String
+ * @var string
* @access private
* @link http://php.net/class.datetime
*/
/**
* Default date format
*
- * @var Array
+ * @var array
* @access private
- * @see File_ASN1::setTimeFormat()
- * @see File_ASN1::asn1map()
+ * @see self::setTimeFormat()
+ * @see self::asn1map()
* @link http://php.net/class.datetime
*/
var $encoded;
/**
* Filters
*
- * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
+ * If the mapping type is self::TYPE_ANY what do we actually encode it as?
*
- * @var Array
+ * @var array
* @access private
- * @see File_ASN1::_encode_der()
+ * @see self::_encode_der()
*/
var $filters;
/**
* Type mapping table for the ANY type.
*
- * Structured or unknown types are mapped to a FILE_ASN1_Element.
+ * Structured or unknown types are mapped to a \phpseclib\File\ASN1\Element.
* Unambiguous types get the direct mapping (int/real/bool).
* Others are mapped as a choice, with an extra indexing level.
*
- * @var Array
+ * @var array
* @access public
*/
var $ANYmap = array(
- FILE_ASN1_TYPE_BOOLEAN => true,
- FILE_ASN1_TYPE_INTEGER => true,
- FILE_ASN1_TYPE_BIT_STRING => 'bitString',
- FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
- FILE_ASN1_TYPE_NULL => 'null',
- FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
- FILE_ASN1_TYPE_REAL => true,
- FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
- FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
- FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
- FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
- FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
- FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
- FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
- FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
- FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
- FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
- FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
- FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
- FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
- //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
- FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
+ self::TYPE_BOOLEAN => true,
+ self::TYPE_INTEGER => true,
+ self::TYPE_BIT_STRING => 'bitString',
+ self::TYPE_OCTET_STRING => 'octetString',
+ self::TYPE_NULL => 'null',
+ self::TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
+ self::TYPE_REAL => true,
+ self::TYPE_ENUMERATED => 'enumerated',
+ self::TYPE_UTF8_STRING => 'utf8String',
+ self::TYPE_NUMERIC_STRING => 'numericString',
+ self::TYPE_PRINTABLE_STRING => 'printableString',
+ self::TYPE_TELETEX_STRING => 'teletexString',
+ self::TYPE_VIDEOTEX_STRING => 'videotexString',
+ self::TYPE_IA5_STRING => 'ia5String',
+ self::TYPE_UTC_TIME => 'utcTime',
+ self::TYPE_GENERALIZED_TIME => 'generalTime',
+ self::TYPE_GRAPHIC_STRING => 'graphicString',
+ self::TYPE_VISIBLE_STRING => 'visibleString',
+ self::TYPE_GENERAL_STRING => 'generalString',
+ self::TYPE_UNIVERSAL_STRING => 'universalString',
+ //self::TYPE_CHARACTER_STRING => 'characterString',
+ self::TYPE_BMP_STRING => 'bmpString'
);
/**
* Non-convertable types are absent from this table.
* size == 0 indicates variable length encoding.
*
- * @var Array
+ * @var array
* @access public
*/
var $stringTypeSize = array(
- FILE_ASN1_TYPE_UTF8_STRING => 0,
- FILE_ASN1_TYPE_BMP_STRING => 2,
- FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
- FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
- FILE_ASN1_TYPE_TELETEX_STRING => 1,
- FILE_ASN1_TYPE_IA5_STRING => 1,
- FILE_ASN1_TYPE_VISIBLE_STRING => 1,
+ self::TYPE_UTF8_STRING => 0,
+ self::TYPE_BMP_STRING => 2,
+ self::TYPE_UNIVERSAL_STRING => 4,
+ self::TYPE_PRINTABLE_STRING => 1,
+ self::TYPE_TELETEX_STRING => 1,
+ self::TYPE_IA5_STRING => 1,
+ self::TYPE_VISIBLE_STRING => 1,
);
- /**
- * Default Constructor.
- *
- * @access public
- */
- function File_ASN1()
- {
- static $static_init = null;
- if (!$static_init) {
- $static_init = true;
- if (!class_exists('Math_BigInteger')) {
- include_once 'Math/BigInteger.php';
- }
- }
- }
-
/**
* Parse BER-encoding
*
* Serves a similar purpose to openssl's asn1parse
*
- * @param String $encoded
- * @return Array
+ * @param string $encoded
+ * @return array
* @access public
*/
function decodeBER($encoded)
{
- if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
+ if ($encoded instanceof Element) {
$encoded = $encoded->element;
}
* Parse BER-encoding (Helper function)
*
* Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
- * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
- * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
+ * $encoded is passed by reference for the recursive calls done for self::TYPE_BIT_STRING and
+ * self::TYPE_OCTET_STRING. In those cases, the indefinite length is used.
*
- * @param String $encoded
- * @param Integer $start
- * @return Array
+ * @param string $encoded
+ * @param int $start
+ * @param int $encoded_pos
+ * @return array
* @access private
*/
- function _decode_ber($encoded, $start = 0)
+ function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
{
$current = array('start' => $start);
- $type = ord($this->_string_shift($encoded));
+ $type = ord($encoded[$encoded_pos++]);
$start++;
$constructed = ($type >> 5) & 1;
do {
$loop = ord($encoded[0]) >> 7;
$tag <<= 7;
- $tag |= ord($this->_string_shift($encoded)) & 0x7F;
+ $tag |= ord($encoded[$encoded_pos++]) & 0x7F;
$start++;
- } while ( $loop );
+ } while ($loop);
}
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
- $length = ord($this->_string_shift($encoded));
+ $length = ord($encoded[$encoded_pos++]);
$start++;
- if ( $length == 0x80 ) { // indefinite length
+ if ($length == 0x80) { // indefinite length
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
// immediately available." -- paragraph 8.1.3.2.c
- $length = strlen($encoded);
- } elseif ( $length & 0x80 ) { // definite length, long form
+ $length = strlen($encoded) - $encoded_pos;
+ } elseif ($length & 0x80) { // definite length, long form
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
// support it up to four.
$length&= 0x7F;
- $temp = $this->_string_shift($encoded, $length);
+ $temp = substr($encoded, $encoded_pos, $length);
+ $encoded_pos += $length;
// tags of indefinte length don't really have a header length; this length includes the tag
$current+= array('headerlength' => $length + 2);
$start+= $length;
$current+= array('headerlength' => 2);
}
- $content = $this->_string_shift($encoded, $length);
+ if ($length > (strlen($encoded) - $encoded_pos)) {
+ return false;
+ }
+
+ $content = substr($encoded, $encoded_pos, $length);
+ $content_pos = 0;
// at this point $length can be overwritten. it's only accurate for definite length things as is
-- http://www.obj-sys.com/asn1tutorial/node12.html */
$class = ($type >> 6) & 3;
switch ($class) {
- case FILE_ASN1_CLASS_APPLICATION:
- case FILE_ASN1_CLASS_PRIVATE:
- case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
+ case self::CLASS_APPLICATION:
+ case self::CLASS_PRIVATE:
+ case self::CLASS_CONTEXT_SPECIFIC:
if (!$constructed) {
return array(
'type' => $class,
}
$newcontent = array();
- if (strlen($content)) {
- $newcontent = $this->_decode_ber($content, $start);
- $length = $newcontent['length'];
- if (substr($content, $length, 2) == "\0\0") {
+ $remainingLength = $length;
+ while ($remainingLength > 0) {
+ $temp = $this->_decode_ber($content, $start, $content_pos);
+ $length = $temp['length'];
+ // end-of-content octets - see paragraph 8.1.5
+ if (substr($content, $content_pos + $length, 2) == "\0\0") {
$length+= 2;
+ $start+= $length;
+ $newcontent[] = $temp;
+ break;
}
$start+= $length;
- $newcontent = array($newcontent);
+ $remainingLength-= $length;
+ $newcontent[] = $temp;
+ $content_pos += $length;
}
return array(
// decode UNIVERSAL tags
switch ($tag) {
- case FILE_ASN1_TYPE_BOOLEAN:
+ case self::TYPE_BOOLEAN:
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
//if (strlen($content) != 1) {
// return false;
//}
- $current['content'] = (bool) ord($content[0]);
+ $current['content'] = (bool) ord($content[$content_pos]);
break;
- case FILE_ASN1_TYPE_INTEGER:
- case FILE_ASN1_TYPE_ENUMERATED:
- $current['content'] = new Math_BigInteger($content, -256);
+ case self::TYPE_INTEGER:
+ case self::TYPE_ENUMERATED:
+ $current['content'] = new BigInteger(substr($content, $content_pos), -256);
break;
- case FILE_ASN1_TYPE_REAL: // not currently supported
+ case self::TYPE_REAL: // not currently supported
return false;
- case FILE_ASN1_TYPE_BIT_STRING:
+ case self::TYPE_BIT_STRING:
// The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
// the number of unused bits in the final subsequent octet. The number shall be in the range zero to
// seven.
if (!$constructed) {
- $current['content'] = $content;
+ $current['content'] = substr($content, $content_pos);
} else {
- $temp = $this->_decode_ber($content, $start);
- $length-= strlen($content);
+ $temp = $this->_decode_ber($content, $start, $content_pos);
+ $length-= (strlen($content) - $content_pos);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {
// all subtags should be bit strings
- //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
+ //if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
// return false;
//}
$current['content'].= substr($temp[$i]['content'], 1);
}
// all subtags should be bit strings
- //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
+ //if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
// return false;
//}
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
}
break;
- case FILE_ASN1_TYPE_OCTET_STRING:
+ case self::TYPE_OCTET_STRING:
if (!$constructed) {
- $current['content'] = $content;
+ $current['content'] = substr($content, $content_pos);
} else {
$current['content'] = '';
$length = 0;
- while (substr($content, 0, 2) != "\0\0") {
- $temp = $this->_decode_ber($content, $length + $start);
- $this->_string_shift($content, $temp['length']);
+ while (substr($content, $content_pos, 2) != "\0\0") {
+ $temp = $this->_decode_ber($content, $length + $start, $content_pos);
+ $content_pos += $temp['length'];
// all subtags should be octet strings
- //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
+ //if ($temp['type'] != self::TYPE_OCTET_STRING) {
// return false;
//}
$current['content'].= $temp['content'];
$length+= $temp['length'];
}
- if (substr($content, 0, 2) == "\0\0") {
+ if (substr($content, $content_pos, 2) == "\0\0") {
$length+= 2; // +2 for the EOC
}
}
break;
- case FILE_ASN1_TYPE_NULL:
+ case self::TYPE_NULL:
// "The contents octets shall not contain any octets." -- paragraph 8.8.2
//if (strlen($content)) {
// return false;
//}
break;
- case FILE_ASN1_TYPE_SEQUENCE:
- case FILE_ASN1_TYPE_SET:
+ case self::TYPE_SEQUENCE:
+ case self::TYPE_SET:
$offset = 0;
$current['content'] = array();
- while (strlen($content)) {
+ $content_len = strlen($content);
+ while ($content_pos < $content_len) {
// if indefinite length construction was used and we have an end-of-content string next
// 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
- if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") {
+ if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
$length = $offset + 2; // +2 for the EOC
break 2;
}
- $temp = $this->_decode_ber($content, $start + $offset);
- $this->_string_shift($content, $temp['length']);
+ $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
+ $content_pos += $temp['length'];
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
- case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
- $temp = ord($this->_string_shift($content));
+ case self::TYPE_OBJECT_IDENTIFIER:
+ $temp = ord($content[$content_pos++]);
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
- while (strlen($content)) {
- $temp = ord($this->_string_shift($content));
+ $content_len = strlen($content);
+ while ($content_pos < $content_len) {
+ $temp = ord($content[$content_pos++]);
$valuen <<= 7;
$valuen |= $temp & 0x7F;
if (~$temp & 0x80) {
Per that, we're not going to do any validation. If there are any illegal characters in the string,
we don't really care */
- case FILE_ASN1_TYPE_NUMERIC_STRING:
+ case self::TYPE_NUMERIC_STRING:
// 0,1,2,3,4,5,6,7,8,9, and space
- case FILE_ASN1_TYPE_PRINTABLE_STRING:
+ case self::TYPE_PRINTABLE_STRING:
// Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
// hyphen, full stop, solidus, colon, equal sign, question mark
- case FILE_ASN1_TYPE_TELETEX_STRING:
+ case self::TYPE_TELETEX_STRING:
// The Teletex character set in CCITT's T61, space, and delete
// see http://en.wikipedia.org/wiki/Teletex#Character_sets
- case FILE_ASN1_TYPE_VIDEOTEX_STRING:
+ case self::TYPE_VIDEOTEX_STRING:
// The Videotex character set in CCITT's T.100 and T.101, space, and delete
- case FILE_ASN1_TYPE_VISIBLE_STRING:
+ case self::TYPE_VISIBLE_STRING:
// Printing character sets of international ASCII, and space
- case FILE_ASN1_TYPE_IA5_STRING:
+ case self::TYPE_IA5_STRING:
// International Alphabet 5 (International ASCII)
- case FILE_ASN1_TYPE_GRAPHIC_STRING:
+ case self::TYPE_GRAPHIC_STRING:
// All registered G sets, and space
- case FILE_ASN1_TYPE_GENERAL_STRING:
+ case self::TYPE_GENERAL_STRING:
// All registered C and G sets, space and delete
- case FILE_ASN1_TYPE_UTF8_STRING:
+ case self::TYPE_UTF8_STRING:
// ????
- case FILE_ASN1_TYPE_BMP_STRING:
- $current['content'] = $content;
+ case self::TYPE_BMP_STRING:
+ $current['content'] = substr($content, $content_pos);
break;
- case FILE_ASN1_TYPE_UTC_TIME:
- case FILE_ASN1_TYPE_GENERALIZED_TIME:
- $current['content'] = $this->_decodeTime($content, $tag);
+ case self::TYPE_UTC_TIME:
+ case self::TYPE_GENERALIZED_TIME:
+ $current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
default:
}
*
* "Special" mappings may be applied on a per tag-name basis via $special.
*
- * @param Array $decoded
- * @param Array $mapping
- * @param Array $special
- * @return Array
+ * @param array $decoded
+ * @param array $mapping
+ * @param array $special
+ * @return array
* @access public
*/
function asn1map($decoded, $mapping, $special = array())
}
switch (true) {
- case $mapping['type'] == FILE_ASN1_TYPE_ANY:
+ case $mapping['type'] == self::TYPE_ANY:
$intype = $decoded['type'];
- if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || ($this->encoded[$decoded['start']] & 0x20)) {
- return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
+ if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
+ return new Element(substr($this->encoded, $decoded['start'], $decoded['length']));
}
$inmap = $this->ANYmap[$intype];
if (is_string($inmap)) {
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
}
break;
- case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
+ case $mapping['type'] == self::TYPE_CHOICE:
foreach ($mapping['children'] as $key => $option) {
switch (true) {
case isset($option['constant']) && $option['constant'] == $decoded['constant']:
case !isset($option['constant']) && $option['type'] == $decoded['type']:
$value = $this->asn1map($decoded, $option, $special);
break;
- case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
+ case !isset($option['constant']) && $option['type'] == self::TYPE_CHOICE:
$v = $this->asn1map($decoded, $option, $special);
if (isset($v)) {
$value = $v;
// if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
// let it through
switch (true) {
- case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
- case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
+ case $decoded['type'] < 18: // self::TYPE_NUMERIC_STRING == 18
+ case $decoded['type'] > 30: // self::TYPE_BMP_STRING == 30
case $mapping['type'] < 18:
case $mapping['type'] > 30:
return null;
}
switch ($decoded['type']) {
- case FILE_ASN1_TYPE_SEQUENCE:
+ case self::TYPE_SEQUENCE:
$map = array();
// ignore the min and max
if ($maymatch) {
$temp = $decoded['content'][$i];
- if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
+ if ($child['type'] != self::TYPE_CHOICE) {
// Get the mapping and input class & constant.
- $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
+ $childClass = $tempClass = self::CLASS_UNIVERSAL;
$constant = null;
if (isset($temp['constant'])) {
- $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
+ $tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
}
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
- $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
+ $childClass = self::CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {
// Can only match if no constant expected and type matches or is generic.
- $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
+ $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], self::TYPE_ANY, self::TYPE_CHOICE)) !== false;
}
}
}
}
// Fail mapping if all input items have not been consumed.
- return $i < $n? null: $map;
+ return $i < $n ? null: $map;
// the main diff between sets and sequences is the encapsulation of the foreach in another for loop
- case FILE_ASN1_TYPE_SET:
+ case self::TYPE_SET:
$map = array();
// ignore the min and max
for ($i = 0; $i < count($decoded['content']); $i++) {
$temp = $decoded['content'][$i];
- $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
+ $tempClass = self::CLASS_UNIVERSAL;
if (isset($temp['constant'])) {
- $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
+ $tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
}
foreach ($mapping['children'] as $key => $child) {
continue;
}
$maymatch = true;
- if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
- $childClass = FILE_ASN1_CLASS_UNIVERSAL;
+ if ($child['type'] != self::TYPE_CHOICE) {
+ $childClass = self::CLASS_UNIVERSAL;
$constant = null;
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
- $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
+ $childClass = self::CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {
// Can only match if no constant expected and type matches or is generic.
- $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
+ $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], self::TYPE_ANY, self::TYPE_CHOICE)) !== false;
}
}
}
}
return $map;
- case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
+ case self::TYPE_OBJECT_IDENTIFIER:
return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
- case FILE_ASN1_TYPE_UTC_TIME:
- case FILE_ASN1_TYPE_GENERALIZED_TIME:
+ case self::TYPE_UTC_TIME:
+ case self::TYPE_GENERALIZED_TIME:
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
}
return @date($this->format, $decoded['content']);
- case FILE_ASN1_TYPE_BIT_STRING:
+ case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$offset = ord($decoded['content'][0]);
$size = (strlen($decoded['content']) - 1) * 8 - $offset;
}
return $values;
}
- case FILE_ASN1_TYPE_OCTET_STRING:
+ case self::TYPE_OCTET_STRING:
return base64_encode($decoded['content']);
- case FILE_ASN1_TYPE_NULL:
+ case self::TYPE_NULL:
return '';
- case FILE_ASN1_TYPE_BOOLEAN:
+ case self::TYPE_BOOLEAN:
return $decoded['content'];
- case FILE_ASN1_TYPE_NUMERIC_STRING:
- case FILE_ASN1_TYPE_PRINTABLE_STRING:
- case FILE_ASN1_TYPE_TELETEX_STRING:
- case FILE_ASN1_TYPE_VIDEOTEX_STRING:
- case FILE_ASN1_TYPE_IA5_STRING:
- case FILE_ASN1_TYPE_GRAPHIC_STRING:
- case FILE_ASN1_TYPE_VISIBLE_STRING:
- case FILE_ASN1_TYPE_GENERAL_STRING:
- case FILE_ASN1_TYPE_UNIVERSAL_STRING:
- case FILE_ASN1_TYPE_UTF8_STRING:
- case FILE_ASN1_TYPE_BMP_STRING:
+ case self::TYPE_NUMERIC_STRING:
+ case self::TYPE_PRINTABLE_STRING:
+ case self::TYPE_TELETEX_STRING:
+ case self::TYPE_VIDEOTEX_STRING:
+ case self::TYPE_IA5_STRING:
+ case self::TYPE_GRAPHIC_STRING:
+ case self::TYPE_VISIBLE_STRING:
+ case self::TYPE_GENERAL_STRING:
+ case self::TYPE_UNIVERSAL_STRING:
+ case self::TYPE_UTF8_STRING:
+ case self::TYPE_BMP_STRING:
return $decoded['content'];
- case FILE_ASN1_TYPE_INTEGER:
- case FILE_ASN1_TYPE_ENUMERATED:
+ case self::TYPE_INTEGER:
+ case self::TYPE_ENUMERATED:
$temp = $decoded['content'];
if (isset($mapping['implicit'])) {
- $temp = new Math_BigInteger($decoded['content'], -256);
+ $temp = new BigInteger($decoded['content'], -256);
}
if (isset($mapping['mapping'])) {
$temp = (int) $temp->toString();
*
* "Special" mappings can be applied via $special.
*
- * @param String $source
- * @param String $mapping
- * @param Integer $idx
- * @return String
+ * @param string $source
+ * @param string $mapping
+ * @param int $idx
+ * @return string
* @access public
*/
function encodeDER($source, $mapping, $special = array())
/**
* ASN.1 Encode (Helper function)
*
- * @param String $source
- * @param String $mapping
- * @param Integer $idx
- * @return String
+ * @param string $source
+ * @param string $mapping
+ * @param int $idx
+ * @return string
* @access private
*/
function _encode_der($source, $mapping, $idx = null, $special = array())
{
- if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
+ if ($source instanceof Element) {
return $source->element;
}
$tag = $mapping['type'];
switch ($tag) {
- case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
- case FILE_ASN1_TYPE_SEQUENCE:
+ case self::TYPE_SET: // Children order is not important, thus process in sequence.
+ case self::TYPE_SEQUENCE:
$tag|= 0x20; // set the constructed bit
- $value = '';
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
+ $value = array();
$child = $mapping['children'];
foreach ($source as $content) {
if ($temp === false) {
return false;
}
- $value.= $temp;
+ $value[]= $temp;
+ }
+ /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
+ as octet strings with the shorter components being padded at their trailing end with 0-octets.
+ NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
+
+ -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
+ if ($mapping['type'] == self::TYPE_SET) {
+ sort($value);
}
+ $value = implode($value, '');
break;
}
+ $value = '';
foreach ($mapping['children'] as $key => $child) {
- if (!isset($source[$key])) {
+ if (!array_key_exists($key, $source)) {
if (!isset($child['optional'])) {
return false;
}
AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
*/
- if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
+ if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
+ $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
+ $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
$value.= $temp;
}
break;
- case FILE_ASN1_TYPE_CHOICE:
+ case self::TYPE_CHOICE:
$temp = false;
foreach ($mapping['children'] as $key => $child) {
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
if (isset($child['constant'])) {
- if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
+ if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
+ $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
- $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
+ $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
}
return $temp;
- case FILE_ASN1_TYPE_INTEGER:
- case FILE_ASN1_TYPE_ENUMERATED:
+ case self::TYPE_INTEGER:
+ case self::TYPE_ENUMERATED:
if (!isset($mapping['mapping'])) {
if (is_numeric($source)) {
- $source = new Math_BigInteger($source);
+ $source = new BigInteger($source);
}
$value = $source->toBytes(true);
} else {
if ($value === false) {
return false;
}
- $value = new Math_BigInteger($value);
+ $value = new BigInteger($value);
$value = $value->toBytes(true);
}
if (!strlen($value)) {
$value = chr(0);
}
break;
- case FILE_ASN1_TYPE_UTC_TIME:
- case FILE_ASN1_TYPE_GENERALIZED_TIME:
- $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
+ case self::TYPE_UTC_TIME:
+ case self::TYPE_GENERALIZED_TIME:
+ $format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
$format.= 'mdHis';
$value = @gmdate($format, strtotime($source)) . 'Z';
break;
- case FILE_ASN1_TYPE_BIT_STRING:
+ case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$bits = array_fill(0, count($mapping['mapping']), 0);
$size = 0;
break;
}
- case FILE_ASN1_TYPE_OCTET_STRING:
+ case self::TYPE_OCTET_STRING:
/* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
-- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
$value = base64_decode($source);
break;
- case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
+ case self::TYPE_OBJECT_IDENTIFIER:
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
if ($oid === false) {
user_error('Invalid OID');
$value.= $temp;
}
break;
- case FILE_ASN1_TYPE_ANY:
+ case self::TYPE_ANY:
$loc = $this->location;
if (isset($idx)) {
array_pop($this->location);
switch (true) {
case !isset($source):
- return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
+ return $this->_encode_der(null, array('type' => self::TYPE_NULL) + $mapping, null, $special);
case is_int($source):
- case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
- return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
+ case $source instanceof BigInteger:
+ return $this->_encode_der($source, array('type' => self::TYPE_INTEGER) + $mapping, null, $special);
case is_float($source):
- return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
+ return $this->_encode_der($source, array('type' => self::TYPE_REAL) + $mapping, null, $special);
case is_bool($source):
- return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
+ return $this->_encode_der($source, array('type' => self::TYPE_BOOLEAN) + $mapping, null, $special);
case is_array($source) && count($source) == 1:
$typename = implode('', array_keys($source));
$outtype = array_search($typename, $this->ANYmap, true);
if ($outtype !== false) {
return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
}
- }
+ }
$filters = $this->filters;
foreach ($loc as $part) {
return false;
}
return $this->_encode_der($source, $filters + $mapping, null, $special);
- case FILE_ASN1_TYPE_NULL:
+ case self::TYPE_NULL:
$value = '';
break;
- case FILE_ASN1_TYPE_NUMERIC_STRING:
- case FILE_ASN1_TYPE_TELETEX_STRING:
- case FILE_ASN1_TYPE_PRINTABLE_STRING:
- case FILE_ASN1_TYPE_UNIVERSAL_STRING:
- case FILE_ASN1_TYPE_UTF8_STRING:
- case FILE_ASN1_TYPE_BMP_STRING:
- case FILE_ASN1_TYPE_IA5_STRING:
- case FILE_ASN1_TYPE_VISIBLE_STRING:
- case FILE_ASN1_TYPE_VIDEOTEX_STRING:
- case FILE_ASN1_TYPE_GRAPHIC_STRING:
- case FILE_ASN1_TYPE_GENERAL_STRING:
+ case self::TYPE_NUMERIC_STRING:
+ case self::TYPE_TELETEX_STRING:
+ case self::TYPE_PRINTABLE_STRING:
+ case self::TYPE_UNIVERSAL_STRING:
+ case self::TYPE_UTF8_STRING:
+ case self::TYPE_BMP_STRING:
+ case self::TYPE_IA5_STRING:
+ case self::TYPE_VISIBLE_STRING:
+ case self::TYPE_VIDEOTEX_STRING:
+ case self::TYPE_GRAPHIC_STRING:
+ case self::TYPE_GENERAL_STRING:
$value = $source;
break;
- case FILE_ASN1_TYPE_BOOLEAN:
+ case self::TYPE_BOOLEAN:
$value = $source ? "\xFF" : "\x00";
break;
default:
}
if (isset($mapping['cast'])) {
- if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
+ if (isset($mapping['explicit']) || $mapping['type'] == self::TYPE_CHOICE) {
$value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
$tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
} else {
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
- * @param Integer $length
- * @return String
+ * @param int $length
+ * @return string
*/
function _encodeLength($length)
{
* Called by _decode_ber() and in the case of implicit tags asn1map().
*
* @access private
- * @param String $content
- * @param Integer $tag
- * @return String
+ * @param string $content
+ * @param int $tag
+ * @return string
*/
function _decodeTime($content, $tag)
{
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
- $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
+ $pattern = $tag == self::TYPE_UTC_TIME ?
'#(..)(..)(..)(..)(..)(..)(.*)#' :
'#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
- if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
+ if ($tag == self::TYPE_UTC_TIME) {
$year = $year >= 50 ? "19$year" : "20$year";
}
* Sets the time / date format for asn1map().
*
* @access public
- * @param String $format
+ * @param string $format
*/
function setTimeFormat($format)
{
* Load the relevant OIDs for a particular ASN.1 semantic mapping.
*
* @access public
- * @param Array $oids
+ * @param array $oids
*/
function loadOIDs($oids)
{
/**
* Load filters
*
- * See File_X509, etc, for an example.
+ * See \phpseclib\File\X509, etc, for an example.
*
* @access public
- * @param Array $filters
+ * @param array $filters
*/
function loadFilters($filters)
{
*
* Inspired by array_shift
*
- * @param String $string
- * @param optional Integer $index
- * @return String
+ * @param string $string
+ * @param int $index
+ * @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
* This is a lazy conversion, dealing only with character size.
* No real conversion table is used.
*
- * @param String $in
- * @param optional Integer $from
- * @param optional Integer $to
- * @return String
+ * @param string $in
+ * @param int $from
+ * @param int $to
+ * @return string
* @access public
*/
- function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
+ function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING)
{
if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
return false;