Completed
Push — master ( 34f908...4c48cd )
by Florent
02:40
created

AttestationObjectLoader::getDecoder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace U2FAuthentication\Fido2\AttestationStatement;
15
16
use Base64Url\Base64Url;
17
use CBOR\Decoder;
18
use CBOR\MapObject;
19
use CBOR\StringStream;
20
use U2FAuthentication\Fido2\AttestedCredentialData;
21
use U2FAuthentication\Fido2\AuthenticatorData;
22
23
class AttestationObjectLoader
24
{
25
    private const FLAG_AT = 0b01000000;
26
    private const FLAG_ED = 0b10000000;
27
28
    private $decoder;
29
30
    public function __construct(Decoder $decoder)
31
    {
32
        $this->decoder = $decoder;
33
    }
34
35
    public function load(string $data): AttestationObject
36
    {
37
        $decodedData = Base64Url::decode($data);
38
        $stream = new StringStream($decodedData);
39
        $attestationObject = $this->decoder->decode($stream)->getNormalizedData();
40
        $authData = $attestationObject['authData'];
41
42
        $authDataStream = new StringStream($authData);
43
        $rp_id_hash = $authDataStream->read(32);
44
        $flags = $authDataStream->read(1);
45
        $signCount = $authDataStream->read(4);
46
        $signCount = unpack('N', $signCount)[1];
47
48
        if (\ord($flags) & self::FLAG_AT) {
49
            $aaguid = $authDataStream->read(16);
50
            $credentialLength = $authDataStream->read(2);
51
            $credentialLength = unpack('n', $credentialLength)[1];
52
            $credentialId = $authDataStream->read($credentialLength);
53
            $credentialPublicKey = $this->decoder->decode($authDataStream);
54
            if (!$credentialPublicKey instanceof MapObject) {
55
                throw new \InvalidArgumentException('The data does not contain a valid credential public key.');
56
            }
57
            $attestedCredentialData = new AttestedCredentialData($aaguid, $credentialId, (string) $credentialPublicKey);
58
        } else {
59
            $attestedCredentialData = null;
60
        }
61
62
        if (\ord($flags) & self::FLAG_ED) {
63
            $extension = $this->decoder->decode($authDataStream);
64
        } else {
65
            $extension = null;
66
        }
67
        $authenticatorData = new AuthenticatorData(
68
            $authData,
69
            $rp_id_hash,
70
            $flags,
71
            $signCount,
72
            $attestedCredentialData,
73
            $extension
74
        );
75
76
        return new AttestationObject(
77
            $data,
78
            new AttestationStatement($attestationObject['fmt'], $attestationObject['attStmt']),
79
            $authenticatorData
80
        );
81
    }
82
}
83