CertificationPath::endEntityCertificate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
nc 2
cc 2
nop 0
crap 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace X509\CertificationPath;
6
7
use Sop\CryptoBridge\Crypto;
8
use X509\Certificate\Certificate;
9
use X509\Certificate\CertificateBundle;
10
use X509\Certificate\CertificateChain;
11
use X509\CertificationPath\PathBuilding\CertificationPathBuilder;
12
use X509\CertificationPath\PathValidation\PathValidationConfig;
13
use X509\CertificationPath\PathValidation\PathValidator;
14
15
/**
16
 * Implements certification path structure.
17
 *
18
 * Certification path is a list of certificates from the trust anchor to
19
 * the end entity certificate, possibly spanning over multiple intermediate
20
 * certificates.
21
 *
22
 * @link https://tools.ietf.org/html/rfc5280#section-3.2
23
 */
24
class CertificationPath implements \Countable, \IteratorAggregate
25
{
26
    /**
27
     * Certification path.
28
     *
29
     * @var Certificate[] $_certificates
30
     */
31
    protected $_certificates;
32
    
33
    /**
34
     * Constructor.
35
     *
36
     * @param Certificate ...$certificates Certificates from the trust anchor
37
     *        to the target end-entity certificate
38
     */
39 38
    public function __construct(Certificate ...$certificates)
40
    {
41 38
        $this->_certificates = $certificates;
42 38
    }
43
    
44
    /**
45
     * Initialize from a certificate chain.
46
     *
47
     * @param CertificateChain $chain
48
     * @return self
49
     */
50 2
    public static function fromCertificateChain(CertificateChain $chain): self
51
    {
52 2
        return new self(...array_reverse($chain->certificates(), false));
53
    }
54
    
55
    /**
56
     * Build certification path to given target.
57
     *
58
     * @param Certificate $target Target end-entity certificate
59
     * @param CertificateBundle $trust_anchors List of trust anchors
60
     * @param CertificateBundle|null $intermediate Optional intermediate
61
     *        certificates
62
     * @return self
63
     */
64 2
    public static function toTarget(Certificate $target,
65
        CertificateBundle $trust_anchors, CertificateBundle $intermediate = null): self
66
    {
67 2
        $builder = new CertificationPathBuilder($trust_anchors);
68 2
        return $builder->shortestPathToTarget($target, $intermediate);
69
    }
70
    
71
    /**
72
     * Build certification path from given trust anchor to target certificate,
73
     * using intermediate certificates from given bundle.
74
     *
75
     * @param Certificate $trust_anchor Trust anchor certificate
76
     * @param Certificate $target Target end-entity certificate
77
     * @param CertificateBundle|null $intermediate Optional intermediate
78
     *        certificates
79
     * @return self
80
     */
81 2
    public static function fromTrustAnchorToTarget(Certificate $trust_anchor,
82
        Certificate $target, CertificateBundle $intermediate = null): self
83
    {
84 2
        return self::toTarget($target, new CertificateBundle($trust_anchor),
85 2
            $intermediate);
86
    }
87
    
88
    /**
89
     * Get certificates.
90
     *
91
     * @return Certificate[]
92
     */
93 5
    public function certificates(): array
94
    {
95 5
        return $this->_certificates;
96
    }
97
    
98
    /**
99
     * Get the trust anchor certificate from the path.
100
     *
101
     * @throws \LogicException If path is empty
102
     * @return Certificate
103
     */
104 2
    public function trustAnchorCertificate(): Certificate
105
    {
106 2
        if (!count($this->_certificates)) {
107 1
            throw new \LogicException("No certificates.");
108
        }
109 1
        return $this->_certificates[0];
110
    }
111
    
112
    /**
113
     * Get the end-entity certificate from the path.
114
     *
115
     * @throws \LogicException If path is empty
116
     * @return Certificate
117
     */
118 2
    public function endEntityCertificate(): Certificate
119
    {
120 2
        if (!count($this->_certificates)) {
121 1
            throw new \LogicException("No certificates.");
122
        }
123 1
        return $this->_certificates[count($this->_certificates) - 1];
124
    }
125
    
126
    /**
127
     * Get certification path as a certificate chain.
128
     *
129
     * @return CertificateChain
130
     */
131 1
    public function certificateChain(): CertificateChain
132
    {
133 1
        return new CertificateChain(
134 1
            ...array_reverse($this->_certificates, false));
135
    }
136
    
137
    /**
138
     * Check whether certification path starts with one ore more given
139
     * certificates in parameter order.
140
     *
141
     * @param Certificate ...$certs Certificates
142
     * @return true
143
     */
144 5
    public function startsWith(Certificate ...$certs): bool
145
    {
146 5
        $n = count($certs);
147 5
        if ($n > count($this->_certificates)) {
148 1
            return false;
149
        }
150 4
        for ($i = 0; $i < $n; ++$i) {
151 4
            if (!$certs[$i]->equals($this->_certificates[$i])) {
152 1
                return false;
153
            }
154
        }
155 3
        return true;
156
    }
157
    
158
    /**
159
     * Validate certification path.
160
     *
161
     * @param PathValidationConfig $config
162
     * @param Crypto|null $crypto Crypto engine, use default if not set
163
     * @throws Exception\PathValidationException
164
     * @return PathValidation\PathValidationResult
165
     */
166 43
    public function validate(PathValidationConfig $config, Crypto $crypto = null): PathValidation\PathValidationResult
167
    {
168 43
        $crypto = $crypto ?: Crypto::getDefault();
169 43
        $validator = new PathValidator($crypto, $config, ...$this->_certificates);
170 43
        return $validator->validate();
171
    }
172
    
173
    /**
174
     *
175
     * @see \Countable::count()
176
     * @return int
177
     */
178 18
    public function count(): int
179
    {
180 18
        return count($this->_certificates);
181
    }
182
    
183
    /**
184
     * Get iterator for certificates.
185
     *
186
     * @see \IteratorAggregate::getIterator()
187
     * @return \ArrayIterator
188
     */
189 1
    public function getIterator(): \ArrayIterator
190
    {
191 1
        return new \ArrayIterator($this->_certificates);
192
    }
193
}
194