Merge branch 'datetime-1.0' into datetime-2.0

This commit is contained in:
terrafrost 2017-08-24 12:50:00 -05:00
commit 221a9be8e6
2 changed files with 57 additions and 34 deletions

View File

@ -25,6 +25,8 @@ namespace phpseclib\File;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
use DateTime;
use DateTimeZone;
/**
* Pure-PHP ASN.1 Parser
@ -707,7 +709,7 @@ class ASN1
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
}
return @date($this->format, $decoded['content']);
return $decoded['content'] ? $decoded['content']->format($this->format) : false;
case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$offset = ord($decoded['content'][0]);
@ -956,7 +958,8 @@ class ASN1
case self::TYPE_GENERALIZED_TIME:
$format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
$format.= 'mdHis';
$value = @gmdate($format, strtotime($source)) . 'Z';
$date = new DateTime($source, new DateTimeZone('GMT'));
$value = $date->format($format) . 'Z';
break;
case self::TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
@ -1137,33 +1140,32 @@ class ASN1
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
$pattern = $tag == self::TYPE_UTC_TIME ?
'#^(..)(..)(..)(..)(..)(..)?(.*)$#' :
'#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
preg_match($pattern, $content, $matches);
list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
$format = 'YmdHis';
if ($tag == self::TYPE_UTC_TIME) {
$year = $year >= 50 ? "19$year" : "20$year";
}
if ($timezone == 'Z') {
$mktime = 'gmmktime';
$timezone = 0;
} elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
$mktime = 'gmmktime';
$timezone = 60 * $matches[3] + 3600 * $matches[2];
if ($matches[1] == '-') {
$timezone = -$timezone;
// https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
// element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
// browsers parse it phpseclib ought to too
if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
$content = $matches[1] . '00' . $matches[2];
}
} else {
$mktime = 'mktime';
$timezone = 0;
$prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
$content = $prefix . $content;
} elseif (strpos($content, '.') !== false) {
$format.= '.u';
}
return @$mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year) + $timezone;
if ($content[strlen($content) - 1] == 'Z') {
$content = substr($content, 0, -1) . '+0000';
}
if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
$format.= 'O';
}
// error supression isn't necessary as of PHP 7.0:
// http://php.net/manual/en/migration70.other-changes.php
return @DateTime::createFromFormat($format, $content);
}
/**

View File

@ -31,6 +31,8 @@ use phpseclib\Crypt\Random;
use phpseclib\Crypt\RSA;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
use DateTime;
use DateTimeZone;
/**
* Pure-PHP X.509 Parser
@ -2082,7 +2084,7 @@ class X509
}
if (!isset($date)) {
$date = time();
$date = new DateTime($date, new DateTimeZone(date_default_timezone_get()));
}
$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
@ -2092,8 +2094,8 @@ class X509
$notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
switch (true) {
case $date < @strtotime($notBefore):
case $date > @strtotime($notAfter):
case $date < new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get())):
case $date > new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get())):
return false;
}
@ -3338,7 +3340,11 @@ class X509
*/
function _timeField($date)
{
$year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
if ($date instanceof Element) {
return $date;
}
$dateObj = new DateTime($date, new DateTimeZone('GMT'));
$year = $dateObj->format('Y'); // the same way ASN1.php parses this
if ($year < 2050) {
return array('utcTime' => $date);
} else {
@ -3403,8 +3409,12 @@ class X509
return false;
}
$startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
$endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
$startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
$endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
$endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
/* "The serial number MUST be a positive integer"
"Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
-- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
@ -3672,7 +3682,9 @@ class X509
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
$thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
$thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
$this->currentCert = $crl->currentCert;
@ -3823,7 +3835,11 @@ class X509
*/
function setStartDate($date)
{
$this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
if (!is_object($date) || !is_a($date, 'DateTime')) {
$date = new DateTime($date);
}
$this->startDate = $date->format('D, d M Y H:i:s O');
}
/**
@ -3847,7 +3863,11 @@ class X509
$temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
$this->endDate = new Element($temp);
} else {
$this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
if (!is_object($date) || !is_a($date, 'DateTime')) {
$date = new DateTime($date);
}
$this->endDate = $date->format('D, d M Y H:i:s O');
}
}
@ -4577,8 +4597,9 @@ class X509
}
$i = count($rclist);
$revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$rclist[] = array('userCertificate' => $serial,
'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O')));
'revocationDate' => $this->_timeField($revocationDate->format('D, d M Y H:i:s O')));
return $i;
}