Failed Conditions
Push — master ( c7c4bc...234d27 )
by Florent
01:37
created

PublicKeyCredentialCreationValidator::check()   C

Complexity

Conditions 15
Paths 13

Size

Total Lines 74
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 32
nc 13
nop 3
dl 0
loc 74
rs 5.9166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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;
15
16
use U2FAuthentication\Fido2\AttestationStatement\AttestationStatementSupportManager;
17
18
class PublicKeyCredentialCreationValidator
19
{
20
    private $attestationStatementSupportManager;
21
    private $credentialIdRepository;
22
23
    public function __construct(AttestationStatementSupportManager $attestationStatementSupportManager, CredentialIdRepository $credentialIdRepository)
24
    {
25
        $this->attestationStatementSupportManager = $attestationStatementSupportManager;
26
        $this->credentialIdRepository = $credentialIdRepository;
27
    }
28
29
    /**
30
     * @see https://www.w3.org/TR/webauthn/#registering-a-new-credential
31
     */
32
    public function check(PublicKeyCredential $publicKeyCredential, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, ?string $rpId = null): void
33
    {
34
        /** @see 7.1.2 */
35
        $C = $publicKeyCredential->getResponse()->getClientDataJSON();
36
37
        /** @see 7.1.3 */
38
        if ('webauthn.create' !== $C->getType()) {
39
            throw new \InvalidArgumentException('The client data type is not "webauthn.create".');
40
        }
41
42
        /** @see 7.1.4 */
43
        if (hash_equals($publicKeyCredentialCreationOptions->getChallenge(), $C->getChallenge())) {
44
            throw new \InvalidArgumentException('Invalid challenge.');
45
        }
46
47
        /** @see 7.1.5 */
48
        if ($rpId === null && $publicKeyCredentialCreationOptions->getRp()->getId() === null) {
49
            throw new \InvalidArgumentException('No rpId.');
50
        }
51
        $rpId = $rpId ?? $publicKeyCredentialCreationOptions->getRp()->getId();
52
        if ($C->getOrigin() !== $rpId) {
53
            throw new \InvalidArgumentException('rpId mismatch.');
54
        }
55
56
        /** @see 7.1.6 */
57
        if ($C->getTokenBinding()) {
58
            throw new \InvalidArgumentException('Token binding not supported.');
59
        }
60
61
        /** @see 7.1.7 */
62
        $getClientDataJSONHash = hash('sha256', $publicKeyCredential->getResponse()->getClientDataJSON()->getRawData());
0 ignored issues
show
Unused Code introduced by
The assignment to $getClientDataJSONHash is dead and can be removed.
Loading history...
63
64
        /** @see 7.1.8 */
65
        $attestationObject = $publicKeyCredential->getResponse()->getAttestationObject();
0 ignored issues
show
Bug introduced by
The method getAttestationObject() does not exist on U2FAuthentication\Fido2\AuthenticatorResponse. It seems like you code against a sub-type of U2FAuthentication\Fido2\AuthenticatorResponse such as U2FAuthentication\Fido2\...atorAttestationResponse. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

65
        $attestationObject = $publicKeyCredential->getResponse()->/** @scrutinizer ignore-call */ getAttestationObject();
Loading history...
66
67
        /** @see 7.1.9 */
68
        $rpIdHash = hash('sha256', $rpId);
69
        if (hash_equals($rpIdHash, $attestationObject->getAuthData()->getRpIdHash())) {
70
            throw new \InvalidArgumentException('rpId hash mismatch.');
71
        }
72
73
        /** @see 7.1.10 */
74
        if (!$attestationObject->getAuthData()->isUserPresent()) {
75
            throw new \InvalidArgumentException('User was not present');
76
        }
77
78
        /** @see 7.1.11 */
79
        if ($publicKeyCredentialCreationOptions->getAuthenticatorSelection()->getUserVerification() === AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED && !$attestationObject->getAuthData()->isUserVerified()) {
80
            throw new \InvalidArgumentException('User authentication required.');
81
        }
82
83
        /** @see 7.1.12 */
84
        if ($publicKeyCredentialCreationOptions->getExtensions()->count() !== 0) {
85
            throw new \InvalidArgumentException('Extensions not supported.');
86
        }
87
88
        /** @see 7.1.13 */
89
        $fmt = $attestationObject->getAttStmt()->getFmt();
90
        if (!$this->attestationStatementSupportManager->has($fmt)) {
91
            throw new \InvalidArgumentException('Unsuppoorted attestation statement format.');
92
        }
93
94
        /** @see 7.1.14 */
95
        $attestationStatementSupport = $this->attestationStatementSupportManager->get($fmt);
96
        if (!$attestationStatementSupport->isValid($attestationObject->getAttStmt(), $attestationObject->getAuthData(), $C)) {
97
            throw new \InvalidArgumentException('Unvalid attestation statement.');
98
        }
99
100
        /** @see 7.1.15 */
101
        /** @see 7.1.16 */
102
        /** @see 7.1.17 */
103
        $credentialId = $attestationObject->getAuthData()->getAttestedCredentialData()->getCredentialId();
104
        if ($this->credentialIdRepository->hasCredentialId($credentialId)) {
105
            throw new \InvalidArgumentException('No credential ID.');
106
        }
107
108
        /** @see 7.1.18 */
109
        /** @see 7.1.19 */
110
    }
111
}
112