CertificationRequestInfo   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 203
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 12
dl 0
loc 203
ccs 61
cts 61
cp 1
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A fromASN1() 0 20 3
A version() 0 4 1
A withSubject() 0 6 1
A subject() 0 4 1
A subjectPKInfo() 0 4 1
A hasAttributes() 0 4 1
A attributes() 0 7 2
A withAttributes() 0 6 1
A withExtensionRequest() 0 11 2
A toASN1() 0 10 2
A sign() 0 8 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace X509\CertificationRequest;
6
7
use ASN1\Element;
8
use ASN1\Type\Constructed\Sequence;
9
use ASN1\Type\Primitive\Integer;
10
use ASN1\Type\Tagged\ImplicitlyTaggedType;
11
use Sop\CryptoBridge\Crypto;
12
use Sop\CryptoTypes\AlgorithmIdentifier\Feature\SignatureAlgorithmIdentifier;
13
use Sop\CryptoTypes\Asymmetric\PrivateKeyInfo;
14
use Sop\CryptoTypes\Asymmetric\PublicKeyInfo;
15
use X501\ASN1\Attribute;
16
use X501\ASN1\Name;
17
use X509\Certificate\Extensions;
18
use X509\CertificationRequest\Attribute\ExtensionRequestValue;
19
20
/**
21
 * Implements <i>CertificationRequestInfo</i> ASN.1 type.
22
 *
23
 * @link https://tools.ietf.org/html/rfc2986#section-4
24
 */
25
class CertificationRequestInfo
26
{
27
    const VERSION_1 = 0;
28
    
29
    /**
30
     * Version.
31
     *
32
     * @var int
33
     */
34
    protected $_version;
35
    
36
    /**
37
     * Subject.
38
     *
39
     * @var Name $_subject
40
     */
41
    protected $_subject;
42
    
43
    /**
44
     * Public key info.
45
     *
46
     * @var PublicKeyInfo $_subjectPKInfo
47
     */
48
    protected $_subjectPKInfo;
49
    
50
    /**
51
     * Attributes.
52
     *
53
     * @var Attributes|null $_attributes
54
     */
55
    protected $_attributes;
56
    
57
    /**
58
     * Constructor.
59
     *
60
     * @param Name $subject Subject
61
     * @param PublicKeyInfo $pkinfo Public key info
62
     */
63 10
    public function __construct(Name $subject, PublicKeyInfo $pkinfo)
64
    {
65 10
        $this->_version = self::VERSION_1;
66 10
        $this->_subject = $subject;
67 10
        $this->_subjectPKInfo = $pkinfo;
68 10
    }
69
    
70
    /**
71
     * Initialize from ASN.1.
72
     *
73
     * @param Sequence $seq
74
     * @throws \UnexpectedValueException
75
     * @return self
76
     */
77 6
    public static function fromASN1(Sequence $seq): self
78
    {
79 6
        $version = $seq->at(0)
80 6
            ->asInteger()
81 6
            ->intNumber();
82 6
        if ($version != self::VERSION_1) {
83 1
            throw new \UnexpectedValueException(
84 1
                "Version $version not supported.");
85
        }
86 5
        $subject = Name::fromASN1($seq->at(1)->asSequence());
87 5
        $pkinfo = PublicKeyInfo::fromASN1($seq->at(2)->asSequence());
88 5
        $obj = new self($subject, $pkinfo);
89 5
        if ($seq->hasTagged(0)) {
90 2
            $obj->_attributes = Attributes::fromASN1(
91 2
                $seq->getTagged(0)
92 2
                    ->asImplicit(Element::TYPE_SET)
93 2
                    ->asSet());
94
        }
95 5
        return $obj;
96
    }
97
    
98
    /**
99
     * Get version.
100
     *
101
     * @return int
102
     */
103 2
    public function version(): int
104
    {
105 2
        return $this->_version;
106
    }
107
    
108
    /**
109
     * Get self with subject.
110
     *
111
     * @param Name $subject
112
     * @return self
113
     */
114 1
    public function withSubject(Name $subject): self
115
    {
116 1
        $obj = clone $this;
117 1
        $obj->_subject = $subject;
118 1
        return $obj;
119
    }
120
    
121
    /**
122
     * Get subject.
123
     *
124
     * @return Name
125
     */
126 4
    public function subject(): Name
127
    {
128 4
        return $this->_subject;
129
    }
130
    
131
    /**
132
     * Get subject public key info.
133
     *
134
     * @return PublicKeyInfo
135
     */
136 4
    public function subjectPKInfo(): PublicKeyInfo
137
    {
138 4
        return $this->_subjectPKInfo;
139
    }
140
    
141
    /**
142
     * Whether certification request info has attributes.
143
     *
144
     * @return bool
145
     */
146 6
    public function hasAttributes(): bool
147
    {
148 6
        return isset($this->_attributes);
149
    }
150
    
151
    /**
152
     * Get attributes.
153
     *
154
     * @throws \LogicException
155
     * @return Attributes
156
     */
157 6
    public function attributes(): Attributes
158
    {
159 6
        if (!$this->hasAttributes()) {
160 1
            throw new \LogicException("No attributes.");
161
        }
162 5
        return $this->_attributes;
163
    }
164
    
165
    /**
166
     * Get instance of self with attributes.
167
     *
168
     * @param Attributes $attribs
169
     */
170 1
    public function withAttributes(Attributes $attribs): self
171
    {
172 1
        $obj = clone $this;
173 1
        $obj->_attributes = $attribs;
174 1
        return $obj;
175
    }
176
    
177
    /**
178
     * Get self with extension request attribute.
179
     *
180
     * @param Extensions $extensions Extensions to request
181
     * @return self
182
     */
183 3
    public function withExtensionRequest(Extensions $extensions): self
184
    {
185 3
        $obj = clone $this;
186 3
        if (!isset($obj->_attributes)) {
187 2
            $obj->_attributes = new Attributes();
188
        }
189 3
        $obj->_attributes = $obj->_attributes->withUnique(
190 3
            Attribute::fromAttributeValues(
191 3
                new ExtensionRequestValue($extensions)));
192 3
        return $obj;
193
    }
194
    
195
    /**
196
     * Generate ASN.1 structure.
197
     *
198
     * @return Sequence
199
     */
200 9
    public function toASN1(): Sequence
201
    {
202 9
        $elements = array(new Integer($this->_version),
203 9
            $this->_subject->toASN1(), $this->_subjectPKInfo->toASN1());
204 9
        if (isset($this->_attributes)) {
205 3
            $elements[] = new ImplicitlyTaggedType(0,
206 3
                $this->_attributes->toASN1());
207
        }
208 9
        return new Sequence(...$elements);
209
    }
210
    
211
    /**
212
     * Create signed CertificationRequest.
213
     *
214
     * @param SignatureAlgorithmIdentifier $algo Algorithm used for signing
215
     * @param PrivateKeyInfo $privkey_info Private key used for signing
216
     * @param Crypto|null $crypto Crypto engine, use default if not set
217
     * @return CertificationRequest
218
     */
219 2
    public function sign(SignatureAlgorithmIdentifier $algo,
220
        PrivateKeyInfo $privkey_info, Crypto $crypto = null): CertificationRequest
221
    {
222 2
        $crypto = $crypto ?: Crypto::getDefault();
223 2
        $data = $this->toASN1()->toDER();
224 2
        $signature = $crypto->sign($data, $privkey_info, $algo);
225 2
        return new CertificationRequest($this, $algo, $signature);
226
    }
227
}
228