mirror of
https://github.com/danog/phpseclib.git
synced 2025-01-22 04:51:19 +01:00
ASN1/X509: latch effective type of ANY fields as an additional indexing level.
This commit is contained in:
parent
9e803fe374
commit
340ee0cd2d
@ -195,6 +195,41 @@ class File_ASN1 {
|
||||
*/
|
||||
var $filters;
|
||||
|
||||
/**
|
||||
* Type mapping table for the ANY type.
|
||||
*
|
||||
* Structured or unknown types are mapped to a 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
|
||||
* @access private
|
||||
*/
|
||||
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'
|
||||
);
|
||||
|
||||
/**
|
||||
* Parse BER-encoding
|
||||
*
|
||||
@ -444,6 +479,16 @@ class File_ASN1 {
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case $mapping['type'] == FILE_ASN1_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']));
|
||||
}
|
||||
$inmap = $this->ANYmap[$intype];
|
||||
if (is_string($inmap)) {
|
||||
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping));
|
||||
}
|
||||
break;
|
||||
case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
|
||||
foreach ($mapping['children'] as $key => $option) {
|
||||
switch (true) {
|
||||
@ -459,7 +504,6 @@ class File_ASN1 {
|
||||
case isset($mapping['implicit']):
|
||||
case isset($mapping['explicit']):
|
||||
case $decoded['type'] == $mapping['type']:
|
||||
case $mapping['type'] == FILE_ASN1_TYPE_ANY:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
@ -469,14 +513,6 @@ class File_ASN1 {
|
||||
$decoded['type'] = $mapping['type'];
|
||||
}
|
||||
|
||||
if ($mapping['type'] == FILE_ASN1_TYPE_ANY) {
|
||||
if ($decoded['type'] == FILE_ASN1_TYPE_SEQUENCE || $decoded['type'] == FILE_ASN1_TYPE_SET) {
|
||||
// return $this->encode_der($decoded['content']);
|
||||
//return serialize($decoded['content']);
|
||||
return substr($this->encoded, $decoded['start'], $decoded['length']);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($decoded['type']) {
|
||||
case FILE_ASN1_TYPE_SEQUENCE:
|
||||
$map = array();
|
||||
@ -920,14 +956,31 @@ class File_ASN1 {
|
||||
}
|
||||
break;
|
||||
case FILE_ASN1_TYPE_ANY:
|
||||
if (!isset($source)) {
|
||||
if (isset($idx)) {
|
||||
array_pop($this->location);
|
||||
}
|
||||
return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL));
|
||||
$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);
|
||||
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);
|
||||
case is_float($source):
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping);
|
||||
case is_bool($source):
|
||||
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
$filters = $this->filters;
|
||||
foreach ($this->location as $part) {
|
||||
foreach ($loc as $part) {
|
||||
if (!isset($filters[$part])) {
|
||||
$filters = false;
|
||||
break;
|
||||
@ -935,13 +988,10 @@ class File_ASN1 {
|
||||
$filters = $filters[$part];
|
||||
}
|
||||
if ($filters === false) {
|
||||
user_error('No filters defined for ' . implode('/', $this->location), E_USER_NOTICE);
|
||||
user_error('No filters defined for ' . implode('/', $loc), E_USER_NOTICE);
|
||||
return false;
|
||||
}
|
||||
if (isset($idx)) {
|
||||
array_pop($this->location);
|
||||
}
|
||||
return $this->_encode_der($source, $filters);
|
||||
return $this->_encode_der($source, $filters + $mapping);
|
||||
case FILE_ASN1_TYPE_NULL:
|
||||
$value = '';
|
||||
break;
|
||||
@ -953,6 +1003,9 @@ class File_ASN1 {
|
||||
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:
|
||||
$value = $source;
|
||||
break;
|
||||
case FILE_ASN1_TYPE_BOOLEAN:
|
||||
|
@ -2033,10 +2033,11 @@ class File_X509 {
|
||||
*
|
||||
* @param String $propName
|
||||
* @param Mixed $propValue
|
||||
* @param String $type optional
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function setDNProp($propName, $propValue)
|
||||
function setDNProp($propName, $propValue, $type = 'utf8String')
|
||||
{
|
||||
if (empty($this->dn)) {
|
||||
$this->dn = array('rdnSequence' => array());
|
||||
@ -2046,13 +2047,17 @@ class File_X509 {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ((array) $propValue as $v)
|
||||
foreach ((array) $propValue as $v) {
|
||||
if (!is_array($v) && isset($type)) {
|
||||
$v = array($type => $v);
|
||||
}
|
||||
$this->dn['rdnSequence'][] = array(
|
||||
array(
|
||||
'type' => $propName,
|
||||
'value'=> $v
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2088,10 +2093,12 @@ class File_X509 {
|
||||
* Get Distinguished Name properties
|
||||
*
|
||||
* @param String $propName
|
||||
* @param Array $dn optional
|
||||
* @param Boolean $withType optional
|
||||
* @return Mixed
|
||||
* @access public
|
||||
*/
|
||||
function getDNProp($propName, $dn = NULL)
|
||||
function getDNProp($propName, $dn = NULL, $withType = false)
|
||||
{
|
||||
if (!isset($dn)) {
|
||||
$dn = $this->dn;
|
||||
@ -2109,7 +2116,11 @@ class File_X509 {
|
||||
$result = array();
|
||||
for ($i = 0; $i < count($dn); $i++) {
|
||||
if ($dn[$i][0]['type'] == $propName) {
|
||||
$result[] = $dn[$i][0]['value'];
|
||||
$v = $dn[$i][0]['value'];
|
||||
if (!$withType && is_array($v) && count($v) == 1) {
|
||||
$v = array_pop($v);
|
||||
}
|
||||
$result[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2121,10 +2132,11 @@ class File_X509 {
|
||||
*
|
||||
* @param Mixed $dn
|
||||
* @param Boolean $merge optional
|
||||
* @param String $type optional
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function setDN($dn, $merge = false)
|
||||
function setDN($dn, $merge = false, $type = 'utf8String')
|
||||
{
|
||||
if (!$merge) {
|
||||
$this->dn = NULL;
|
||||
@ -2137,8 +2149,8 @@ class File_X509 {
|
||||
}
|
||||
|
||||
// handles stuff generated by openssl_x509_parse()
|
||||
foreach ($dn as $type => $value) {
|
||||
if (!$this->setDNProp($type, $value)) {
|
||||
foreach ($dn as $prop => $value) {
|
||||
if (!$this->setDNProp($prop, $value, $type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2148,9 +2160,9 @@ class File_X509 {
|
||||
// handles everything else
|
||||
$results = preg_split('#((?:^|, |/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
for ($i = 1; $i < count($results); $i+=2) {
|
||||
$type = trim($results[$i], ', =/');
|
||||
$prop = trim($results[$i], ', =/');
|
||||
$value = $results[$i + 1];
|
||||
if (!$this->setDNProp($type, $value)) {
|
||||
if (!$this->setDNProp($prop, $value, $type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2162,6 +2174,7 @@ class File_X509 {
|
||||
* Get the Distinguished Name for a certificates subject
|
||||
*
|
||||
* @param Boolean $string optional
|
||||
* @param Array $dn optional
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
@ -2177,11 +2190,11 @@ class File_X509 {
|
||||
|
||||
$start = true;
|
||||
foreach ($dn['rdnSequence'] as $field) {
|
||||
$type = $field[0]['type'];
|
||||
$prop = $field[0]['type'];
|
||||
$value = $field[0]['value'];
|
||||
|
||||
$delim = ', ';
|
||||
switch ($type) {
|
||||
switch ($prop) {
|
||||
case 'id-at-countryName':
|
||||
$desc = 'C=';
|
||||
break;
|
||||
@ -2209,12 +2222,15 @@ class File_X509 {
|
||||
break;
|
||||
default:
|
||||
$delim = '/';
|
||||
$desc = preg_replace('#.+-([^-]+)$#', '$1', $type) . '=';
|
||||
$desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '=';
|
||||
}
|
||||
|
||||
if (!$start) {
|
||||
$output.= $delim;
|
||||
}
|
||||
if (is_array($value) && count($value) == 1) {
|
||||
$value = array_pop($value); // Always strip data type.
|
||||
}
|
||||
$output.= $desc . $value;
|
||||
$start = false;
|
||||
}
|
||||
@ -2254,28 +2270,30 @@ class File_X509 {
|
||||
* Get an individual Distinguished Name property for a certificates issuer
|
||||
*
|
||||
* @param String $propName
|
||||
* @param Boolean $withType optional
|
||||
* @access public
|
||||
* @return Mixed
|
||||
*/
|
||||
function getIssuerDNProp($propName)
|
||||
function getIssuerDNProp($propName, $withType = false)
|
||||
{
|
||||
if (!isset($this->currentCert) || !is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer']);
|
||||
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of getDNProp()
|
||||
*
|
||||
* @param String $propName
|
||||
* @param Boolean $withType optional
|
||||
* @access public
|
||||
* @return Mixed
|
||||
*/
|
||||
function getSubjectDNProp($propName)
|
||||
function getSubjectDNProp($propName, $withType = false)
|
||||
{
|
||||
return $this->getDNProp($propName);
|
||||
return $this->getDNProp($propName, NULL, $withType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user