Rev 2 | Rev 10 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2 | Rev 5 | ||
---|---|---|---|
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * X.509 Utilities for PHP |
4 | * X.509 Utilities for PHP |
5 | * Copyright 2011-2014 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2011-2014 Daniel Marschall, ViaThinkSoft |
6 | * Version 2014-11-17 |
6 | * Version 2014-11-17 |
7 | * |
7 | * |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | * you may not use this file except in compliance with the License. |
9 | * you may not use this file except in compliance with the License. |
10 | * You may obtain a copy of the License at |
10 | * You may obtain a copy of the License at |
11 | * |
11 | * |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | * |
13 | * |
14 | * Unless required by applicable law or agreed to in writing, software |
14 | * Unless required by applicable law or agreed to in writing, software |
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | * See the License for the specific language governing permissions and |
17 | * See the License for the specific language governing permissions and |
18 | * limitations under the License. |
18 | * limitations under the License. |
19 | */ |
19 | */ |
20 | 20 | ||
21 | # define('OPENSSL_EXEC', 'openssl'); |
21 | # define('OPENSSL_EXEC', 'openssl'); |
22 | # define('OPENSSL_EXEC', 'torify openssl'); |
22 | # define('OPENSSL_EXEC', 'torify openssl'); |
23 | define('OPENSSL_EXEC', 'vtor -cr 1 -- openssl'); |
23 | define('OPENSSL_EXEC', 'vtor -cr 1 -- openssl'); |
24 | 24 | ||
25 | # ToDo: For every function 2 modes: certFile, certPEM |
25 | # ToDo: For every function 2 modes: certFile, certPEM |
26 | 26 | ||
27 | function x_509_matching_issuer($cert, $issuer) { |
27 | function x_509_matching_issuer($cert, $issuer) { |
28 | exec(OPENSSL_EXEC.' verify -purpose any -CApath /dev/null -CAfile '.escapeshellarg($issuer).' '.escapeshellarg($cert), $out, $code); |
28 | exec(OPENSSL_EXEC.' verify -purpose any -CApath /dev/null -CAfile '.escapeshellarg($issuer).' '.escapeshellarg($cert), $out, $code); |
29 | $out = implode("\n", $out); |
29 | $out = implode("\n", $out); |
30 | # Ab 1.0 wird hier ein Errorcode zurückgeliefert |
30 | # Ab 1.0 wird hier ein Errorcode zurückgeliefert |
31 | # if ($code != 0) return false; |
31 | # if ($code != 0) return false; |
32 | 32 | ||
33 | # TODO |
33 | # TODO |
34 | # error 20 at 0 depth lookup:unable to get local issuer certificate |
34 | # error 20 at 0 depth lookup:unable to get local issuer certificate |
35 | $chain0_ok = strpos($out, "error 2 at 1 depth lookup:unable to get issuer certificate") !== false; |
35 | $chain0_ok = strpos($out, "error 2 at 1 depth lookup:unable to get issuer certificate") !== false; |
36 | $all_ok = substr($out, -2) == 'OK'; |
36 | $all_ok = substr($out, -2) == 'OK'; |
37 | 37 | ||
38 | $ok = $chain0_ok | $all_ok; |
38 | $ok = $chain0_ok | $all_ok; |
39 | 39 | ||
40 | return $ok; |
40 | return $ok; |
41 | } |
41 | } |
42 | 42 | ||
43 | function x_509_is_crl_file($infile) { # Only PEM files |
43 | function x_509_is_crl_file($infile) { # Only PEM files |
44 | $cx = file($infile); |
44 | $cx = file($infile); |
45 | return trim($cx[0]) == '-----BEGIN X509 CRL-----'; |
45 | return trim($cx[0]) == '-----BEGIN X509 CRL-----'; |
46 | } |
46 | } |
47 | 47 | ||
48 | function x_509_chain($infile, $CApath) { |
48 | function x_509_chain($infile, $CApath) { |
49 | $chain = array(); |
49 | $chain = array(); |
50 | $chain[] = $infile; |
50 | $chain[] = $infile; |
51 | 51 | ||
52 | while (true) { |
52 | while (true) { |
53 | $out = array(); |
53 | $out = array(); |
54 | exec(OPENSSL_EXEC.' x509 -issuer_hash -in '.escapeshellarg($infile).' -noout', $out, $code); |
54 | exec(OPENSSL_EXEC.' x509 -issuer_hash -in '.escapeshellarg($infile).' -noout', $out, $code); |
55 | if ($code != 0) return false; |
55 | if ($code != 0) return false; |
56 | $hash = $out[0]; |
56 | $hash = $out[0]; |
57 | unset($out); |
57 | unset($out); |
58 | 58 | ||
59 | # $ary = glob($CApath . $hash . '.*'); |
59 | # $ary = glob($CApath . $hash . '.*'); |
60 | # $aryr = glob($CApath . $hash . '.r*'); |
60 | # $aryr = glob($CApath . $hash . '.r*'); |
61 | 61 | ||
62 | $ary = array(); |
62 | $ary = array(); |
63 | $aryr = array(); |
63 | $aryr = array(); |
64 | $all_trusted = glob($CApath . '*.pem'); |
64 | $all_trusted = glob($CApath . '*.pem'); |
65 | foreach ($all_trusted as &$a) { |
65 | foreach ($all_trusted as &$a) { |
66 | if (x_509_is_crl_file($a)) { |
66 | if (x_509_is_crl_file($a)) { |
67 | $out = array(); |
67 | $out = array(); |
68 | exec(OPENSSL_EXEC.' crl -hash -noout -in '.escapeshellarg($a), $out, $code); |
68 | exec(OPENSSL_EXEC.' crl -hash -noout -in '.escapeshellarg($a), $out, $code); |
69 | if ($code != 0) return false; |
69 | if ($code != 0) return false; |
70 | $this_hash = trim($out[0]); |
70 | $this_hash = trim($out[0]); |
71 | unset($out); |
71 | unset($out); |
72 | # echo "CRL $a : $this_hash == $hash<br>\n"; |
72 | # echo "CRL $a : $this_hash == $hash<br>\n"; |
73 | if ($this_hash == $hash) { |
73 | if ($this_hash == $hash) { |
74 | $aryr[] = $a; |
74 | $aryr[] = $a; |
75 | } |
75 | } |
76 | if ($code != 0) return false; |
76 | if ($code != 0) return false; |
77 | } else { |
77 | } else { |
78 | $out = array(); |
78 | $out = array(); |
79 | exec(OPENSSL_EXEC.' x509 -subject_hash -noout -in '.escapeshellarg($a), $out, $code); |
79 | exec(OPENSSL_EXEC.' x509 -subject_hash -noout -in '.escapeshellarg($a), $out, $code); |
80 | if ($code != 0) return false; |
80 | if ($code != 0) return false; |
81 | $this_hash = trim($out[0]); |
81 | $this_hash = trim($out[0]); |
82 | unset($out); |
82 | unset($out); |
83 | # echo "CERT $a : $this_hash == $hash<br>\n"; |
83 | # echo "CERT $a : $this_hash == $hash<br>\n"; |
84 | if ($this_hash == $hash) { |
84 | if ($this_hash == $hash) { |
85 | $ary[] = $a; |
85 | $ary[] = $a; |
86 | } |
86 | } |
87 | } |
87 | } |
88 | } |
88 | } |
89 | 89 | ||
90 | $found = false; |
90 | $found = false; |
91 | # echo "Searching issuer for $infile... (Hash = $hash)<br>\n"; |
91 | # echo "Searching issuer for $infile... (Hash = $hash)<br>\n"; |
92 | foreach ($ary as &$a) { |
92 | foreach ($ary as &$a) { |
93 | if (in_array($a, $aryr)) continue; |
93 | if (in_array($a, $aryr)) continue; |
94 | 94 | ||
95 | # echo "Check $a...<br>\n"; |
95 | # echo "Check $a...<br>\n"; |
96 | if (x_509_matching_issuer($infile, $a)) { |
96 | if (x_509_matching_issuer($infile, $a)) { |
97 | # echo "Found! New file is $a<br>\n"; |
97 | # echo "Found! New file is $a<br>\n"; |
98 | $found = true; |
98 | $found = true; |
99 | $infile = $a; |
99 | $infile = $a; |
100 | 100 | ||
101 | if (in_array($a, $chain)) { |
101 | if (in_array($a, $chain)) { |
102 | # echo "Finished.\n"; |
102 | # echo "Finished.\n"; |
103 | return $chain; |
103 | return $chain; |
104 | } |
104 | } |
105 | 105 | ||
106 | $chain[] = $a; |
106 | $chain[] = $a; |
107 | break; |
107 | break; |
108 | } |
108 | } |
109 | } |
109 | } |
110 | if (!$found) { |
110 | if (!$found) { |
111 | # echo "No issuer found!\n"; |
111 | # echo "No issuer found!\n"; |
112 | return false; |
112 | return false; |
113 | } |
113 | } |
114 | } |
114 | } |
115 | } |
115 | } |
116 | 116 | ||
117 | function x_509_get_ocsp_uris($infile) { |
117 | function x_509_get_ocsp_uris($infile) { |
118 | exec(OPENSSL_EXEC.' x509 -ocsp_uri -in '.escapeshellarg($infile).' -noout', $out, $code); |
118 | exec(OPENSSL_EXEC.' x509 -ocsp_uri -in '.escapeshellarg($infile).' -noout', $out, $code); |
119 | if ($code != 0) return false; |
119 | if ($code != 0) return false; |
120 | return $out; |
120 | return $out; |
121 | } |
121 | } |
122 | 122 | ||
123 | 123 | ||
124 | function x_509_ocsp_check_chain($infile, $CApath) { |
124 | function x_509_ocsp_check_chain($infile, $CApath) { |
125 | return '(Skipped)'; # TODO: we need caching, otherwise the page is too slow |
125 | return '(Skipped)'; # TODO: we need caching, otherwise the page is too slow |
126 | 126 | ||
127 | $x = x_509_chain($infile, $CApath); |
127 | $x = x_509_chain($infile, $CApath); |
128 | 128 | ||
129 | if ($x === false) { |
129 | if ($x === false) { |
130 | return 'Error: Could not complete chain!'; |
130 | return 'Error: Could not complete chain!'; |
131 | } |
131 | } |
132 | 132 | ||
133 | # echo 'Chain: '; |
133 | # echo 'Chain: '; |
134 | # print_r($x); |
134 | # print_r($x); |
135 | 135 | ||
136 | $found_ocsp = false; |
136 | $found_ocsp = false; |
137 | $diag_nonce_err = false; |
137 | $diag_nonce_err = false; |
138 | $diag_verify_err = false; |
138 | $diag_verify_err = false; |
139 | $diag_revoked = false; |
139 | $diag_revoked = false; |
140 | $diag_unknown = false; |
140 | $diag_unknown = false; |
141 | 141 | ||
142 | foreach ($x as $n => &$y) { |
142 | foreach ($x as $n => &$y) { |
143 | if (isset($x[$n+1])) { |
143 | if (isset($x[$n+1])) { |
144 | $issuer = $x[$n+1]; |
144 | $issuer = $x[$n+1]; |
145 | } else { |
145 | } else { |
146 | $issuer = $y; // Root |
146 | $issuer = $y; // Root |
147 | } |
147 | } |
148 | 148 | ||
149 | $uris = x_509_get_ocsp_uris($y); |
149 | $uris = x_509_get_ocsp_uris($y); |
150 | 150 | ||
151 | foreach ($uris as &$uri) { |
151 | foreach ($uris as &$uri) { |
152 | $found_ocsp = true; |
152 | $found_ocsp = true; |
153 | 153 | ||
154 | $out = array(); |
154 | $out = array(); |
155 | $xx = parse_url($uri); |
155 | $xx = parse_url($uri); |
156 | $host = $xx['host']; |
156 | $host = $xx['host']; |
157 | # $cmd = OPENSSL_EXEC." ocsp -issuer ".escapeshellarg($issuer)." -cert ".escapeshellarg($y)." -url ".escapeshellarg($uri)." -CApath ".escapeshellarg($CApath)." -VAfile ".escapeshellarg($issuer)." -nonce -header 'HOST' ".escapeshellarg($host)." -header 'User-Agent' 'Mozilla/5.0 (Windows NT 6.1; rv23.0) Gecko/20100101 Firefox/23.0' 2>&1" /* -text */; |
157 | # $cmd = OPENSSL_EXEC." ocsp -issuer ".escapeshellarg($issuer)." -cert ".escapeshellarg($y)." -url ".escapeshellarg($uri)." -CApath ".escapeshellarg($CApath)." -VAfile ".escapeshellarg($issuer)." -nonce -header 'HOST' ".escapeshellarg($host)." -header 'User-Agent' 'Mozilla/5.0 (Windows NT 6.1; rv23.0) Gecko/20100101 Firefox/23.0' 2>&1" /* -text */; |
158 | # TODO: trusted.pem nicht hartcoden |
158 | # TODO: trusted.pem nicht hartcoden |
159 | $cmd = OPENSSL_EXEC." ocsp -issuer ".escapeshellarg($issuer)." -cert ".escapeshellarg($y)." -url ".escapeshellarg($uri)." -CAfile ".escapeshellarg($CApath.'/../trusted.pem')." -VAfile ".escapeshellarg($issuer)." -nonce -header 'HOST' ".escapeshellarg($host)." -header 'User-Agent' 'Mozilla/5.0 (Windows NT 6.1; rv23.0) Gecko/20100101 Firefox/23.0' 2>&1" /* -text */; |
159 | $cmd = OPENSSL_EXEC." ocsp -issuer ".escapeshellarg($issuer)." -cert ".escapeshellarg($y)." -url ".escapeshellarg($uri)." -CAfile ".escapeshellarg($CApath.'/../trusted.pem')." -VAfile ".escapeshellarg($issuer)." -nonce -header 'HOST' ".escapeshellarg($host)." -header 'User-Agent' 'Mozilla/5.0 (Windows NT 6.1; rv23.0) Gecko/20100101 Firefox/23.0' 2>&1" /* -text */; |
160 | #echo $cmd; |
160 | #echo $cmd; |
161 | exec($cmd, $out, $code); |
161 | exec($cmd, $out, $code); |
162 | if ($code != 0) { |
162 | if ($code != 0) { |
163 | if (($out[0] == 'Error querying OCSP responsder') || |
163 | if (($out[0] == 'Error querying OCSP responsder') || |
164 | ($out[0] == 'Error querying OCSP responder')) { |
164 | ($out[0] == 'Error querying OCSP responder')) { |
165 | # TODO: openssl has a typo 'Error querying OCSP responsder' |
165 | # TODO: openssl has a typo 'Error querying OCSP responsder' |
166 | # TODO: why does this error occour for comodo CA? |
166 | # TODO: why does this error occour for comodo CA? |
167 | return "Error querying OCSP responder (Code $code)"; |
167 | return "Error querying OCSP responder (Code $code)"; |
168 | } |
168 | } |
169 | # print_r($out); |
169 | # print_r($out); |
170 | return 'Error: OpenSSL-Exec failure ('.$code.')!'; |
170 | return 'Error: OpenSSL-Exec failure ('.$code.')!'; |
171 | } |
171 | } |
172 | 172 | ||
173 | $outc = implode("\n", $out); |
173 | $outc = implode("\n", $out); |
174 | if (strpos($outc, "Response verify OK") === false) $diag_verify_err = true; |
174 | if (strpos($outc, "Response verify OK") === false) $diag_verify_err = true; |
175 | if (strpos($outc, "WARNING: no nonce in response") !== false) $diag_nonce_err = true; |
175 | if (strpos($outc, "WARNING: no nonce in response") !== false) $diag_nonce_err = true; |
176 | # We are currently not watching for other warnings (ToDo) |
176 | # We are currently not watching for other warnings (ToDo) |
177 | 177 | ||
178 | if (strpos($outc, "$y: unknown") !== false) { |
178 | if (strpos($outc, "$y: unknown") !== false) { |
179 | $diag_unknown = true; |
179 | $diag_unknown = true; |
180 | } else if (strpos($outc, "$y: revoked") !== false) { |
180 | } else if (strpos($outc, "$y: revoked") !== false) { |
181 | $diag_revoked = true; |
181 | $diag_revoked = true; |
182 | } else if (strpos($outc, "$y: good") === false) { |
182 | } else if (strpos($outc, "$y: good") === false) { |
183 | #echo "C = $outc<br>\n"; |
183 | #echo "C = $outc<br>\n"; |
184 | #Ã TODO: |
184 | #Ã TODO: |
185 | # COMODO sagt |
185 | # COMODO sagt |
186 | # C = Responder Error: unauthorized |
186 | # C = Responder Error: unauthorized |
187 | # STARTCOM sagt |
187 | # STARTCOM sagt |
188 | # C = Responder Error: malformedrequest |
188 | # C = Responder Error: malformedrequest |
189 | return "Error: Unexpected OCSP state! ($outc)"; |
189 | return "Error: Unexpected OCSP state! ($outc)"; |
190 | } |
190 | } |
191 | 191 | ||
192 | # print_r($out); |
192 | # print_r($out); |
193 | unset($out); |
193 | unset($out); |
194 | } |
194 | } |
195 | } |
195 | } |
196 | 196 | ||
197 | # echo "Found OCSP = ".($found_ocsp ? 1 : 0)."\n"; |
197 | # echo "Found OCSP = ".($found_ocsp ? 1 : 0)."\n"; |
198 | # echo "Diag Nonce Error = ".($diag_nonce_err ? 1 : 0)."\n"; |
198 | # echo "Diag Nonce Error = ".($diag_nonce_err ? 1 : 0)."\n"; |
199 | # echo "Diag Verify Error = ".($diag_verify_err ? 1 : 0)."\n"; |
199 | # echo "Diag Verify Error = ".($diag_verify_err ? 1 : 0)."\n"; |
200 | # echo "Diag Revoked Error = ".($diag_revoked ? 1 : 0)."\n"; |
200 | # echo "Diag Revoked Error = ".($diag_revoked ? 1 : 0)."\n"; |
201 | # echo "Diag Unknown Error = ".($diag_unknown ? 1 : 0)."\n"; |
201 | # echo "Diag Unknown Error = ".($diag_unknown ? 1 : 0)."\n"; |
202 | 202 | ||
203 | if (!$found_ocsp) { |
203 | if (!$found_ocsp) { |
204 | return 'No OCSP responders found in chain.'; |
204 | return 'No OCSP responders found in chain.'; |
205 | } |
205 | } |
206 | 206 | ||
207 | if ($diag_verify_err) { |
207 | if ($diag_verify_err) { |
208 | return 'Error: OCSP Verification failure!'; |
208 | return 'Error: OCSP Verification failure!'; |
209 | } |
209 | } |
210 | 210 | ||
211 | if ($diag_revoked) { |
211 | if ($diag_revoked) { |
212 | return 'Error: Some certs are revoked!'; |
212 | return 'Error: Some certs are revoked!'; |
213 | } |
213 | } |
214 | 214 | ||
215 | if ($diag_unknown) { |
215 | if ($diag_unknown) { |
216 | return 'Warning: Some certs have unknown state!'; |
216 | return 'Warning: Some certs have unknown state!'; |
217 | } |
217 | } |
218 | 218 | ||
219 | if ($diag_nonce_err) { |
219 | if ($diag_nonce_err) { |
220 | return 'OK, but NONCE missing'; |
220 | return 'OK, but NONCE missing'; |
221 | } |
221 | } |
222 | 222 | ||
223 | return 'OK'; |
223 | return 'OK'; |
224 | } |
224 | } |
225 | 225 | ||
226 | function _opensslVerify($cert, $mode = 0, $crl_mode = 0) { |
226 | function _opensslVerify($cert, $mode = 0, $crl_mode = 0) { |
227 | # mode |
227 | # mode |
228 | # 0 = cert is a file |
228 | # 0 = cert is a file |
229 | # 1 = cert is pem string |
229 | # 1 = cert is pem string |
230 | 230 | ||
231 | # crl_mode |
231 | # crl_mode |
232 | # 0 = no crl check |
232 | # 0 = no crl check |
233 | # 1 = 1 crl check |
233 | # 1 = 1 crl check |
234 | # 2 = all crl check |
234 | # 2 = all crl check |
235 | 235 | ||
236 | $params = ''; |
236 | $params = ''; |
237 | if ($crl_mode == 0) { |
237 | if ($crl_mode == 0) { |
238 | $params = ''; |
238 | $params = ''; |
239 | } else if ($crl_mode == 1) { |
239 | } else if ($crl_mode == 1) { |
240 | $params = '-crl_check '; |
240 | $params = '-crl_check '; |
241 | } else if ($crl_mode == 2) { |
241 | } else if ($crl_mode == 2) { |
242 | $params = '-crl_check_all '; |
242 | $params = '-crl_check_all '; |
243 | } else { |
243 | } else { |
244 | return false; |
244 | return false; |
245 | } |
245 | } |
246 | 246 | ||
247 | if ($mode == 0) { |
247 | if ($mode == 0) { |
248 | # $cmd = OPENSSL_EXEC.' verify '.$params.' -CApath '.escapeshellarg(__DIR__.'/../ca/trusted/').' '.escapeshellarg($cert); |
248 | # $cmd = OPENSSL_EXEC.' verify '.$params.' -CApath '.escapeshellarg(__DIR__.'/../ca/trusted/').' '.escapeshellarg($cert); |
249 | $cmd = OPENSSL_EXEC.' verify '.$params.' -CAfile '.escapeshellarg(__DIR__.'/../ca/trusted.pem').' '.escapeshellarg($cert); |
249 | $cmd = OPENSSL_EXEC.' verify '.$params.' -CAfile '.escapeshellarg(__DIR__.'/../ca/trusted.pem').' '.escapeshellarg($cert); |
250 | } else if ($mode == 1) { |
250 | } else if ($mode == 1) { |
251 | # $cmd = 'echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' verify '.$params.' -CApath '.escapeshellarg(__DIR__.'/../ca/trusted/'); |
251 | # $cmd = 'echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' verify '.$params.' -CApath '.escapeshellarg(__DIR__.'/../ca/trusted/'); |
252 | $cmd = 'echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' verify '.$params.' -CAfile '.escapeshellarg(__DIR__.'/../ca/trusted.pem'); |
252 | $cmd = 'echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' verify '.$params.' -CAfile '.escapeshellarg(__DIR__.'/../ca/trusted.pem'); |
253 | } else { |
253 | } else { |
254 | return false; |
254 | return false; |
255 | } |
255 | } |
256 | $out = array(); |
256 | $out = array(); |
257 | exec($cmd, $out, $code); |
257 | exec($cmd, $out, $code); |
258 | 258 | ||
259 | if ($code != 0) return false; |
259 | if ($code != 0) return false; |
260 | 260 | ||
261 | return $out; |
261 | return $out; |
262 | } |
262 | } |
263 | 263 | ||
264 | function opensslVerify($cert, $mode = 0) { |
264 | function opensslVerify($cert, $mode = 0) { |
265 | # 0 = cert is a file |
265 | # 0 = cert is a file |
266 | # 1 = cert is pem string |
266 | # 1 = cert is pem string |
267 | 267 | ||
268 | $out = _opensslVerify($cert, $mode, 0); |
268 | $out = _opensslVerify($cert, $mode, 0); |
269 | if ($out === false) return 'Internal error'; |
269 | if ($out === false) return 'Internal error'; |
270 | $outtext = implode("\n", $out); |
270 | $outtext = implode("\n", $out); |
271 | 271 | ||
272 | $out_crl = _opensslVerify($cert, $mode, 2); |
272 | $out_crl = _opensslVerify($cert, $mode, 2); |
273 | if ($out_crl === false) return 'Internal error'; |
273 | if ($out_crl === false) return 'Internal error'; |
274 | $outtext_crl = implode("\n", $out_crl); |
274 | $outtext_crl = implode("\n", $out_crl); |
275 | 275 | ||
276 | if (strpos($outtext, "unable to get local issuer certificate") !== false) { |
276 | if (strpos($outtext, "unable to get local issuer certificate") !== false) { |
277 | return 'CA unknown'; |
277 | return 'CA unknown'; |
278 | } else if (strpos($outtext, "certificate signature failure") !== false) { |
278 | } else if (strpos($outtext, "certificate signature failure") !== false) { |
279 | return 'Fraudulent!'; |
279 | return 'Fraudulent!'; |
280 | } |
280 | } |
281 | 281 | ||
282 | $stat_expired = (strpos($outtext, "certificate has expired") !== false); |
282 | $stat_expired = (strpos($outtext, "certificate has expired") !== false); |
283 | $stat_revoked = (strpos($outtext_crl, "certificate revoked") !== false); |
283 | $stat_revoked = (strpos($outtext_crl, "certificate revoked") !== false); |
284 | 284 | ||
285 | # (ToDo) We are currently not looking for warnings |
285 | # (ToDo) We are currently not looking for warnings |
286 | # $stat_crl_expired = (strpos($outtext_crl, "CRL has expired") !== false); |
286 | # $stat_crl_expired = (strpos($outtext_crl, "CRL has expired") !== false); |
287 | 287 | ||
288 | if ($stat_expired && $stat_revoked) { |
288 | if ($stat_expired && $stat_revoked) { |
289 | return 'Expired & Revoked'; |
289 | return 'Expired & Revoked'; |
290 | } else if ($stat_revoked) { |
290 | } else if ($stat_revoked) { |
291 | return 'Revoked'; |
291 | return 'Revoked'; |
292 | } else if ($stat_expired) { |
292 | } else if ($stat_expired) { |
293 | return 'Expired'; |
293 | return 'Expired'; |
294 | } |
294 | } |
295 | 295 | ||
296 | if (strpos($out[0], ': OK') !== false) { |
296 | if (strpos($out[0], ': OK') !== false) { |
297 | return 'Verified'; |
297 | return 'Verified'; |
298 | } |
298 | } |
299 | 299 | ||
300 | return 'Unknown error'; |
300 | return 'Unknown error'; |
301 | } |
301 | } |
302 | 302 | ||
303 | function getTextdump($cert, $mode = 0, $format = 0) { |
303 | function getTextdump($cert, $mode = 0, $format = 0) { |
304 | # mode |
304 | # mode |
305 | # 0 = cert is a file |
305 | # 0 = cert is a file |
306 | # 1 = cert is pem string |
306 | # 1 = cert is pem string |
307 | 307 | ||
308 | # format |
308 | # format |
309 | # 0 = normal |
309 | # 0 = normal |
310 | # 1 = nameopt |
310 | # 1 = nameopt |
311 | 311 | ||
312 | if ($format == 0) { |
312 | if ($format == 0) { |
313 | $params = ''; |
313 | $params = ''; |
314 | } else if ($format == 1) { |
314 | } else if ($format == 1) { |
315 | $params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq, lname"'; |
315 | $params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq, lname"'; |
316 | } else { |
316 | } else { |
317 | return false; |
317 | return false; |
318 | } |
318 | } |
319 | 319 | ||
320 | if ($mode == 0) { |
320 | if ($mode == 0) { |
321 | exec(OPENSSL_EXEC.' x509 -noout -text'.$params.' -in '.escapeshellarg($cert), $out, $code); |
321 | exec(OPENSSL_EXEC.' x509 -noout -text'.$params.' -in '.escapeshellarg($cert), $out, $code); |
322 | } else if ($mode == 1) { |
322 | } else if ($mode == 1) { |
323 | exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout -text'.$params, $out, $code); |
323 | exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout -text'.$params, $out, $code); |
324 | } else { |
324 | } else { |
325 | return false; |
325 | return false; |
326 | } |
326 | } |
327 | 327 | ||
328 | if ($code != 0) return false; |
328 | if ($code != 0) return false; |
329 | 329 | ||
330 | $text = implode("\n", $out); |
330 | $text = implode("\n", $out); |
331 | 331 | ||
332 | $text = str_replace("\n\n", "\n", $text); # TODO: repeat until no \n\n exist anymore |
332 | $text = str_replace("\n\n", "\n", $text); # TODO: repeat until no \n\n exist anymore |
333 | 333 | ||
334 | return $text; |
334 | return $text; |
335 | } |
335 | } |
336 | 336 | ||
337 | function getAttributes($cert, $mode = 0, $issuer = false, $longnames = false) { |
337 | function getAttributes($cert, $mode = 0, $issuer = false, $longnames = false) { |
338 | # mode |
338 | # mode |
339 | # 0 = cert is a file |
339 | # 0 = cert is a file |
340 | # 1 = cert is pem string |
340 | # 1 = cert is pem string |
341 | 341 | ||
342 | if ($longnames) { |
342 | if ($longnames) { |
343 | $params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq, lname"'; |
343 | $params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq, lname"'; |
344 | } else { |
344 | } else { |
345 | $params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq"'; |
345 | $params = ' -nameopt "esc_ctrl, esc_msb, sep_multiline, space_eq"'; |
346 | } |
346 | } |
347 | 347 | ||
348 | if ($issuer) { |
348 | if ($issuer) { |
349 | $params .= ' -issuer'; |
349 | $params .= ' -issuer'; |
350 | } else { |
350 | } else { |
351 | $params .= ' -subject'; |
351 | $params .= ' -subject'; |
352 | } |
352 | } |
353 | 353 | ||
354 | if ($mode == 0) { |
354 | if ($mode == 0) { |
355 | exec(OPENSSL_EXEC.' x509 -noout'.$params.' -in '.escapeshellarg($cert), $out, $code); |
355 | exec(OPENSSL_EXEC.' x509 -noout'.$params.' -in '.escapeshellarg($cert), $out, $code); |
356 | } else if ($mode == 1) { |
356 | } else if ($mode == 1) { |
357 | exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout'.$params, $out, $code); |
357 | exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout'.$params, $out, $code); |
358 | } else { |
358 | } else { |
359 | return false; |
359 | return false; |
360 | } |
360 | } |
361 | 361 | ||
362 | $attributes = array(); |
362 | $attributes = array(); |
363 | foreach ($out as $n => &$o) { |
363 | foreach ($out as $n => &$o) { |
364 | if ($n == 0) continue; |
364 | if ($n == 0) continue; |
365 | preg_match("| (.*) = (.*)$|ismU", $o, $m); |
365 | preg_match("| (.*) = (.*)$|ismU", $o, $m); |
366 | if (!isset($attributes[$m[1]])) $attributes[$m[1]] = array(); |
366 | if (!isset($attributes[$m[1]])) $attributes[$m[1]] = array(); |
367 | $attributes[$m[1]][] = $m[2]; |
367 | $attributes[$m[1]][] = $m[2]; |
368 | } |
368 | } |
369 | 369 | ||
370 | return $attributes; |
370 | return $attributes; |
371 | } |
371 | } |
372 | 372 | ||
373 | function openssl_get_sig_base64($cert, $mode = 0) { |
373 | function openssl_get_sig_base64($cert, $mode = 0) { |
374 | # mode |
374 | # mode |
375 | # 0 = cert is a file |
375 | # 0 = cert is a file |
376 | # 1 = cert is pem string |
376 | # 1 = cert is pem string |
377 | 377 | ||
378 | $out = array(); |
378 | $out = array(); |
379 | if ($mode == 0) { |
379 | if ($mode == 0) { |
380 | exec(OPENSSL_EXEC.' x509 -noout'.$params.' -in '.escapeshellarg($cert), $out, $code); |
380 | exec(OPENSSL_EXEC.' x509 -noout'.$params.' -in '.escapeshellarg($cert), $out, $code); |
381 | } else if ($mode == 1) { |
381 | } else if ($mode == 1) { |
382 | exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout'.$params, $out, $code); |
382 | exec('echo '.escapeshellarg($cert).' | '.OPENSSL_EXEC.' x509 -noout'.$params, $out, $code); |
383 | } else { |
383 | } else { |
384 | return false; |
384 | return false; |
385 | } |
385 | } |
386 | $dump = implode("\n", $out); |
386 | $dump = implode("\n", $out); |
387 | 387 | ||
388 | /* |
388 | /* |
389 | 389 | ||
390 | Signature Algorithm: sha1WithRSAEncryption |
390 | Signature Algorithm: sha1WithRSAEncryption |
391 | 65:f0:6f:f0:1d:66:a4:fe:d1:38:85:6f:5e:06:7b:f3:a7:08: |
391 | 65:f0:6f:f0:1d:66:a4:fe:d1:38:85:6f:5e:06:7b:f3:a7:08: |
392 | ... |
392 | ... |
393 | 1a:13:37 |
393 | 1a:13:37 |
394 | 394 | ||
395 | */ |
395 | */ |
396 | 396 | ||
397 | $regex = "@\n {4}Signature Algorithm: (\S+)\n(( {8}([a-f0-9][a-f0-9]:){18}\n)* {8}([a-f0-9][a-f0-9](:[a-f0-9][a-f0-9]){0,17}\n))@sm"; |
397 | $regex = "@\n {4}Signature Algorithm: (\S+)\n(( {8}([a-f0-9][a-f0-9]:){18}\n)* {8}([a-f0-9][a-f0-9](:[a-f0-9][a-f0-9]){0,17}\n))@sm"; |
398 | preg_match_all($regex, "$dump\n", $m); |
398 | preg_match_all($regex, "$dump\n", $m); |
399 | if (!isset($m[2][0])) return false; |
399 | if (!isset($m[2][0])) return false; |
400 | $x = preg_replace("@[^a-z0-9]@", "", $m[2][0]); |
400 | $x = preg_replace("@[^a-z0-9]@", "", $m[2][0]); |
401 | $x = hex2bin($x); |
401 | $x = hex2bin($x); |
402 | return base64_encode($x); |
402 | return base64_encode($x); |
403 | } |
403 | } |
404 | 404 |