Passed
Push — master ( e584ed...a08a48 )
by Esteban De La Fuente
05:48
created

CertificateFaker::setIssuer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 8
dl 0
loc 22
ccs 12
cts 12
cp 1
crap 1
rs 9.9332

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
 * LibreDTE: Biblioteca PHP (Núcleo).
7
 * Copyright (C) LibreDTE <https://www.libredte.cl>
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
20
 * GNU junto a este programa.
21
 *
22
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
23
 */
24
25
namespace libredte\lib\Core\Signature;
26
27
/**
28
 * Clase que se encarga de generar certificados autofirmados y retornarlos como
29
 * un string de datos, un arreglo o una instancia de Certificate.
30
 */
31
class CertificateFaker
32
{
33
    /**
34
     * Datos del sujeto del certificado.
35
     *
36
     * @var array
37
     */
38
    private array $subject;
39
40
    /**
41
     * Datos del emisor del certificado.
42
     *
43
     * @var array
44
     */
45
    private array $issuer;
46
47
    /**
48
     * Validez del certificado en formato UNIX timestamp.
49
     *
50
     * @var array
51
     */
52
    private array $validity;
53
54
    /**
55
     * Contraseña para proteger la clave privada en el certificado.
56
     *
57
     * @var string
58
     */
59
    private string $password;
60
61
    /**
62
     * Constructor de la clase.
63
     *
64
     * Establece valores por defecto para el sujeto, emisor, validez y
65
     * contraseña.
66
     */
67 58
    public function __construct()
68
    {
69 58
        $this->setSubject();
70 58
        $this->setIssuer();
71 58
        $this->setValidity();
72 58
        $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 self
88
     */
89 58
    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
    ): self {
100 58
        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 58
        $this->subject = [
107 58
            'C' => $C,
108 58
            'ST' => $ST,
109 58
            'L' => $L,
110 58
            'O' => $O,
111 58
            'OU' => $OU,
112 58
            'CN' => $CN,
113 58
            'emailAddress' => $emailAddress,
114 58
            'serialNumber' => strtoupper($serialNumber),
115 58
            'title' => $title,
116 58
        ];
117
118 58
        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 self
133
     */
134 58
    public function setIssuer(
135
        string $C = 'CL',
136
        string $ST = 'Colchagua',
137
        string $L = 'Santa Cruz',
138
        string $O = 'LibreDTE',
139
        string $OU = 'Facturación Electrónica',
140
        string $CN = 'LibreDTE Autoridad Certificadora de Pruebas',
141
        string $emailAddress = '[email protected]',
142
        string $serialNumber = '76192083-9',
143
    ): self {
144 58
        $this->issuer = [
145 58
            'C' => $C,
146 58
            'ST' => $ST,
147 58
            'L' => $L,
148 58
            'O' => $O,
149 58
            'OU' => $OU,
150 58
            'CN' => $CN,
151 58
            'emailAddress' => $emailAddress,
152 58
            'serialNumber' => strtoupper($serialNumber),
153 58
        ];
154
155 58
        return $this;
156
    }
157
158
    /**
159
     * Configura la validez del certificado.
160
     *
161
     * @param string|null $validTo Fecha de validez hasta, en formato 'Y-m-d'.
162
     * Si no se proporciona, se establece un año a partir de la fecha actual.
163
     * @return self
164
     */
165 58
    public function setValidity(string $validTo = null): self
166
    {
167 58
        $validFrom = (int) date('U');
168
169 58
        if ($validTo === null) {
170 58
            $validTo = date('Y-m-d', strtotime('+1 year', $validFrom));
171
        }
172 58
        $validTo = strtotime($validTo);
173
174 58
        $days = (int) (($validTo - $validFrom) / (60 * 60 * 24));
175
176 58
        $this->validity = [
177 58
            'from' => $validFrom,
178 58
            'to' => $validTo,
179 58
            'days' => $days,
180 58
        ];
181
182 58
        return $this;
183
    }
184
185
    /**
186
     * Configura la contraseña para proteger la clave privada.
187
     *
188
     * @param string $password Contraseña para proteger la clave privada.
189
     * @return void
190
     */
191 58
    public function setPassword(string $password = 'i_love_libredte')
192
    {
193 58
        $this->password = $password;
194
    }
195
196
    /**
197
     * Obtiene la contraseña configurada.
198
     *
199
     * @return string Contraseña configurada.
200
     */
201 2
    public function getPassword(): string
202
    {
203 2
        return $this->password;
204
    }
205
206
    /**
207
     * Genera un certificado digital en formato PKCS#12 y lo devuelve como un
208
     * string.
209
     *
210
     * @return string Certificado digital en formato PKCS#12.
211
     */
212 56
    public function createAsString(): string
213
    {
214
        // Días de validez del certificado (emisor y sujeto).
215 56
        $days = $this->validity['days'];
216
217
        // Crear clave privada y CSR para el emisor.
218 56
        $issuerPrivateKey = openssl_pkey_new();
219 56
        if (!$issuerPrivateKey) {
220
            throw new CertificateException(
221
                'No fue posible generar la llave privada del emisor del certificado.'
222
            );
223
        }
224 56
        $issuerCsr = openssl_csr_new($this->issuer, $issuerPrivateKey);
0 ignored issues
show
Bug introduced by
It seems like $issuerPrivateKey can also be of type resource; however, parameter $private_key of openssl_csr_new() does only seem to accept OpenSSLAsymmetricKey, maybe add an additional type check? ( Ignorable by Annotation )

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

224
        $issuerCsr = openssl_csr_new($this->issuer, /** @scrutinizer ignore-type */ $issuerPrivateKey);
Loading history...
225
226
        // Crear certificado autofirmado para el emisor.
227 56
        $issuerCert = openssl_csr_sign(
228 56
            $issuerCsr,         // CSR del emisor.
229 56
            null,               // Certificado emisor (null indica que es autofirmado).
230 56
            $issuerPrivateKey,  // Clave privada del emisor.
231 56
            $days,              // Número de días de validez (misma sujeto).
232 56
            [],                 // Opciones adicionales.
233 56
            666                 // Número de serie del certificado.
234 56
        );
235
236
        // Crear clave privada y CSR para el sujeto.
237 56
        $subjectPrivateKey = openssl_pkey_new();
238 56
        if (!$subjectPrivateKey) {
239
            throw new CertificateException(
240
                'No fue posible generar la llave privada del certificado.'
241
            );
242
        }
243 56
        $subjectCsr = openssl_csr_new($this->subject, $subjectPrivateKey);
244
245
        // Usar el certificado del emisor para firmar el CSR del sujeto.
246 56
        $subjectCert = openssl_csr_sign(
247 56
            $subjectCsr,        // La solicitud de firma del certificado (CSR).
248 56
            $issuerCert,        // Certificado emisor.
249 56
            $issuerPrivateKey,  // Clave privada del emisor.
250 56
            $days,              // Número de días de validez.
251 56
            [],                 // Opciones adicionales.
252 56
            69                  // Número de serie del certificado.
253 56
        );
254
255
        // Exportar el certificado final en formato PKCS#12.
256 56
        openssl_pkcs12_export(
257 56
            $subjectCert,
258 56
            $data,
259 56
            $subjectPrivateKey,
260 56
            $this->password
261 56
        );
262
263
        // Entregar los datos del certificado digital.
264 56
        return $data;
265
    }
266
267
    /**
268
     * Genera un certificado digital en formato PKCS#12 y lo devuelve como un
269
     * arreglo.
270
     *
271
     * @return array Certificado digital en formato PKCS#12.
272
     */
273 54
    public function createAsArray(): array
274
    {
275 54
        $data = $this->createAsString();
276 54
        $array = [];
277 54
        openssl_pkcs12_read($data, $array, $this->password);
278
279 54
        return $array;
280
    }
281
282
    /**
283
     * Genera un certificado digital y lo devuelve como una instancia de
284
     * Certificate.
285
     *
286
     * @return Certificate Instancia de Certificate.
287
     */
288 51
    public function create(): Certificate
289
    {
290 51
        $array = $this->createAsArray();
291
292 51
        return CertificateLoader::createFromArray($array);
293
    }
294
}
295