mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-12-26 11:37:33 +00:00
ASN1: revamp how OIDs are handled
This commit is contained in:
parent
756b247446
commit
e793461543
@ -515,24 +515,7 @@ class File_ASN1
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
||||||
$temp = ord($content[$content_pos++]);
|
$current['content'] = $this->_decodeOID(substr($content, $content_pos));
|
||||||
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
|
|
||||||
$valuen = 0;
|
|
||||||
// process septets
|
|
||||||
$content_len = strlen($content);
|
|
||||||
while ($content_pos < $content_len) {
|
|
||||||
$temp = ord($content[$content_pos++]);
|
|
||||||
$valuen <<= 7;
|
|
||||||
$valuen |= $temp & 0x7F;
|
|
||||||
if (~$temp & 0x80) {
|
|
||||||
$current['content'].= ".$valuen";
|
|
||||||
$valuen = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// the eighth bit of the last byte should not be 1
|
|
||||||
//if ($temp >> 7) {
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
break;
|
break;
|
||||||
/* Each character string type shall be encoded as if it had been declared:
|
/* Each character string type shall be encoded as if it had been declared:
|
||||||
[UNIVERSAL x] IMPLICIT OCTET STRING
|
[UNIVERSAL x] IMPLICIT OCTET STRING
|
||||||
@ -1111,27 +1094,7 @@ class File_ASN1
|
|||||||
$value = base64_decode($source);
|
$value = base64_decode($source);
|
||||||
break;
|
break;
|
||||||
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
||||||
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
|
$value = $this->_encodeOID($source);
|
||||||
if ($oid === false) {
|
|
||||||
user_error('Invalid OID');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$value = '';
|
|
||||||
$parts = explode('.', $oid);
|
|
||||||
$value = chr(40 * $parts[0] + $parts[1]);
|
|
||||||
for ($i = 2; $i < count($parts); $i++) {
|
|
||||||
$temp = '';
|
|
||||||
if (!$parts[$i]) {
|
|
||||||
$temp = "\0";
|
|
||||||
} else {
|
|
||||||
while ($parts[$i]) {
|
|
||||||
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
|
|
||||||
$parts[$i] >>= 7;
|
|
||||||
}
|
|
||||||
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
|
|
||||||
}
|
|
||||||
$value.= $temp;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case FILE_ASN1_TYPE_ANY:
|
case FILE_ASN1_TYPE_ANY:
|
||||||
$loc = $this->location;
|
$loc = $this->location;
|
||||||
@ -1230,6 +1193,108 @@ class File_ASN1
|
|||||||
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BER-decode the OID
|
||||||
|
*
|
||||||
|
* Called by _decode_ber()
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function _decodeOID($content)
|
||||||
|
{
|
||||||
|
static $eighty;
|
||||||
|
if (!$eighty) {
|
||||||
|
$eighty = new Math_BigInteger(80);
|
||||||
|
}
|
||||||
|
|
||||||
|
$oid = array();
|
||||||
|
$pos = 0;
|
||||||
|
$len = strlen($content);
|
||||||
|
$n = new Math_BigInteger();
|
||||||
|
while ($pos < $len) {
|
||||||
|
$temp = ord($content[$pos++]);
|
||||||
|
$n = $n->bitwise_leftShift(7);
|
||||||
|
$n = $n->bitwise_or(new Math_BigInteger($temp & 0x7F));
|
||||||
|
if (~$temp & 0x80) {
|
||||||
|
$oid[] = $n;
|
||||||
|
$n = new Math_BigInteger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$part1 = array_shift($oid);
|
||||||
|
$first = floor(ord($content[0]) / 40);
|
||||||
|
/*
|
||||||
|
"This packing of the first two object identifier components recognizes that only three values are allocated from the root
|
||||||
|
node, and at most 39 subsequent values from nodes reached by X = 0 and X = 1."
|
||||||
|
|
||||||
|
-- https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22
|
||||||
|
*/
|
||||||
|
if ($first <= 2) { // ie. 0 <= ord($content[0]) < 120 (0x78)
|
||||||
|
array_unshift($oid, ord($content[0]) % 40);
|
||||||
|
array_unshift($oid, $first);
|
||||||
|
} else {
|
||||||
|
array_unshift($oid, $part1->subtract($eighty));
|
||||||
|
array_unshift($oid, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('.', $oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DER-encode the OID
|
||||||
|
*
|
||||||
|
* Called by _encode_der()
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function _encodeOID($source)
|
||||||
|
{
|
||||||
|
static $mask, $zero, $forty;
|
||||||
|
if (!$mask) {
|
||||||
|
$mask = new Math_BigInteger(0x7F);
|
||||||
|
$zero = new Math_BigInteger();
|
||||||
|
$forty = new Math_BigInteger(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
|
||||||
|
if ($oid === false) {
|
||||||
|
user_error('Invalid OID');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$parts = explode('.', $oid);
|
||||||
|
$part1 = array_shift($parts);
|
||||||
|
$part2 = array_shift($parts);
|
||||||
|
|
||||||
|
$first = new Math_BigInteger($part1);
|
||||||
|
$first = $first->multiply($forty);
|
||||||
|
$first = $first->add(new Math_BigInteger($part2));
|
||||||
|
|
||||||
|
array_unshift($parts, $first->toString());
|
||||||
|
|
||||||
|
$value = '';
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (!$part) {
|
||||||
|
$temp = "\0";
|
||||||
|
} else {
|
||||||
|
$temp = '';
|
||||||
|
$part = new Math_BigInteger($part);
|
||||||
|
while (!$part->equals($zero)) {
|
||||||
|
$submask = $part->bitwise_and($mask);
|
||||||
|
$submask->setPrecision(8);
|
||||||
|
$temp = (chr(0x80) | $submask->toBytes()) . $temp;
|
||||||
|
$part = $part->bitwise_rightShift(7);
|
||||||
|
}
|
||||||
|
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
|
||||||
|
}
|
||||||
|
$value.= $temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BER-decode the time (using UNIX time)
|
* BER-decode the time (using UNIX time)
|
||||||
*
|
*
|
||||||
|
@ -341,4 +341,26 @@ class Unit_File_ASN1Test extends PhpseclibTestCase
|
|||||||
$asn1 = new File_ASN1();
|
$asn1 = new File_ASN1();
|
||||||
$asn1->decodeBER($data);
|
$asn1->decodeBER($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group github1367
|
||||||
|
*/
|
||||||
|
public function testOIDs()
|
||||||
|
{
|
||||||
|
// from the example in 8.19.5 in the following:
|
||||||
|
// https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22
|
||||||
|
$orig = pack('H*', '813403');
|
||||||
|
$asn1 = new File_ASN1();
|
||||||
|
$new = $asn1->_decodeOID($orig);
|
||||||
|
$this->assertSame('2.100.3', $new);
|
||||||
|
$this->assertSame($orig, $asn1->_encodeOID($new));
|
||||||
|
|
||||||
|
// UUID OID from the following:
|
||||||
|
// https://healthcaresecprivacy.blogspot.com/2011/02/creating-and-using-unique-id-uuid-oid.html
|
||||||
|
$orig = '2.25.329800735698586629295641978511506172918';
|
||||||
|
$asn1 = new File_ASN1();
|
||||||
|
$new = $asn1->_encodeOID($orig);
|
||||||
|
$this->assertSame(pack('H*', '6983f09da7ebcfdee0c7a1a7b2c0948cc8f9d776'), $new);
|
||||||
|
$this->assertSame($orig, $asn1->_decodeOID($new));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user