Passed
Push — master ( 5c7e77...f5ca5a )
by Thomas
03:03
created

RegistrationResult::getIdentifier()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 6
rs 10
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\Crypto\CoseKeyInterface;
15
use MadWizard\WebAuthn\Pki\CertificateDetails;
16
17
final class RegistrationResult implements RegistrationResultInterface // TODO: use interface everywhere
18
{ // TODO: add credentialRegistration?
19
    /**
20
     * @var CredentialId
21
     */
22
    private $credentialId;
23
24
    /**
25
     * @var AuthenticatorData
26
     */
27
    private $authenticatorData;
28
29
    /**
30
     * @var VerificationResult
31
     */
32
    private $verificationResult;
33
34
    /**
35
     * @var MetadataInterface|null
36
     */
37
    private $metadata;
38
39
    /**
40
     * @var AttestationObject
41
     */
42
    private $attestationObject;
43
44
    /**
45
     * @var IdentifierInterface|false|null
46
     */
47
    private $cachedIdentifier = false;
48
49 1
    public function __construct(CredentialId $credentialId, AuthenticatorData $authenticatorData, AttestationObject $attestationObject, VerificationResult $verificationResult, ?MetadataInterface $metadata = null)
50
    {
51 1
        $this->credentialId = $credentialId;
52 1
        $this->authenticatorData = $authenticatorData;
53 1
        $this->verificationResult = $verificationResult;
54 1
        $this->metadata = $metadata;
55 1
        $this->attestationObject = $attestationObject;
56 1
    }
57
58 1
    public function getCredentialId(): CredentialId
59
    {
60 1
        return $this->credentialId;
61
    }
62
63 1
    public function getPublicKey(): CoseKeyInterface
64
    {
65 1
        return $this->authenticatorData->getKey();
66
    }
67
68 1
    public function getVerificationResult(): VerificationResult
69
    {
70 1
        return $this->verificationResult;
71
    }
72
73 1
    public function getSignatureCounter(): int
74
    {
75 1
        return $this->authenticatorData->getSignCount();
76
    }
77
78
    public function getAttestationObject(): AttestationObject
79
    {
80
        return $this->attestationObject;
81
    }
82
83
    public function getAuthenticatorData(): AuthenticatorData
84
    {
85
        return $this->authenticatorData;
86
    }
87
88
    public function getMetadata(): ?MetadataInterface
89
    {
90
        return $this->metadata;
91
    }
92
93
    public function getIdentifier(): ?IdentifierInterface
94
    {
95
        if ($this->cachedIdentifier === false) {
96
            $this->cachedIdentifier = $this->determineIdentifier();
97
        }
98
        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...
99
    }
100
101 1
    public function withMetadata(?MetadataInterface $metadata): RegistrationResult
102
    {
103 1
        return new RegistrationResult($this->credentialId, $this->authenticatorData, $this->attestationObject, $this->verificationResult, $metadata);
104
    }
105
106
    private static function pkIdFromPemCertificate(string $pem): IdentifierInterface
107
    {
108
        $cert = CertificateDetails::fromPem($pem);
109
        return new AttestationKeyIdentifier($cert->getPublicKeyIdentifier());
110
    }
111
112
    private function determineIdentifier(): ?IdentifierInterface
113
    {
114
        // If a valid AAGUID is present, this is the main identifier. Do not look for others.
115
        $identifier = $this->authenticatorData->getAaguid();
116
        if ($identifier !== null && !$identifier->isZeroAaguid()) {
117
            return $identifier;
118
        }
119
120
        // Use public key identifier for U2F only. Apple for example generates a certificate
121
        // for each credential using the credential's key so using the public key identifier
122
        // would 'leak' a personal public key to the MDS.
123
        if ($this->attestationObject->getFormat() === FidoU2fAttestationStatement::FORMAT_ID) {
124
            // If certificates are available, get the attestation certificate's public key identifier
125
            $trustPath = $this->verificationResult->getTrustPath();
126
            if ($trustPath instanceof CertificateTrustPath) {
127
                $certs = $trustPath->getCertificates();
128
                if (isset($certs[0])) {
129
                    return self::pkIdFromPemCertificate($certs[0]->asPem());
130
                }
131
            }
132
        }
133
        return null;
134
    }
135
}
136