@@ -38,27 +38,36 @@ class Certificado
38
38
/**
39
39
* Certificado constructor.
40
40
*
41
- * @param string $filename
41
+ * @param string $filename Allows filename or certificate contents (PEM or DER)
42
42
* @param OpenSSL $openSSL
43
- * @throws \UnexpectedValueException when the file does not exists or is not readable
44
- * @throws \UnexpectedValueException when cannot read the certificate file or is empty
45
- * @throws \RuntimeException when cannot parse the certificate file or is empty
43
+ * @throws \UnexpectedValueException when the certificate does not exists or is not readable
44
+ * @throws \UnexpectedValueException when cannot read the certificate or is empty
45
+ * @throws \RuntimeException when cannot parse the certificate or is empty
46
46
* @throws \RuntimeException when cannot get serialNumberHex or serialNumber from certificate
47
47
*/
48
48
public function __construct (string $ filename , OpenSSL $ openSSL = null )
49
49
{
50
- $ this ->assertFileExists ($ filename );
51
- $ contents = strval (file_get_contents ($ filename ));
50
+ $ this ->setOpenSSL ($ openSSL ?: new OpenSSL ());
51
+ $ contents = $ this ->extractPemCertificate ($ filename );
52
+ // using $filename as PEM content did not retrieve any result, so, use it as path
52
53
if ('' === $ contents ) {
53
- throw new \UnexpectedValueException ("File $ filename is empty " );
54
+ $ sourceName = 'file ' . $ filename ;
55
+ $ this ->assertFileExists ($ filename );
56
+ $ contents = file_get_contents ($ filename ) ?: '' ;
57
+ if ('' === $ contents ) {
58
+ throw new \UnexpectedValueException ("File $ filename is empty " );
59
+ }
60
+ // this will take PEM contents or perform a PHP conversion from DER to PEM
61
+ $ contents = $ this ->obtainPemCertificate ($ contents );
62
+ } else {
63
+ $ filename = '' ;
64
+ $ sourceName = '(contents) ' ;
54
65
}
55
- $ this ->setOpenSSL ($ openSSL ?: new OpenSSL ());
56
- $ contents = $ this ->obtainPemCertificate ($ contents );
57
66
58
67
// get the certificate data
59
68
$ data = openssl_x509_parse ($ contents , true );
60
69
if (! is_array ($ data )) {
61
- throw new \RuntimeException ("Cannot parse the certificate file $ filename " );
70
+ throw new \RuntimeException ("Cannot parse the certificate $ sourceName " );
62
71
}
63
72
64
73
// get the public key
@@ -74,7 +83,7 @@ public function __construct(string $filename, OpenSSL $openSSL = null)
74
83
} elseif (isset ($ data ['serialNumber ' ])) {
75
84
$ serial ->loadDecimal ($ data ['serialNumber ' ]);
76
85
} else {
77
- throw new \RuntimeException ("Cannot get serialNumberHex or serialNumber from certificate file $ filename " );
86
+ throw new \RuntimeException ("Cannot get serialNumberHex or serialNumber from certificate $ sourceName " );
78
87
}
79
88
$ this ->serial = $ serial ;
80
89
$ this ->validFrom = $ data ['validFrom_time_t ' ] ?? 0 ;
@@ -84,12 +93,29 @@ public function __construct(string $filename, OpenSSL $openSSL = null)
84
93
$ this ->filename = $ filename ;
85
94
}
86
95
96
+ private function extractPemCertificate (string $ contents ): string
97
+ {
98
+ if (strlen ($ contents ) < 2000 ) {
99
+ return '' ; // is too short to be a PEM certificate
100
+ }
101
+ $ openssl = $ this ->getOpenSSL ();
102
+ $ decoded = @base64_decode ($ contents , true ) ?: '' ;
103
+ if ($ contents === base64_encode ($ decoded )) { // is a one liner certificate
104
+ $ doubleEncoded = $ openssl ->readPemContents ($ decoded )->certificate ();
105
+ if ($ doubleEncoded !== '' ) {
106
+ return $ doubleEncoded ;
107
+ }
108
+ $ contents = $ this ->getOpenSSL ()->derCerConvertPhp ($ decoded );
109
+ }
110
+ return $ openssl ->readPemContents ($ contents )->certificate ();
111
+ }
112
+
87
113
private function obtainPemCertificate (string $ contents ): string
88
114
{
89
115
$ openssl = $ this ->getOpenSSL ();
90
116
$ extracted = $ openssl ->readPemContents ($ contents )->certificate ();
91
117
if ('' === $ extracted ) { // cannot extract, could be on DER format
92
- $ extracted = $ openssl ->derCerConvertPhp ($ contents );
118
+ $ extracted = $ this -> getOpenSSL () ->derCerConvertPhp ($ contents );
93
119
}
94
120
return $ extracted ;
95
121
}
0 commit comments