1
0
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:
Patrick Monnerat 2012-10-23 13:37:51 +02:00
parent 9e803fe374
commit 340ee0cd2d
2 changed files with 107 additions and 36 deletions

View File

@ -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:

View File

@ -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);
}
/**