Passed
Push — master ( 3266fb...94512e )
by Thomas
03:56 queued 01:13
created

TpmPublic::parseUnique()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.009

Importance

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