Update website
This commit is contained in:
parent
bb4b0f9be8
commit
011b183e28
4263 changed files with 3014 additions and 720369 deletions
|
@ -1,289 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\WebAuthn;
|
||||
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
use function ord;
|
||||
use function unpack;
|
||||
|
||||
use const INF;
|
||||
use const NAN;
|
||||
|
||||
/**
|
||||
* Concise Binary Object Representation (CBOR) decoder.
|
||||
*
|
||||
* This is not a general purpose CBOR decoder and only implements the CTAP2 canonical CBOR encoding form.
|
||||
*
|
||||
* @see https://www.rfc-editor.org/rfc/rfc7049
|
||||
* @see https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#message-encoding
|
||||
*/
|
||||
final class CBORDecoder
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
public function decode(DataStream $stream)
|
||||
{
|
||||
return $this->wellFormed($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://www.rfc-editor.org/rfc/rfc7049#appendix-C
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function wellFormed(DataStream $stream)
|
||||
{
|
||||
// process initial bytes
|
||||
$initialByte = ord($stream->take(1));
|
||||
$majorType = $initialByte >> 5;
|
||||
$value = $additionalInformation = $initialByte & 0x1f;
|
||||
switch ($additionalInformation) {
|
||||
case 24:
|
||||
if ($majorType !== 7) {
|
||||
$value = ord($stream->take(1));
|
||||
}
|
||||
|
||||
break;
|
||||
case 25:
|
||||
if ($majorType !== 7) {
|
||||
$unpackedValue = unpack('n', $stream->take(2));
|
||||
Assert::isArray($unpackedValue);
|
||||
Assert::keyExists($unpackedValue, 1);
|
||||
Assert::integer($unpackedValue[1]);
|
||||
$value = $unpackedValue[1];
|
||||
}
|
||||
|
||||
break;
|
||||
case 26:
|
||||
if ($majorType !== 7) {
|
||||
$unpackedValue = unpack('N', $stream->take(4));
|
||||
Assert::isArray($unpackedValue);
|
||||
Assert::keyExists($unpackedValue, 1);
|
||||
Assert::integer($unpackedValue[1]);
|
||||
$value = $unpackedValue[1];
|
||||
}
|
||||
|
||||
break;
|
||||
case 27:
|
||||
if ($majorType !== 7) {
|
||||
$unpackedValue = unpack('J', $stream->take(8));
|
||||
Assert::isArray($unpackedValue);
|
||||
Assert::keyExists($unpackedValue, 1);
|
||||
Assert::integer($unpackedValue[1]);
|
||||
$value = $unpackedValue[1];
|
||||
}
|
||||
|
||||
break;
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
throw new WebAuthnException();
|
||||
}
|
||||
|
||||
// process content
|
||||
switch ($majorType) {
|
||||
case 0:
|
||||
return $this->getUnsignedInteger($value);
|
||||
|
||||
case 1:
|
||||
return $this->getNegativeInteger($value);
|
||||
|
||||
case 2:
|
||||
return $this->getByteString($stream, $value);
|
||||
|
||||
case 3:
|
||||
return $this->getTextString($stream, $value);
|
||||
|
||||
case 4:
|
||||
return $this->getList($stream, $value);
|
||||
|
||||
case 5:
|
||||
return $this->getMap($stream, $value);
|
||||
|
||||
case 6:
|
||||
return $this->getTag($stream);
|
||||
|
||||
case 7:
|
||||
return $this->getFloatNumberOrSimpleValue($stream, $value, $additionalInformation);
|
||||
|
||||
default:
|
||||
throw new WebAuthnException();
|
||||
}
|
||||
}
|
||||
|
||||
private function getUnsignedInteger(int $value): int
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function getNegativeInteger(int $value): int
|
||||
{
|
||||
return -1 - $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getByteString(DataStream $stream, int $value): string
|
||||
{
|
||||
return $stream->take($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getTextString(DataStream $stream, int $value): string
|
||||
{
|
||||
return $stream->take($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return list<mixed>
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getList(DataStream $stream, int $value): array
|
||||
{
|
||||
$list = [];
|
||||
for ($i = 0; $i < $value; $i++) {
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
$list[] = $this->wellFormed($stream);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return array<array-key, mixed>
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getMap(DataStream $stream, int $value): array
|
||||
{
|
||||
$map = [];
|
||||
for ($i = 0; $i < $value; $i++) {
|
||||
/** @psalm-suppress MixedAssignment, MixedArrayOffset */
|
||||
$map[$this->wellFormed($stream)] = $this->wellFormed($stream);
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getTag(DataStream $stream)
|
||||
{
|
||||
// 1 embedded data item
|
||||
return $this->wellFormed($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getFloatNumberOrSimpleValue(DataStream $stream, int $value, int $additionalInformation)
|
||||
{
|
||||
switch ($additionalInformation) {
|
||||
case 20:
|
||||
return true;
|
||||
|
||||
case 21:
|
||||
return false;
|
||||
|
||||
case 22:
|
||||
return null;
|
||||
|
||||
case 24:
|
||||
// simple value
|
||||
return ord($stream->take(1));
|
||||
|
||||
case 25:
|
||||
return $this->getHalfFloat($stream);
|
||||
|
||||
case 26:
|
||||
return $this->getSingleFloat($stream);
|
||||
|
||||
case 27:
|
||||
return $this->getDoubleFloat($stream);
|
||||
|
||||
case 31:
|
||||
// "break" stop code for indefinite-length items
|
||||
throw new WebAuthnException();
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IEEE 754 Half-Precision Float (16 bits follow)
|
||||
*
|
||||
* @see https://www.rfc-editor.org/rfc/rfc7049#appendix-D
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getHalfFloat(DataStream $stream): float
|
||||
{
|
||||
$value = unpack('n', $stream->take(2));
|
||||
Assert::isArray($value);
|
||||
Assert::keyExists($value, 1);
|
||||
Assert::integer($value[1]);
|
||||
|
||||
$half = $value[1];
|
||||
$exp = ($half >> 10) & 0x1f;
|
||||
$mant = $half & 0x3ff;
|
||||
|
||||
if ($exp === 0) {
|
||||
$val = $mant * (2 ** -24);
|
||||
} elseif ($exp !== 31) {
|
||||
$val = ($mant + 1024) * (2 ** ($exp - 25));
|
||||
} else {
|
||||
$val = $mant === 0 ? INF : NAN;
|
||||
}
|
||||
|
||||
return $half & 0x8000 ? -$val : $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* IEEE 754 Single-Precision Float (32 bits follow)
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getSingleFloat(DataStream $stream): float
|
||||
{
|
||||
$value = unpack('G', $stream->take(4));
|
||||
Assert::isArray($value);
|
||||
Assert::keyExists($value, 1);
|
||||
Assert::float($value[1]);
|
||||
|
||||
return $value[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* IEEE 754 Double-Precision Float (64 bits follow)
|
||||
*
|
||||
* @throws WebAuthnException
|
||||
*/
|
||||
private function getDoubleFloat(DataStream $stream): float
|
||||
{
|
||||
$value = unpack('E', $stream->take(8));
|
||||
Assert::isArray($value);
|
||||
Assert::keyExists($value, 1);
|
||||
Assert::float($value[1]);
|
||||
|
||||
return $value[1];
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue