r105244 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r105243‎ | r105244 | r105245 >
Date:23:28, 5 December 2011
Author:platonides
Status:deferred (Comments)
Tags:miscextensions 
Comment:
Parser of ASN1 syntax used in RSA keys.
Modified paths:
  • /trunk/extensions/TorBlock/ASN1Parser.php (added) (history)

Diff [purge]

Index: trunk/extensions/TorBlock/ASN1Parser.php
@@ -0,0 +1,165 @@
 2+<?php
 3+
 4+class ASN1Exception extends Exception {
 5+}
 6+
 7+class ASN1Parser {
 8+ /* const */ static $tagClasses = array( 'universal', 'application', 'context-specific', 'private' );
 9+ /* const */ static $tagNames = array(
 10+ 2 => 'INTEGER',
 11+ 3 => 'BIT STRING',
 12+ 4 => 'OCTET STRING',
 13+ 5 => 'NULL',
 14+ 6 => 'OBJECT IDENTIFIER',
 15+ 16 => 'SEQUENCE',
 16+ 17 => 'SET',
 17+ 19 => 'PrintableString',
 18+ 20 => 'T61String',
 19+ 22 => 'IA5String',
 20+ 23 => 'UTCTime'
 21+ );
 22+
 23+ const INTEGER = 2;
 24+ const BIT_STRING = 3;
 25+ const OCTET_STRING = 4;
 26+ const NULL = 5;
 27+ const OBJECT_IDENTIFIER = 6;
 28+ const SEQUENCE = 16;
 29+ const SET = 17;
 30+ const PrintableString = 19;
 31+ const T61String = 20;
 32+ const IA5String = 22;
 33+ const UTCTime = 23;
 34+
 35+ static function encodeLength($number) {
 36+ if ($number < 128)
 37+ return chr($number);
 38+
 39+ $out = pack("N*", $number);
 40+ $out = ltrim( $out, "\0" );
 41+
 42+ return chr( 0x80 | strlen($out) ) . $out;
 43+ }
 44+
 45+ static function decode($buffer) {
 46+ if ( strlen( $buffer ) < 2 )
 47+ throw new ASN1Exception( 'ASN1 string is too short' );
 48+
 49+ $i = 0;
 50+ $result = array();
 51+ while ( $i < strlen( $buffer ) ) {
 52+ $item = array();
 53+
 54+ $tag = ord( $buffer[$i] );
 55+ $item['tag-class'] = self::$tagClasses[$tag >> 6];
 56+
 57+ $i++;
 58+ $constructed = $tag & 0x20; // Primitive/Constructed bit
 59+ $tag &= 0x1f;
 60+
 61+ if ( $tag != 0x1f ) {
 62+ // Great! it's in one octet
 63+
 64+ $item['tag'] = $tag;
 65+ } else {
 66+ $tag = 0;
 67+ for (; $i < strlen($buffer); $i++) {
 68+ $t = ord( $buffer[$i] );
 69+ $tag = ( $tag << 7 ) | ( $t & 0x7f );
 70+
 71+ // The last octet of the tag identifier will have the high-bit set to 0
 72+ if ( ( $t & 0x80 ) == 0 ) {
 73+ break;
 74+ }
 75+ }
 76+ if ( $i == strlen($buffer) )
 77+ throw new ASN1Exception( 'End of data found when processing tag identifier' );
 78+
 79+ $item['tag'] = $tag;
 80+ $i++;
 81+ }
 82+
 83+ /* Parse length */
 84+ $length = ord( $buffer[$i] );
 85+ $i++;
 86+
 87+ if ( ( $length & 0x80 ) == 0 ) {
 88+ $item['length'] = $length;
 89+ } else {
 90+ $l = $length & 0x7f;
 91+ $lengthBytes = substr( $buffer, $i, $l );
 92+ if ( strlen( $lengthBytes ) != $l ) {
 93+ throw new ASN1Exception( 'Not enough bytes for long-form length' );
 94+ }
 95+
 96+ $length = 0;
 97+ for ($j = 0; $j < $l; $j++, $i++) {
 98+ $length = ( $length << 8 ) | ord( $lengthBytes[$j] );
 99+
 100+ if ( $length < 0 )
 101+ throw new ASN1Exception( 'Overflow calculating length' );
 102+ }
 103+ $item['length'] = $length;
 104+
 105+ }
 106+ $item['contents'] = substr( $buffer, $i, $length );
 107+ $i += $length;
 108+
 109+ if ( $constructed ) {
 110+ $item['contents'] = self::decode( $item['contents'] );
 111+ } elseif ( $tag == 6 ) {
 112+ /* We could show the pretty name here instead of the hex dump
 113+ *
 114+ * a source could be crypto/objects/objects.txt from openssl
 115+ * project or crypto/objects/obj_dat.txt (where hexadecimal
 116+ * data is available )
 117+ */
 118+ $item['contents'] = $item['contents'];
 119+ } else {
 120+ $item['contents'] = $item['contents'];
 121+ }
 122+
 123+ $result[] = $item;
 124+ }
 125+
 126+ return count ( $result ) > 1 ? $result : $result[0];
 127+ }
 128+
 129+ /**
 130+ * Prettifies an array output by decode()
 131+ */
 132+ static function prettyDecode($decodedArray) {
 133+ $decoded = $decodedArray;
 134+ array_walk_recursive($decoded, array( __CLASS__, 'prettyItem' ) );
 135+
 136+ return $decoded;
 137+ }
 138+
 139+ static protected function prettyItem(&$value, $key) {
 140+ switch ($key) {
 141+ case 'contents': // Not called when contents is an array
 142+ $value = strlen( $value ) ? '0x' . bin2hex( $value ) : "''";
 143+ break;
 144+ case 'tag':
 145+ if ( isset( self::$tagNames[$value] ) ) {
 146+ $value = self::$tagNames[$value];
 147+ }
 148+ break;
 149+ }
 150+ }
 151+
 152+ static function buildTag($tagId, $contents) {
 153+ if ( is_int( $tagId ) && $tagId < 31 ) {
 154+ if ( $tagId == self::SEQUENCE || $tagId == self::SET ) {
 155+ $tagId |= 0x20; // Mark as structured data
 156+ }
 157+ $out = chr( $tagId );
 158+ } else {
 159+ throw new ASN1Exception( 'Code to build tags in high-tag-number form is not written yet' );
 160+ }
 161+ $out .= self::encodeLength( strlen( $contents ) );
 162+ $out .= $contents;
 163+
 164+ return $out;
 165+ }
 166+}
Property changes on: trunk/extensions/TorBlock/ASN1Parser.php
___________________________________________________________________
Added: svn:eol-style
1167 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r110158Trim trailing whitespace from r105244reedy20:05, 27 January 2012
r110160Reuse constants for array keysreedy20:13, 27 January 2012
r110164Follow-up r105244, remove dummy else branch, it was there...platonides20:40, 27 January 2012

Comments

#Comment by Aaron Schulz (talk | contribs)   00:43, 20 January 2012

Can you reuse the constants in the array keys rather than set by hand? I know you can have things like "protected $member = self::X" in PHP.

#Comment by Reedy (talk | contribs)   20:03, 27 January 2012
reedy@ubuntu64-web-esxi:~$ cat test.php
<?php

$array = array(
        1 => LOLCONST
);

const LOLCONST = 10;
reedy@ubuntu64-web-esxi:~$ php -l test.php
No syntax errors detected in test.php
#Comment by Reedy (talk | contribs)   20:10, 27 January 2012

Doesn't work directly in a class though, needs self::CONSTANT


reedy@ubuntu64-web-esxi:~$ cat test.php
<?php

class Foo{
$array = array(
        1 => LOLCONST
);

const LOLCONST = 10;
}
reedy@ubuntu64-web-esxi:~$ php -l test.php
PHP Parse error:  syntax error, unexpected T_VARIABLE, expecting T_FUNCTION in test.php on line 4
Errors parsing test.php

#Comment by Reedy (talk | contribs)   20:14, 27 January 2012

What's going on here?

			if ( $constructed ) {
				$item['contents'] = self::decode( $item['contents'] );
			} elseif ( $tag == 6 ) {
				/* We could show the pretty name here instead of the hex dump
				 *
				 * a source could be crypto/objects/objects.txt from openssl
				 * project or crypto/objects/obj_dat.txt (where hexadecimal
				 * data is available )
				 */
				 $item['contents'] = $item['contents'];
			} else {
				$item['contents'] = $item['contents'];
			}

Assiging the variable back to itself? :/


Code not so much of an issue as it's not used by anything yet...

#Comment by MaxSem (talk | contribs)   10:52, 31 January 2012

Would be great if this had some tests.

Status & tagging log