Test Failed
Push — master ( 51d50e...3266fb )
by Thomas
06:40 queued 03:58
created

TpmPublic::parseUnique()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 3
dl 0
loc 13
ccs 5
cts 5
cp 1
crap 3
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 5
    private $unique;
68
69 5
    public function __construct(ByteBuffer $data)
70 5
    {
71
        $this->rawData = $data->getBinaryString();
72 5
        $this->type = $data->getUint16Val(0);
73 5
74
        $this->nameAlg = $data->getUint16Val(2);
75 5
        $this->objectAttributes = $data->getUint32Val(4);
76
77
        $offset = 8;
78 5
79
        // Auth policy
80 5
        self::readLengthPrefixed($data, $offset);
81
82 5
        $this->parameters = $this->parseParameters($this->type, $data, $offset);
83
        $this->unique = $this->parseUnique($this->type, $data, $offset);
84 5
85 1
        if ($offset !== $data->getLength()) {
86
            throw new ParseException('Unexpected bytes after TPMT_PUBLIC structure.');
87 4
        }
88
    }
89 5
90
    private function parseParameters(int $type, ByteBuffer $buffer, int &$offset): KeyParametersInterface
91 5
    {
92 5
        if ($type === self::TPM_ALG_RSA) {
93 5
            $parameters = TpmRsaParameters::parse($buffer, $offset, $endOffset);
94 5
            $offset = $endOffset;
95
            return $parameters;
96
        }
97
        if ($type === self::TPM_ALG_ECC) {
98
            $parameters = TpmEccParameters::parse($buffer, $offset, $endOffset);
99
            $offset = $endOffset;
100
            return $parameters;
101
        }
102
        throw new UnsupportedException(sprintf('TPM public key type %d is not supported.', $type));
103
    }
104 2
105
    private function parseUnique(int $type, ByteBuffer $buffer, int &$offset): KeyPublicIdInterface
106 2
    {
107
        if ($type === self::TPM_ALG_RSA) {
108
            $unique = TpmRsaPublicId::parse($buffer, $offset, $endOffset);
109 1
            $offset = $endOffset;
110
            return $unique;
111 1
        }
112
        if ($type === self::TPM_ALG_ECC) {
113
            $unique = TpmEccPublicId::parse($buffer, $offset, $endOffset);
114 2
            $offset = $endOffset;
115
            return $unique;
116 2
        }
117
        throw new UnsupportedException(sprintf('TPM public key type %d is not supported.', $type));
118
    }
119 1
120
    public function getType(): int
121 1
    {
122
        return $this->type;
123
    }
124 2
125
    public function getObjectAttributes(): int
126 2
    {
127
        return $this->objectAttributes;
128
    }
129 3
130
    public function getParameters(): KeyParametersInterface
131
    {
132 3
        return $this->parameters;
133
    }
134
135 3
    public function getNameAlg(): int
136 3
    {
137 1
        return $this->nameAlg;
138
    }
139
140 2
    public function getUnique(): KeyPublicIdInterface
141 2
    {
142
        return $this->unique;
143
    }
144
145
    public function isValidPubInfoName(ByteBuffer $name): bool
146
    {
147
        // TPM names are prefixed by a 16-bit integer representing the hashing algorithm
148
        $algo = $name->getUint16Val(0);
149
150
        // The name itself is a concatenation of the algorithm and a hash of this whole structure.
151
        $phpAlgo = self::PHP_HASH_ALG_MAP[$algo] ?? null;
152
        if ($phpAlgo === null) {
153
            throw new UnsupportedException(sprintf('Algorithm 0x%04X is not allowed for names for TPMT_PUBLIC.', $algo));
154
        }
155
156
        $validName = pack('n', $algo) . hash($phpAlgo, $this->rawData, true);
157
        return \hash_equals($validName, $name->getBinaryString());
158
    }
159
}
160