GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

ACValidator   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 24
eloc 65
dl 0
loc 183
ccs 70
cts 70
cp 1
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A _validateHolder() 0 16 3
A _validateTime() 0 9 3
A __construct() 0 6 1
A _validateTargeting() 0 12 4
A _validateIssuerProfile() 0 10 5
A _hasMatchingTarget() 0 8 3
A validate() 0 8 1
A _verifyIssuer() 0 20 4
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\X509\AttributeCertificate\Validation;
6
7
use Sop\CryptoBridge\Crypto;
8
use Sop\X509\AttributeCertificate\AttributeCertificate;
9
use Sop\X509\AttributeCertificate\Validation\Exception\ACValidationException;
10
use Sop\X509\Certificate\Certificate;
11
use Sop\X509\Certificate\Extension\Extension;
12
use Sop\X509\Certificate\Extension\Target\Targets;
13
use Sop\X509\Certificate\Extension\TargetInformationExtension;
14
use Sop\X509\CertificationPath\Exception\PathValidationException;
15
use Sop\X509\CertificationPath\PathValidation\PathValidationConfig;
16
17
/**
18
 * Implements attribute certificate validation conforming to RFC 5755.
19
 *
20
 * @see https://tools.ietf.org/html/rfc5755#section-5
21
 */
22
class ACValidator
23
{
24
    /**
25
     * Attribute certificate.
26
     *
27
     * @var AttributeCertificate
28
     */
29
    protected $_ac;
30
31
    /**
32
     * Validation configuration.
33
     *
34
     * @var ACValidationConfig
35
     */
36
    protected $_config;
37
38
    /**
39
     * Crypto engine.
40
     *
41
     * @var Crypto
42
     */
43
    protected $_crypto;
44
45
    /**
46
     * Constructor.
47
     *
48
     * @param AttributeCertificate $ac     Attribute certificate to validate
49
     * @param ACValidationConfig   $config Validation configuration
50
     * @param null|Crypto          $crypto Crypto engine, use default if not set
51
     */
52 12
    public function __construct(AttributeCertificate $ac,
53
        ACValidationConfig $config, ?Crypto $crypto = null)
54
    {
55 12
        $this->_ac = $ac;
56 12
        $this->_config = $config;
57 12
        $this->_crypto = $crypto ?? Crypto::getDefault();
58 12
    }
59
60
    /**
61
     * Validate attribute certificate.
62
     *
63
     * @throws ACValidationException If validation fails
64
     *
65
     * @return AttributeCertificate Validated AC
66
     */
67 12
    public function validate(): AttributeCertificate
68
    {
69 12
        $this->_validateHolder();
70 10
        $issuer = $this->_verifyIssuer();
71 7
        $this->_validateIssuerProfile($issuer);
72 5
        $this->_validateTime();
73 3
        $this->_validateTargeting();
74 2
        return $this->_ac;
75
    }
76
77
    /**
78
     * Validate AC holder's certification.
79
     *
80
     * @throws ACValidationException
81
     *
82
     * @return Certificate Certificate of the AC's holder
83
     */
84 12
    private function _validateHolder(): Certificate
85
    {
86 12
        $path = $this->_config->holderPath();
87 12
        $config = PathValidationConfig::defaultConfig()
88 12
            ->withMaxLength(count($path))
89 12
            ->withDateTime($this->_config->evaluationTime());
90
        try {
91 12
            $holder = $path->validate($config, $this->_crypto)->certificate();
92 1
        } catch (PathValidationException $e) {
93 1
            throw new ACValidationException(
94 1
                "Failed to validate holder PKC's certification path.", 0, $e);
95
        }
96 11
        if (!$this->_ac->isHeldBy($holder)) {
97 1
            throw new ACValidationException("Name mismatch of AC's holder PKC.");
98
        }
99 10
        return $holder;
100
    }
101
102
    /**
103
     * Verify AC's signature and issuer's certification.
104
     *
105
     * @throws ACValidationException
106
     *
107
     * @return Certificate Certificate of the AC's issuer
108
     */
109 10
    private function _verifyIssuer(): Certificate
110
    {
111 10
        $path = $this->_config->issuerPath();
112 10
        $config = PathValidationConfig::defaultConfig()
113 10
            ->withMaxLength(count($path))
114 10
            ->withDateTime($this->_config->evaluationTime());
115
        try {
116 10
            $issuer = $path->validate($config, $this->_crypto)->certificate();
117 1
        } catch (PathValidationException $e) {
118 1
            throw new ACValidationException(
119 1
                "Failed to validate issuer PKC's certification path.", 0, $e);
120
        }
121 9
        if (!$this->_ac->isIssuedBy($issuer)) {
122 1
            throw new ACValidationException("Name mismatch of AC's issuer PKC.");
123
        }
124 8
        $pubkey_info = $issuer->tbsCertificate()->subjectPublicKeyInfo();
125 8
        if (!$this->_ac->verify($pubkey_info, $this->_crypto)) {
126 1
            throw new ACValidationException('Failed to verify signature.');
127
        }
128 7
        return $issuer;
129
    }
130
131
    /**
132
     * Validate AC issuer's profile.
133
     *
134
     * @see https://tools.ietf.org/html/rfc5755#section-4.5
135
     *
136
     * @param Certificate $cert
137
     *
138
     * @throws ACValidationException
139
     */
140 7
    private function _validateIssuerProfile(Certificate $cert): void
141
    {
142 7
        $exts = $cert->tbsCertificate()->extensions();
143 7
        if ($exts->hasKeyUsage() && !$exts->keyUsage()->isDigitalSignature()) {
144 1
            throw new ACValidationException(
145
                "Issuer PKC's Key Usage extension doesn't permit" .
146 1
                     ' verification of digital signatures.');
147
        }
148 6
        if ($exts->hasBasicConstraints() && $exts->basicConstraints()->isCA()) {
149 1
            throw new ACValidationException('Issuer PKC must not be a CA.');
150
        }
151 5
    }
152
153
    /**
154
     * Validate AC's validity period.
155
     *
156
     * @throws ACValidationException
157
     */
158 5
    private function _validateTime(): void
159
    {
160 5
        $t = $this->_config->evaluationTime();
161 5
        $validity = $this->_ac->acinfo()->validityPeriod();
162 5
        if ($validity->notBeforeTime()->diff($t)->invert) {
163 1
            throw new ACValidationException('Validity period has not started.');
164
        }
165 4
        if ($t->diff($validity->notAfterTime())->invert) {
166 1
            throw new ACValidationException('Attribute certificate has expired.');
167
        }
168 3
    }
169
170
    /**
171
     * Validate AC's target information.
172
     *
173
     * @throws ACValidationException
174
     */
175 3
    private function _validateTargeting(): void
176
    {
177 3
        $exts = $this->_ac->acinfo()->extensions();
178
        // if target information extension is not present
179 3
        if (!$exts->has(Extension::OID_TARGET_INFORMATION)) {
180 1
            return;
181
        }
182 2
        $ext = $exts->get(Extension::OID_TARGET_INFORMATION);
183 2
        if ($ext instanceof TargetInformationExtension &&
184 2
            !$this->_hasMatchingTarget($ext->targets())) {
185 1
            throw new ACValidationException(
186 1
                "Attribute certificate doesn't have a matching target.");
187
        }
188 1
    }
189
190
    /**
191
     * Check whether validation configuration has matching targets.
192
     *
193
     * @param Targets $targets Set of eligible targets
194
     *
195
     * @return bool
196
     */
197 2
    private function _hasMatchingTarget(Targets $targets): bool
198
    {
199 2
        foreach ($this->_config->targets() as $target) {
200 2
            if ($targets->hasTarget($target)) {
201 2
                return true;
202
            }
203
        }
204 1
        return false;
205
    }
206
}
207