Check clock sequence and local identifier boundaries

This commit is contained in:
Ben Ramsey
2020-03-06 17:00:08 -06:00
parent 8a8d5d4ba8
commit 4a53d4d33d
3 changed files with 173 additions and 18 deletions
+44 -9
View File
@@ -15,7 +15,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Exception\DceSecurityException;
use Ramsey\Uuid\Provider\DceSecurityProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
@@ -25,6 +25,7 @@ use function hex2bin;
use function in_array;
use function pack;
use function str_pad;
use function strlen;
use function substr_replace;
use const STR_PAD_LEFT;
@@ -41,6 +42,16 @@ class DceSecurityGenerator implements DceSecurityGeneratorInterface
Uuid::DCE_DOMAIN_ORG,
];
/**
* Upper bounds for the clock sequence in DCE Security UUIDs.
*/
private const CLOCK_SEQ_HIGH = 63;
/**
* Lower bounds for the clock sequence in DCE Security UUIDs.
*/
private const CLOCK_SEQ_LOW = 0;
/**
* @var NumberConverterInterface
*/
@@ -73,15 +84,27 @@ class DceSecurityGenerator implements DceSecurityGeneratorInterface
?int $clockSeq = null
): string {
if (!in_array($localDomain, self::DOMAINS)) {
throw new InvalidArgumentException(
throw new DceSecurityException(
'Local domain must be a valid DCE Security domain'
);
}
if ($localIdentifier && $localIdentifier->isNegative()) {
throw new DceSecurityException(
'Local identifier out of bounds; it must be a value between 0 and 4294967295'
);
}
if ($clockSeq > self::CLOCK_SEQ_HIGH || $clockSeq < self::CLOCK_SEQ_LOW) {
throw new DceSecurityException(
'Clock sequence out of bounds; it must be a value between 0 and 63'
);
}
switch ($localDomain) {
case Uuid::DCE_DOMAIN_ORG:
if ($localIdentifier === null) {
throw new InvalidArgumentException(
throw new DceSecurityException(
'A local identifier must be provided for the org domain'
);
}
@@ -102,18 +125,30 @@ class DceSecurityGenerator implements DceSecurityGeneratorInterface
break;
}
$identifierHex = $this->numberConverter->toHex($localIdentifier->toString());
// The maximum value for the local identifier is 0xffffffff, or
// 4294967295. This is 8 hexadecimal digits, so if the length of
// hexadecimal digits is greater than 8, we know the value is greater
// than 0xffffffff.
if (strlen($identifierHex) > 8) {
throw new DceSecurityException(
'Local identifier out of bounds; it must be a value between 0 and 4294967295'
);
}
$domainByte = pack('n', $localDomain)[1];
$identifierBytes = hex2bin(str_pad(
$this->numberConverter->toHex($localIdentifier->toString()),
8,
'0',
STR_PAD_LEFT
));
$identifierBytes = hex2bin(str_pad($identifierHex, 8, '0', STR_PAD_LEFT));
if ($node instanceof Hexadecimal) {
$node = $node->toString();
}
// Shift the clock sequence 8 bits to the left, so it matches 0x3f00.
if ($clockSeq !== null) {
$clockSeq = $clockSeq << 8;
}
/** @var string $bytes */
$bytes = $this->timeGenerator->generate($node, $clockSeq);