1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
<?php
// Copyright (C) 2015 Remy van Elst
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
function ocsp_stapling($host, $ip, $port) {
//used openssl cli to check if host has enabled oscp stapling.
global $timeout;
// OpenSSL 1.1.0 has ipv6 support: https://rt.openssl.org/Ticket/Display.html?id=1832
// if (filter_var(preg_replace('/[^A-Za-z0-9\.\:_-]/', '', $ip), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
// // ipv6 openssl tools are broken. (https://rt.openssl.org/Ticket/Display.html?id=1365&user=guest&pass=guest)
// return false;
// }
$result = "";
// escapeshellcmd adds \[\] to ipv6 address.
// todo: look into escapeshellarg vs. escapeshellcmd
if (filter_var(preg_replace('/[^A-Za-z0-9\.\:_-]/', '', $ip), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$output = shell_exec('echo | timeout ' . $timeout . ' openssl s_client -servername "' . escapeshellcmd($host) . '" -connect \'' . $ip . ':' . escapeshellcmd($port) . '\' -tlsextdebug -status 2>&1 | sed -n "/OCSP response:/,/---/p"');
} else {
$output = shell_exec('echo | timeout ' . $timeout . ' openssl s_client -servername "' . escapeshellcmd($host) . '" -connect "' . escapeshellcmd($ip) . ':' . escapeshellcmd($port) . '" -tlsextdebug -status 2>&1 | sed -n "/OCSP response:/,/---/p"');
}
if (strpos($output, "no response sent") !== false) {
$result = array("working" => 0,
"cert_status" => "No response sent");
}
if (strpos($output, "OCSP Response Data:") !== false) {
$lines = array();
$output = preg_replace("/[[:blank:]]+/"," ", $output);
$stapling_status_lines = explode("\n", $output);
$stapling_status_lines = array_map('trim', $stapling_status_lines);
foreach($stapling_status_lines as $line) {
if(endsWith($line, ":") == false) {
list($k, $v) = explode(":", $line);
$lines[trim($k)] = trim($v);
}
}
$result = array("working" => 1,
"cert_status" => $lines["Cert Status"],
"this_update" => $lines["This Update"],
"next_update" => $lines["Next Update"],
"responder_id" => $lines["Responder Id"],
"hash_algorithm" => $lines["Hash Algorithm"],
"signature_algorithm" => $lines["Signature Algorithm"],
"issuer_name_hash" => $lines["Issuer Name Hash"]);
}
return $result;
}
function ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri) {
//uses openssl cli to validate cert status with ocsp
global $random_blurp, $timeout;
$result = array();
$tmp_dir = '/tmp/';
$root_ca = getcwd() . '/cacert.pem';
$pem_issuer = "";
$pem_client = "";
openssl_x509_export($raw_cert_data, $pem_client);
openssl_x509_export_to_file($raw_cert_data, $tmp_dir.$random_blurp.'.cert_client.pem');
openssl_x509_export($raw_next_cert_data, $pem_issuer);
openssl_x509_export_to_file($raw_next_cert_data, $tmp_dir.$random_blurp.'.cert_issuer.pem');
$isser_loc = $tmp_dir.$random_blurp.'.cert_issuer.pem';
// Some OCSP's want HTTP/1.1 but OpenSSL does not do that. Add Host header as workaround.
$ocsp_host = parse_url($ocsp_uri, PHP_URL_HOST);
$output = shell_exec('timeout ' . $timeout . ' | openssl ocsp -resp_text -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc .' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST='. escapeshellcmd($ocsp_host) . '" 2>&1');
$filter_output = shell_exec('timeout ' . $timeout . ' | openssl ocsp -resp_text -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc .' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST='. escapeshellcmd($ocsp_host) . '" 2>&1 | grep -v -e "to get local issuer certificate" -e "signer certificate not found" -e "Response Verify" -e "'. $tmp_dir.$random_blurp.'.cert_client.pem" | grep -e "Cert Status:" -e "Revocation Time:" -e "Revocation Reason:" -e "This Update:" -e "Next Update:" -e "OCSP Response Status:"');
$output = preg_replace("/[[:blank:]]+/"," ", $output);
$ocsp_status_lines = explode("\n", $output);
$ocsp_status_lines = array_map('trim', $ocsp_status_lines);
foreach($ocsp_status_lines as $line) {
if(endsWith($line, ":") == false) {
list($k, $v) = explode(":", $line, 2);
if (trim($k)) {
$lines[trim($k)] = trim($v);
}
}
}
if ($lines[$tmp_dir . $random_blurp . ".cert_client.pem"] == "good") {
$result["status"] = "good";
} else if ($lines[$tmp_dir . $random_blurp . ".cert_client.pem"] == "revoked") {
$result["status"] = "revoked";
} else {
$result["error"] = $filter_output;
$result["status"] = "unknown";
}
if (isset($lines["This Update"])) {
$result["this_update"] = $lines["This Update"];
}
if (isset($lines["Next Update"])) {
$result["next_update"] = $lines["Next Update"];
}
if (isset($lines["Reason"])) {
$result["reason"] = $lines["Reason"];
}
if (isset($lines["Revocation Time"])) {
$result["revocation_time"] = $lines["Revocation Time"];
}
$result["ocsp_uri"] = $ocsp_uri;
//remove temp files after use
unlink($tmp_dir.$random_blurp.'.cert_client.pem');
unlink($tmp_dir.$random_blurp.'.cert_issuer.pem');
return $result;
}
?>
|