Passed
Push — master ( 3a2451...e6e9f9 )
by Thomas
08:19 queued 05:35
created

TpmPublic::parseParameters()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4.125

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 13
ccs 5
cts 10
cp 0.5
crap 4.125
rs 9.9666
1
<?php
2
3
namespace MadWizard\WebAuthn\Attestation\Tpm;
4
5
use MadWizard\WebAuthn\Exception\ParseException;
6
use MadWizard\WebAuthn\Exception\UnsupportedException;
7
use MadWizard\WebAuthn\Format\ByteBuffer;
8
9
/**
10
 * Represents TPMT_PUBLIC structure.
11
 */
12
final class TpmPublic extends AbstractTpmStructure
13
{
14
    public const TPM_ALG_RSA = 0x0001;
15
16
    public const TPM_ALG_ECC = 0x0023;
17
18
    public const TPM_ALG_NULL = 0x0010;
19
20
    public const TPM_ALG_SHA = 0x0004; // ISO/IEC 10118-3 the SHA1 algorithm
21
22
    public const TPM_ALG_SHA1 = 0x0004; // ISO/IEC 10118-3 redefinition for documentation consistency TPM
23
24
    public const TPM_ALG_SHA256 = 0x000B; // ISO/IEC 10118-3 the SHA 256 algorithm
25
26
    public const TPM_ALG_SHA384 = 0x000C; //  ISO/IEC 10118-3 the SHA 384 algorithm
27
28
    public const TPM_ALG_SHA512 = 0x000D; // ISO/IEC 10118-3 the SHA 512 algorithm
29
30
    private const PHP_HASH_ALG_MAP = [
31
        self::TPM_ALG_SHA1 => 'sha1',
32
        self::TPM_ALG_SHA256 => 'sha256',
33
        self::TPM_ALG_SHA384 => 'sha384',
34
        self::TPM_ALG_SHA512 => 'sha512',
35
    ];
36
37
    /**
38
     * @var int
39
     */
40
    private $type;
41
42
    /**
43
     * @var int
44
     */
45
    private $objectAttributes;
46
47
    /**
48
     * @var int
49
     */
50
    private $nameAlg;
51
52
    /**
53
     * @var string
54
     */
55
    private $rawData;
56
57
    /**
58
     * @var KeyParametersInterface
59
     */
60
    private $parameters;
61
62
    /**
63
     * @var ByteBuffer
64
     */
65
    private $unique;
66
67 5
    public function __construct(ByteBuffer $data)
68
    {
69 5
        $this->rawData = $data->getBinaryString();
70 5
        $this->type = $data->getUint16Val(0);
71
72 5
        $this->nameAlg = $data->getUint16Val(2);
73 5
        $this->objectAttributes = $data->getUint32Val(4);
74
75 5
        $offset = 8;
76
77
        // Auth policy
78 5
        $this->readLengthPrefixed($data, $offset);
79
80 5
        $this->parameters = $this->parseParameters($this->type, $data, $offset);
81
82 5
        $this->unique = $this->readLengthPrefixed($data, $offset);
83
84 5
        if ($offset !== $data->getLength()) {
85 1
            throw new ParseException('Unexpected bytes after TPMT_PUBLIC structure.');
86
        }
87 4
    }
88
89 5
    private function parseParameters(int $type, ByteBuffer $buffer, int &$offset): KeyParametersInterface
90
    {
91 5
        if ($type === self::TPM_ALG_RSA) {
92 5
            $parameters = TpmRsaParameters::parse($buffer, $offset, $endOffset);
93 5
            $offset = $endOffset;
94 5
            return $parameters;
95
        }
96
        if ($type === self::TPM_ALG_ECC) {
97
            $parameters = TpmEccParameters::parse($buffer, $offset, $endOffset);
98
            $offset = $endOffset;
99
            return $parameters;
100
        }
101
        throw new UnsupportedException(sprintf('TPM public key type %d is not supported.', $type));
102
    }
103
104 2
    public function getType(): int
105
    {
106 2
        return $this->type;
107
    }
108
109 1
    public function getObjectAttributes(): int
110
    {
111 1
        return $this->objectAttributes;
112
    }
113
114 2
    public function getParameters(): KeyParametersInterface
115
    {
116 2
        return $this->parameters;
117
    }
118
119 1
    public function getNameAlg(): int
120
    {
121 1
        return $this->nameAlg;
122
    }
123
124 2
    public function getUnique(): ByteBuffer
125
    {
126 2
        return $this->unique;
127
    }
128
129 3
    public function isValidPubInfoName(ByteBuffer $name): bool
130
    {
131
        // TPM names are prefixed by a 16-bit integer representing the hashing algorithm
132 3
        $algo = $name->getUint16Val(0);
133
134
        // The name itself is a concatenation of the algorithm and a hash of this whole structure.
135 3
        $phpAlgo = self::PHP_HASH_ALG_MAP[$algo] ?? null;
136 3
        if ($phpAlgo === null) {
137 1
            throw new UnsupportedException(sprintf('Algorithm 0x%04X is not allowed for names for TPMT_PUBLIC.', $algo));
138
        }
139
140 2
        $validName = pack('n', $algo) . hash($phpAlgo, $this->rawData, true);
141 2
        return \hash_equals($validName, $name->getBinaryString());
142
    }
143
}
144