CertificateFaker::setSubject()   A
last analyzed

Complexity

Conditions 4
Paths 2

Size

Total Lines 30
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 14
nc 2
nop 9
dl 0
loc 30
ccs 17
cts 17
cp 1
crap 4
rs 9.7998
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Derafu: Biblioteca PHP (Núcleo).
7
 * Copyright (C) Derafu <https://www.derafu.org>
8
 *
9
 * Este programa es software libre: usted puede redistribuirlo y/o modificarlo
10
 * bajo los términos de la Licencia Pública General Affero de GNU publicada por
11
 * la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, o
12
 * (a su elección) cualquier versión posterior de la misma.
13
 *
14
 * Este programa se distribuye con la esperanza de que sea útil, pero SIN
15
 * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD
16
 * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la Licencia Pública
17
 * General Affero de GNU para obtener una información más detallada.
18
 *
19
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
20
 * junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace Derafu\Lib\Core\Package\Prime\Component\Certificate\Support;
26
27
use Derafu\Lib\Core\Package\Prime\Component\Certificate\Exception\CertificateException;
28
use OpenSSLAsymmetricKey;
29
30
/**
31
 * Clase que se encarga de generar certificados autofirmados y retornarlos como
32
 * un string de datos, un arreglo o una instancia de Certificate.
33
 */
34
class CertificateFaker
35
{
36
    /**
37
     * Datos del sujeto del certificado.
38
     *
39
     * @var array
40
     */
41
    private array $subject;
42
43
    /**
44
     * Datos del emisor del certificado.
45
     *
46
     * @var array
47
     */
48
    private array $issuer;
49
50
    /**
51
     * Validez del certificado en formato UNIX timestamp.
52
     *
53
     * @var array
54
     */
55
    private array $validity;
56
57
    /**
58
     * Contraseña para proteger la clave privada en el certificado.
59
     *
60
     * @var string
61
     */
62
    private string $password;
63
64
    /**
65
     * Constructor que asigna por defecto todos los valores por defecto.
66
     */
67 24
    public function __construct()
68
    {
69 24
        $this->setSubject();
70 24
        $this->setIssuer();
71 24
        $this->setValidity();
72 24
        $this->setPassword();
73
    }
74
75
    /**
76
     * Configura los datos del sujeto del certificado.
77
     *
78
     * @param string $C País del sujeto.
79
     * @param string $ST Estado o provincia del sujeto.
80
     * @param string $L Localidad del sujeto.
81
     * @param string $O Organización del sujeto.
82
     * @param string $OU Unidad organizativa del sujeto.
83
     * @param string $CN Nombre común del sujeto.
84
     * @param string $emailAddress Correo electrónico del sujeto.
85
     * @param string $serialNumber Número de serie del sujeto.
86
     * @param string $title Título del sujeto.
87
     * @return static
88
     */
89 24
    public function setSubject(
90
        string $C = 'CL',
91
        string $ST = 'Colchagua',
92
        string $L = 'Santa Cruz',
93
        string $O = 'Organización Intergaláctica de Robots',
94
        string $OU = 'Tecnología',
95
        string $CN = 'Daniel',
96
        string $emailAddress = '[email protected]',
97
        string $serialNumber = '11222333-9',
98
        string $title = 'Bot',
99
    ): static {
100 24
        if (empty($CN) || empty($emailAddress) || empty($serialNumber)) {
101 2
            throw new CertificateException(
102 2
                'El CN, emailAddress y serialNumber son obligatorios.'
103 2
            );
104
        }
105
106 24
        $this->subject = [
107 24
            'C' => $C,
108 24
            'ST' => $ST,
109 24
            'L' => $L,
110 24
            'O' => $O,
111 24
            'OU' => $OU,
112 24
            'CN' => $CN,
113 24
            'emailAddress' => $emailAddress,
114 24
            'serialNumber' => strtoupper($serialNumber),
115 24
            'title' => $title,
116 24
        ];
117
118 24
        return $this;
119
    }
120
121
    /**
122
     * Configura los datos del emisor del certificado.
123
     *
124
     * @param string $C País del emisor.
125
     * @param string $ST Estado o provincia del emisor.
126
     * @param string $L Localidad del emisor.
127
     * @param string $O Organización del emisor.
128
     * @param string $OU Unidad organizativa del emisor.
129
     * @param string $CN Nombre común del emisor.
130
     * @param string $emailAddress Correo electrónico del emisor.
131
     * @param string $serialNumber Número de serie del emisor.
132
     * @return static
133
     */
134 24
    public function setIssuer(
135
        string $C = 'CL',
136
        string $ST = 'Colchagua',
137
        string $L = 'Santa Cruz',
138
        string $O = 'Derafu',
139
        string $OU = 'Tecnología',
140
        string $CN = 'Derafu Autoridad Certificadora de Pruebas',
141
        string $emailAddress = '[email protected]',
142
        string $serialNumber = '76192083-9',
143
    ): static {
144 24
        $this->issuer = [
145 24
            'C' => $C,
146 24
            'ST' => $ST,
147 24
            'L' => $L,
148 24
            'O' => $O,
149 24
            'OU' => $OU,
150 24
            'CN' => $CN,
151 24
            'emailAddress' => $emailAddress,
152 24
            'serialNumber' => strtoupper($serialNumber),
153 24
        ];
154
155 24
        return $this;
156
    }
157
158
    /**
159
     * Configura la validez del certificado.
160
     *
161
     * @param int $days Días que el certificado será válido desde la
162
     * fecha actual. Si no se proporciona, tendrá validez de 365 días.
163
     * @return static
164
     */
165 24
    public function setValidity(int $days = 365): static
166
    {
167 24
        $this->validity = [
168 24
            'days' => $days,
169 24
        ];
170
171 24
        return $this;
172
    }
173
174
    /**
175
     * Configura la contraseña para proteger la clave privada.
176
     *
177
     * @param string $password Contraseña para proteger la clave privada.
178
     * @return void
179
     */
180 24
    public function setPassword(string $password = 'i_love_derafu')
181
    {
182 24
        $this->password = $password;
183
    }
184
185
    /**
186
     * Genera un certificado digital en formato PKCS#12 y lo devuelve como un
187
     * string.
188
     *
189
     * @return string Certificado digital en formato PKCS#12.
190
     */
191 22
    private function toString(): string
192
    {
193
        // Días de validez del certificado (emisor y sujeto).
194 22
        $days = $this->validity['days'];
195
196
        // Crear clave privada y CSR para el emisor.
197 22
        $issuerPrivateKey = openssl_pkey_new();
198 22
        if (!$issuerPrivateKey instanceof OpenSSLAsymmetricKey) {
199
            throw new CertificateException(
200
                'No fue posible generar la llave privada del emisor del certificado.'
201
            );
202
        }
203 22
        $issuerCsr = openssl_csr_new($this->issuer, $issuerPrivateKey);
204
205
        // Crear certificado autofirmado para el emisor (CA).
206 22
        $issuerCert = openssl_csr_sign(
207 22
            $issuerCsr,         // CSR del emisor.
208 22
            null,               // Certificado emisor (null indica que es autofirmado).
209 22
            $issuerPrivateKey,  // Clave privada del emisor.
210 22
            $days,              // Número de días de validez (misma sujeto).
211 22
            [],                 // Opciones adicionales.
212 22
            666                 // Número de serie del certificado.
213 22
        );
214
215
        // Validar que se haya podido crear el certificado del emisor (CA).
216 22
        if ($issuerCert === false) {
217
            throw new CertificateException(
218
                'No fue posible generar el certificado del emisor (CA).'
219
            );
220
        }
221
222
        // Crear clave privada y CSR para el sujeto.
223 22
        $subjectPrivateKey = openssl_pkey_new();
224 22
        if (!$subjectPrivateKey instanceof OpenSSLAsymmetricKey) {
225
            throw new CertificateException(
226
                'No fue posible generar la llave privada del certificado.'
227
            );
228
        }
229 22
        $subjectCsr = openssl_csr_new($this->subject, $subjectPrivateKey);
230
231
        // Usar el certificado del emisor para firmar el CSR del sujeto.
232 22
        $subjectCert = openssl_csr_sign(
233 22
            $subjectCsr,        // La solicitud de firma del certificado (CSR).
234 22
            $issuerCert,        // Certificado emisor.
235 22
            $issuerPrivateKey,  // Clave privada del emisor.
236 22
            $days,              // Número de días de validez.
237 22
            [],                 // Opciones adicionales.
238 22
            69                  // Número de serie del certificado.
239 22
        );
240
241
        // Validar que se haya podido crear el certificado del usuario.
242 22
        if ($subjectCert === false) {
243
            throw new CertificateException(
244
                'No fue posible generar el certificado del usuario.'
245
            );
246
        }
247
248
        // Exportar el certificado final en formato PKCS#12.
249 22
        openssl_pkcs12_export(
250 22
            $subjectCert,
251 22
            $data,
252 22
            $subjectPrivateKey,
253 22
            $this->password
254 22
        );
255
256
        // Entregar los datos del certificado digital.
257 22
        return $data;
258
    }
259
260
    /**
261
     * Genera un certificado digital en formato PKCS#12 y lo devuelve como un
262
     * arreglo.
263
     *
264
     * @return array Certificado digital en formato PKCS#12.
265
     */
266 22
    public function toArray(): array
267
    {
268 22
        $data = $this->toString();
269 22
        $array = [];
270 22
        openssl_pkcs12_read($data, $array, $this->password);
271
272 22
        return $array;
273
    }
274
}
275