AttestationObjectLoader   A
last analyzed

Complexity

Total Complexity 4

Size/Duplication

Total Lines 45
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 45
rs 10
c 0
b 0
f 0
wmc 4

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A load() 0 33 3
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 Assert\Assertion;
17
use Base64Url\Base64Url;
18
use CBOR\Decoder;
19
use CBOR\MapObject;
20
use CBOR\StringStream;
21
use U2FAuthentication\Fido2\AttestedCredentialData;
22
use U2FAuthentication\Fido2\AuthenticationExtensions\AuthenticationExtensionsClientOutputsLoader;
23
use U2FAuthentication\Fido2\AuthenticatorData;
24
25
class AttestationObjectLoader
26
{
27
    private const FLAG_AT = 0b01000000;
28
    private const FLAG_ED = 0b10000000;
29
30
    private $decoder;
31
32
    public function __construct(Decoder $decoder)
33
    {
34
        $this->decoder = $decoder;
35
    }
36
37
    public function load(string $data): AttestationObject
38
    {
39
        $decodedData = Base64Url::decode($data);
40
        $stream = new StringStream($decodedData);
41
        $attestationObject = $this->decoder->decode($stream)->getNormalizedData();
42
        $authData = $attestationObject['authData'];
43
44
        $authDataStream = new StringStream($authData);
45
        $rp_id_hash = $authDataStream->read(32);
46
        $flags = $authDataStream->read(1);
47
        $signCount = $authDataStream->read(4);
48
        $signCount = unpack('N', $signCount)[1];
49
50
        $attestedCredentialData = null;
51
        if (\ord($flags) & self::FLAG_AT) {
52
            $aaguid = $authDataStream->read(16);
53
            $credentialLength = $authDataStream->read(2);
54
            $credentialLength = unpack('n', $credentialLength)[1];
55
            $credentialId = $authDataStream->read($credentialLength);
56
            $credentialPublicKey = $this->decoder->decode($authDataStream);
57
            Assertion::isInstanceOf($credentialPublicKey, MapObject::class, 'The data does not contain a valid credential public key.');
58
            $attestedCredentialData = new AttestedCredentialData($aaguid, $credentialId, (string) $credentialPublicKey);
59
        }
60
61
        $extension = null;
62
        if (\ord($flags) & self::FLAG_ED) {
63
            $extension = $this->decoder->decode($authDataStream);
64
            $extension = AuthenticationExtensionsClientOutputsLoader::load($extension);
65
        }
66
67
        $authenticatorData = new AuthenticatorData($authData, $rp_id_hash, $flags, $signCount, $attestedCredentialData, $extension);
68
69
        return new AttestationObject($data, new AttestationStatement($attestationObject['fmt'], $attestationObject['attStmt']), $authenticatorData);
70
    }
71
}
72