RegistrationResult::determineIdentifier()   A
last analyzed

Complexity

Conditions 6
Paths 5

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 5
nop 0
dl 0
loc 22
ccs 0
cts 11
cp 0
crap 42
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
namespace MadWizard\WebAuthn\Server\Registration;
4
5
use MadWizard\WebAuthn\Attestation\AttestationObject;
6
use MadWizard\WebAuthn\Attestation\AuthenticatorData;
7
use MadWizard\WebAuthn\Attestation\Identifier\AttestationKeyIdentifier;
8
use MadWizard\WebAuthn\Attestation\Identifier\IdentifierInterface;
9
use MadWizard\WebAuthn\Attestation\Statement\FidoU2fAttestationStatement;
10
use MadWizard\WebAuthn\Attestation\TrustAnchor\MetadataInterface;
11
use MadWizard\WebAuthn\Attestation\TrustPath\CertificateTrustPath;
12
use MadWizard\WebAuthn\Attestation\Verifier\VerificationResult;
13
use MadWizard\WebAuthn\Credential\CredentialId;
14
use MadWizard\WebAuthn\Credential\UserHandle;
15
use MadWizard\WebAuthn\Crypto\CoseKeyInterface;
16
use MadWizard\WebAuthn\Pki\CertificateDetails;
17
18
final class RegistrationResult implements RegistrationResultInterface // TODO: use interface everywhere
19
{
20
    /**
21
     * @var CredentialId
22
     */
23
    private $credentialId;
24
25
    /**
26
     * @var AuthenticatorData
27
     */
28
    private $authenticatorData;
29
30
    /**
31
     * @var VerificationResult
32
     */
33
    private $verificationResult;
34
35
    /**
36
     * @var MetadataInterface|null
37
     */
38
    private $metadata;
39
40
    /**
41
     * @var AttestationObject
42
     */
43
    private $attestationObject;
44
45
    /**
46
     * @var IdentifierInterface|false|null
47
     */
48
    private $cachedIdentifier = false;
49
50
    /**
51
     * @var UserHandle
52
     */
53
    private $userHandle;
54
55 1
    public function __construct(CredentialId $credentialId, AuthenticatorData $authenticatorData, AttestationObject $attestationObject, VerificationResult $verificationResult, UserHandle $userHandle, ?MetadataInterface $metadata = null)
56
    {
57 1
        $this->credentialId = $credentialId;
58 1
        $this->authenticatorData = $authenticatorData;
59 1
        $this->verificationResult = $verificationResult;
60 1
        $this->metadata = $metadata;
61 1
        $this->attestationObject = $attestationObject;
62 1
        $this->userHandle = $userHandle;
63 1
    }
64
65 1
    public function getCredentialId(): CredentialId
66
    {
67 1
        return $this->credentialId;
68
    }
69
70 1
    public function getPublicKey(): CoseKeyInterface
71
    {
72 1
        return $this->authenticatorData->getKey();
73
    }
74
75 1
    public function getUserHandle(): UserHandle
76
    {
77 1
        return $this->userHandle;
78
    }
79
80 1
    public function getVerificationResult(): VerificationResult
81
    {
82 1
        return $this->verificationResult;
83
    }
84
85
    public function getSignatureCounter(): int
86
    {
87
        return $this->authenticatorData->getSignCount();
88
    }
89
90
    public function getAttestationObject(): AttestationObject
91
    {
92
        return $this->attestationObject;
93
    }
94
95
    public function getAuthenticatorData(): AuthenticatorData
96
    {
97
        return $this->authenticatorData;
98
    }
99
100
    public function getMetadata(): ?MetadataInterface
101
    {
102
        return $this->metadata;
103
    }
104
105
    public function getIdentifier(): ?IdentifierInterface
106
    {
107
        if ($this->cachedIdentifier === false) {
108
            $this->cachedIdentifier = $this->determineIdentifier();
109
        }
110
        return $this->cachedIdentifier;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->cachedIdentifier could return the type true which is incompatible with the type-hinted return MadWizard\WebAuthn\Attes...dentifierInterface|null. Consider adding an additional type-check to rule them out.
Loading history...
111
    }
112
113 1
    public function withMetadata(?MetadataInterface $metadata): RegistrationResult
114
    {
115 1
        return new RegistrationResult($this->credentialId, $this->authenticatorData, $this->attestationObject, $this->verificationResult, $this->userHandle, $metadata);
116
    }
117
118
    private static function pkIdFromPemCertificate(string $pem): IdentifierInterface
119
    {
120
        $cert = CertificateDetails::fromPem($pem);
121
        return new AttestationKeyIdentifier($cert->getPublicKeyIdentifier());
122
    }
123
124
    private function determineIdentifier(): ?IdentifierInterface
125
    {
126
        // If a valid AAGUID is present, this is the main identifier. Do not look for others.
127
        $identifier = $this->authenticatorData->getAaguid();
128
        if ($identifier !== null && !$identifier->isZeroAaguid()) {
129
            return $identifier;
130
        }
131
132
        // Use public key identifier for U2F only. Apple for example generates a certificate
133
        // for each credential using the credential's key so using the public key identifier
134
        // would 'leak' a personal public key to the MDS.
135
        if ($this->attestationObject->getFormat() === FidoU2fAttestationStatement::FORMAT_ID) {
136
            // If certificates are available, get the attestation certificate's public key identifier
137
            $trustPath = $this->verificationResult->getTrustPath();
138
            if ($trustPath instanceof CertificateTrustPath) {
139
                $certs = $trustPath->getCertificates();
140
                if (isset($certs[0])) {
141
                    return self::pkIdFromPemCertificate($certs[0]->asPem());
142
                }
143
            }
144
        }
145
        return null;
146
    }
147
148
    public function isUserVerified(): bool
149
    {
150
        return $this->authenticatorData->isUserVerified();
151
    }
152
}
153