diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CHANGELOG.md | 7 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | css/ssl.css | 6 | ||||
-rw-r--r-- | functions/connection.php | 979 | ||||
-rw-r--r-- | functions/json.php | 61 | ||||
-rw-r--r-- | functions/ocsp.php | 69 | ||||
-rw-r--r-- | functions/parse_certificate.php | 1295 | ||||
-rw-r--r-- | functions/textual.php | 16 | ||||
-rw-r--r-- | functions/variables.php | 2 | ||||
-rw-r--r-- | inc/footer.php | 75 | ||||
-rw-r--r-- | inc/form.php | 56 | ||||
-rw-r--r-- | index.php | 426 | ||||
-rw-r--r-- | json.php | 56 |
14 files changed, 1365 insertions, 1685 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..484ab7e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +results/* diff --git a/CHANGELOG.md b/CHANGELOG.md index b86ce19..20bc282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,14 @@ ## 2.1 -- Add json API endpoint (see README) -- Rewrote internals to use same endpoint +- Add json API endpoint (see README). +- Rewrote internals to use same endpoint. +- Add warnings for connection and certificate issues. - Don't follow redirects during HTTP header gathering. ## 2.0 -- Add TLS_FALLBACK_SCSV check +- Add TLS_FALLBACK_SCSV check. - Lower some timeouts from 5 to 2. ## 1.9 @@ -30,6 +30,7 @@ Simple PHP script which decodes an SSL connection and/or certificate and display - Issuer validation - Date validation - JSON API +- Warnings for bad connection settings or certificate options ### Requirements diff --git a/css/ssl.css b/css/ssl.css index afb8586..f8d7bce 100644 --- a/css/ssl.css +++ b/css/ssl.css @@ -49,6 +49,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. border-right-style: solid; border-right-width: 1px; border-right-color: #ddd; + border-top-style: solid; + border-top-width: 1px; + border-top-color: #ddd; + border-bottom-style: solid; + border-bottom-width: 1px; + border-bottom-color: #ddd; height: 100%; overflow-y: auto; z-index: 1000; diff --git a/functions/connection.php b/functions/connection.php index 3cd4fc4..a1e718e 100644 --- a/functions/connection.php +++ b/functions/connection.php @@ -49,591 +49,367 @@ function server_http_headers($host, $port){ } function ssl_conn_ciphersuites($host, $port, $ciphersuites){ - $old_error_reporting = error_reporting(); - error_reporting($old_error_reporting ^ E_WARNING); - $results = array(); - foreach ($ciphersuites as $value) { - $results[$value] = false; - $stream = stream_context_create (array("ssl" => - array("verify_peer" => false, - "verify_peer_name" => false, - "allow_self_signed" => true, - 'ciphers' => $value, - "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); - if ( $read_stream === false ) { - $results[$value] = false; - } else { - $results[$value] = true; - } - } - error_reporting($old_error_reporting); - return $results; - } - - function ssl_conn_protocols($host, $port){ - $old_error_reporting = error_reporting(); - error_reporting($old_error_reporting ^ E_WARNING); - $results = array('sslv3' => false, - 'tlsv1.0' => false, - 'tlsv1.1' => false, - 'tlsv1.2' => false); - - $stream_sslv3 = stream_context_create (array("ssl" => - array("verify_peer" => false, - "capture_session_meta" => true, - "verify_peer_name" => false, - "allow_self_signed" => true, - 'crypto_method' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT, - "sni_enabled" => true))); - $read_stream_sslv3 = stream_socket_client("sslv3://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_sslv3); - if ( $read_stream_sslv3 === false ) { - $results['sslv3'] = false; - } else { - $results['sslv3'] = true; - } - - $stream_tlsv10 = stream_context_create (array("ssl" => - array("verify_peer" => false, - "capture_session_meta" => true, - "verify_peer_name" => false, - "allow_self_signed" => true, - 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_0_CLIENT, - "sni_enabled" => true))); - $read_stream_tlsv10 = stream_socket_client("tlsv1.0://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv10); - if ( $read_stream_tlsv10 === false ) { - $results['tlsv1.0'] = false; - } else { - $results['tlsv1.0'] = true; - } - - $stream_tlsv11 = stream_context_create (array("ssl" => - array("verify_peer" => false, - "capture_session_meta" => true, - "verify_peer_name" => false, - "allow_self_signed" => true, - 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_1_CLIENT, - "sni_enabled" => true))); - $read_stream_tlsv11 = stream_socket_client("tlsv1.1://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv11); - if ( $read_stream_tlsv11 === false ) { - $results['tlsv1.1'] = false; - } else { - $results['tlsv1.1'] = true; - } - - $stream_tlsv12 = stream_context_create (array("ssl" => - array("verify_peer" => false, - "capture_session_meta" => true, - "verify_peer_name" => false, - "allow_self_signed" => true, - 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_2_CLIENT, - "sni_enabled" => true))); - $read_stream_tlsv12 = stream_socket_client("tlsv1.2://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv12); - if ( $read_stream_tlsv12 === false ) { - $results['tlsv1.2'] = false; - } else { - $results['tlsv1.2'] = true; - } - error_reporting($old_error_reporting); - return $results; - } + $old_error_reporting = error_reporting(); + error_reporting($old_error_reporting ^ E_WARNING); + $results = array(); + foreach ($ciphersuites as $value) { + $results[$value] = false; + $stream = stream_context_create (array("ssl" => + array("verify_peer" => false, + "verify_peer_name" => false, + "allow_self_signed" => true, + 'ciphers' => $value, + "sni_enabled" => true))); + $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); + if ( $read_stream === false ) { + $results[$value] = false; + } else { + $results[$value] = true; + } + } + error_reporting($old_error_reporting); + return $results; +} +function ssl_conn_protocols($host, $port){ + $old_error_reporting = error_reporting(); + error_reporting($old_error_reporting ^ E_WARNING); + $results = array('sslv3' => false, + 'tlsv1.0' => false, + 'tlsv1.1' => false, + 'tlsv1.2' => false); -function ssl_conn_metadata($host, $port, $chain=null) { - global $random_blurp; - global $current_folder; - $stream = stream_context_create (array("ssl" => + $stream_sslv3 = stream_context_create (array("ssl" => array("verify_peer" => false, "capture_session_meta" => true, "verify_peer_name" => false, "allow_self_signed" => true, + 'crypto_method' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT, "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); - if ( $read_stream === false ) { - return false; + $read_stream_sslv3 = stream_socket_client("sslv3://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_sslv3); + if ( $read_stream_sslv3 === false ) { + $results['sslv3'] = false; } else { - $context = stream_context_get_params($read_stream); - $context_meta = stream_context_get_options($read_stream)['ssl']['session_meta']; - $cert_data = openssl_x509_parse($context["options"]["ssl"]["peer_certificate"])[0]; - - if ($context_meta) { - ?> - <section id="conndata"> - <h3>Connection Data</h3> - <table class="table table-striped table-bordered"> - <tbody> - <tr> - <td colspan="2"><strong>Connection Data</strong></td> - </tr> - <?php - if ( $chain ) { - ?> - <tr> - <td>Chain sent by Server (in server order)</td> - <td style="font-family: monospace;"> - <?php - $chain_length = count($chain); - $certificate_chain = array(); - if ($chain_length <= 10) { - for ($i = 0; $i < $chain_length; $i++) { - if (openssl_x509_parse($chain[$i])['issuer']['CN'] && openssl_x509_parse($chain[$i])['subject']['CN']) { - echo "Name...........: <i>"; - echo htmlspecialchars(openssl_x509_parse($chain[$i])['subject']['CN']); - echo " </i><br>Issued by......:<i> "; - echo htmlspecialchars(openssl_x509_parse($chain[$i])['issuer']['CN']); - echo "</i><br>"; - - $export_pem = ""; - openssl_x509_export($chain[$i], $export_pem); - array_push($certificate_chain, $export_pem); - - if (openssl_x509_parse($chain[$i])['issuer']['CN'] == openssl_x509_parse($chain[$i + 1])['subject']['CN']){ - continue; - } else { - if ($i != $chain_length - 1) { - echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>Error: Issuer does not match the next certificate CN. Chain order is probaby wrong.</span><br><br>"; - } - } - } - } - echo "<br>"; - } else { - echo "<span class='text-danger'>Error: Certificate chain to large.</span><br>"; - } - - file_put_contents('/tmp/verify_cert.' . $random_blurp . '.pem', implode("\n", array_reverse($certificate_chain)).PHP_EOL , FILE_APPEND); - - $verify_output = 0; - $verify_exit_code = 0; - $verify_exec = exec(escapeshellcmd('openssl verify -verbose -purpose any -CAfile ' . getcwd() . '/cacert.pem /tmp/verify_cert.' . $random_blurp . '.pem') . "| grep -v OK", $verify_output, $verify_exit_code); - - if ($verify_exit_code != 1) { - echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>Error: Validating certificate chain failed:</span><br>"; - echo "<pre>"; - echo str_replace('/tmp/verify_cert.' . $random_blurp . '.pem: ', '', implode("\n", $verify_output)); - echo "</pre>"; - } else { - echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>Sucessfully validated certificate chain.</span><br>"; - } + $results['sslv3'] = true; + } - unlink('/tmp/verify_cert.' . $random_blurp . '.pem'); + $stream_tlsv10 = stream_context_create (array("ssl" => + array("verify_peer" => false, + "capture_session_meta" => true, + "verify_peer_name" => false, + "allow_self_signed" => true, + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_0_CLIENT, + "sni_enabled" => true))); + $read_stream_tlsv10 = stream_socket_client("tlsv1.0://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv10); + if ( $read_stream_tlsv10 === false ) { + $results['tlsv1.0'] = false; + } else { + $results['tlsv1.0'] = true; + } - ?> - </td> - </tr> + $stream_tlsv11 = stream_context_create (array("ssl" => + array("verify_peer" => false, + "capture_session_meta" => true, + "verify_peer_name" => false, + "allow_self_signed" => true, + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_1_CLIENT, + "sni_enabled" => true))); + $read_stream_tlsv11 = stream_socket_client("tlsv1.1://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv11); + if ( $read_stream_tlsv11 === false ) { + $results['tlsv1.1'] = false; + } else { + $results['tlsv1.1'] = true; + } - <?php - } - if ( fixed_gethostbyname($host) ) { - ?> - <tr> - <td>IP / Hostname / Port</td> - <td> - <?php - echo htmlspecialchars(fixed_gethostbyname($host)); - echo " - "; - echo htmlspecialchars(gethostbyaddr(fixed_gethostbyname($host))); - echo " - "; - echo htmlspecialchars($port); - ?> - </td> - </tr> - <?php - } - ?> - <tr> - <td>Protocol</td> - <td> - <?php - $protocols = ssl_conn_protocols($host, $port); - foreach (array_reverse($protocols) as $key => $value) { - if ( $value == true ) { - if ( $key == "tlsv1.2") { - echo '<p><span class="text-success glyphicon glyphicon-ok"></span> - <span class="text-success">TLSv1.2 (Supported)</span></p>'; - } else if ( $key == "tlsv1.1") { - echo '<p><span class="glyphicon glyphicon-ok"></span> - TLSv1.1 (Supported)</p>'; - } else if ( $key == "tlsv1.0") { - echo '<p><span class="glyphicon glyphicon-ok"></span> - TLSv1.0 (Supported)</p>'; - } else if ( $key == "sslv3") { - echo '<p><span class="text-danger glyphicon glyphicon-ok"></span> - <span class="text-danger">SSLv3 (Supported)</span></p>'; - } else { - echo '<p><span class="glyphicon glyphicon-ok"></span> - <span>'.$key.' (Supported)</span></p>'; - } - } else { - if ( $key == "tlsv1.2") { - echo '<p><span class="text-danger glyphicon glyphicon-remove"></span> - <span class="text-danger">TLSv1.2 (Not supported)</span></p>'; - } else if ( $key == "tlsv1.1") { - echo '<p><span class="glyphicon glyphicon-remove"></span> - TLSv1.1 (Not supported)</p>'; - } else if ( $key == "tlsv1.0") { - echo '<p><span class="glyphicon glyphicon-remove"></span> - TLSv1.0 (Not supported)</p>'; - } else if ( $key == "sslv3") { - echo '<p><span class="text-success glyphicon glyphicon-remove"></span> - <span class="text-success">SSLv3 (Not supported)</span></p>'; - } else { - echo '<p><span class="glyphicon glyphicon-remove"></span> - <span>'.$key.'(Not supported)</span></p>'; - } - } - } - ?> + $stream_tlsv12 = stream_context_create (array("ssl" => + array("verify_peer" => false, + "capture_session_meta" => true, + "verify_peer_name" => false, + "allow_self_signed" => true, + 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_2_CLIENT, + "sni_enabled" => true))); + $read_stream_tlsv12 = stream_socket_client("tlsv1.2://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv12); + if ( $read_stream_tlsv12 === false ) { + $results['tlsv1.2'] = false; + } else { + $results['tlsv1.2'] = true; + } + error_reporting($old_error_reporting); + return $results; +} - </td> - </tr> - <?php - if ($_GET['ciphersuites'] == 1) { - ?> - <tr> - <td>Ciphersuites supported by server</td> - <td> - <?php - $ciphersuites_to_test = array('ECDHE-RSA-AES256-GCM-SHA384', - 'ECDHE-ECDSA-AES256-GCM-SHA384', - 'ECDHE-RSA-AES256-SHA384', - 'ECDHE-ECDSA-AES256-SHA384', - 'ECDHE-RSA-AES256-SHA', - 'ECDHE-ECDSA-AES256-SHA', - 'SRP-DSS-AES-256-CBC-SHA', - 'SRP-RSA-AES-256-CBC-SHA', - 'SRP-AES-256-CBC-SHA', - 'DH-DSS-AES256-GCM-SHA384', - 'DHE-DSS-AES256-GCM-SHA384', - 'DH-RSA-AES256-GCM-SHA384', - 'DHE-RSA-AES256-GCM-SHA384', - 'DHE-RSA-AES256-SHA256', - 'DHE-DSS-AES256-SHA256', - 'DH-RSA-AES256-SHA256', - 'DH-DSS-AES256-SHA256', - 'DHE-RSA-AES256-SHA', - 'DHE-DSS-AES256-SHA', - 'DH-RSA-AES256-SHA', - 'DH-DSS-AES256-SHA', - 'DHE-RSA-CAMELLIA256-SHA', - 'DHE-DSS-CAMELLIA256-SHA', - 'DH-RSA-CAMELLIA256-SHA', - 'DH-DSS-CAMELLIA256-SHA', - 'ECDH-RSA-AES256-GCM-SHA384', - 'ECDH-ECDSA-AES256-GCM-SHA384', - 'ECDH-RSA-AES256-SHA384', - 'ECDH-ECDSA-AES256-SHA384', - 'ECDH-RSA-AES256-SHA', - 'ECDH-ECDSA-AES256-SHA', - 'AES256-GCM-SHA384', - 'AES256-SHA256', - 'AES256-SHA', - 'CAMELLIA256-SHA', - 'PSK-AES256-CBC-SHA', - 'ECDHE-RSA-AES128-GCM-SHA256', - 'ECDHE-ECDSA-AES128-GCM-SHA256', - 'ECDHE-RSA-AES128-SHA256', - 'ECDHE-ECDSA-AES128-SHA256', - 'ECDHE-RSA-AES128-SHA', - 'ECDHE-ECDSA-AES128-SHA', - 'SRP-DSS-AES-128-CBC-SHA', - 'SRP-RSA-AES-128-CBC-SHA', - 'SRP-AES-128-CBC-SHA', - 'DH-DSS-AES128-GCM-SHA256', - 'DHE-DSS-AES128-GCM-SHA256', - 'DH-RSA-AES128-GCM-SHA256', - 'DHE-RSA-AES128-GCM-SHA256', - 'DHE-RSA-AES128-SHA256', - 'DHE-DSS-AES128-SHA256', - 'DH-RSA-AES128-SHA256', - 'DH-DSS-AES128-SHA256', - 'DHE-RSA-AES128-SHA', - 'DHE-DSS-AES128-SHA', - 'DH-RSA-AES128-SHA', - 'DH-DSS-AES128-SHA', - 'DHE-RSA-SEED-SHA', - 'DHE-DSS-SEED-SHA', - 'DH-RSA-SEED-SHA', - 'DH-DSS-SEED-SHA', - 'DHE-RSA-CAMELLIA128-SHA', - 'DHE-DSS-CAMELLIA128-SHA', - 'DH-RSA-CAMELLIA128-SHA', - 'DH-DSS-CAMELLIA128-SHA', - 'ECDH-RSA-AES128-GCM-SHA256', - 'ECDH-ECDSA-AES128-GCM-SHA256', - 'ECDH-RSA-AES128-SHA256', - 'ECDH-ECDSA-AES128-SHA256', - 'ECDH-RSA-AES128-SHA', - 'ECDH-ECDSA-AES128-SHA', - 'AES128-GCM-SHA256', - 'AES128-SHA256', - 'AES128-SHA', - 'SEED-SHA', - 'CAMELLIA128-SHA', - 'IDEA-CBC-SHA', - 'PSK-AES128-CBC-SHA', - 'ECDHE-RSA-RC4-SHA', - 'ECDHE-ECDSA-RC4-SHA', - 'ECDH-RSA-RC4-SHA', - 'ECDH-ECDSA-RC4-SHA', - 'RC4-SHA', - 'RC4-MD5', - 'PSK-RC4-SHA', - 'ECDHE-RSA-DES-CBC3-SHA', - 'ECDHE-ECDSA-DES-CBC3-SHA', - 'SRP-DSS-3DES-EDE-CBC-SHA', - 'SRP-RSA-3DES-EDE-CBC-SHA', - 'SRP-3DES-EDE-CBC-SHA', - 'EDH-RSA-DES-CBC3-SHA', - 'EDH-DSS-DES-CBC3-SHA', - 'DH-RSA-DES-CBC3-SHA', - 'DH-DSS-DES-CBC3-SHA', - 'ECDH-RSA-DES-CBC3-SHA', - 'ECDH-ECDSA-DES-CBC3-SHA', - 'DES-CBC3-SHA', - 'PSK-3DES-EDE-CBC-SHA', - 'EDH-RSA-DES-CBC-SHA', - 'EDH-DSS-DES-CBC-SHA', - 'DH-RSA-DES-CBC-SHA', - 'DH-DSS-DES-CBC-SHA', - 'DES-CBC-SHA', - 'EXP-EDH-RSA-DES-CBC-SHA', - 'EXP-EDH-DSS-DES-CBC-SHA', - 'EXP-DH-RSA-DES-CBC-SHA', - 'EXP-DH-DSS-DES-CBC-SHA', - 'EXP-DES-CBC-SHA', - 'EXP-RC2-CBC-MD5', - 'EXP-RC4-MD5', - 'ECDHE-RSA-NULL-SHA', - 'ECDHE-ECDSA-NULL-SHA', - 'AECDH-NULL-SHA', - 'ECDH-RSA-NULL-SHA', - 'ECDH-ECDSA-NULL-SHA', - 'NULL-SHA256', - 'NULL-SHA', - 'NULL-MD5'); +function ssl_conn_metadata($data) { + global $random_blurp; + global $current_folder; + $chain_length = count($data["chain"]); + echo "<section id='conndata'>"; + if (is_array($data["warning"]) && count($data["warning"]) >= 1) { + $data["warning"] = array_unique($data["warning"]); + if (count($data["warning"]) == 1) { + echo "<h3>" . count($data["warning"]) . " warning!</h3>"; + } else { + echo "<h3>" . count($data["warning"]) . " warnings!</h3>"; + } + foreach ($data["warning"] as $key => $value) { + echo "<div class='alert alert-danger' role='alert'>"; + echo htmlspecialchars($value); + echo "</div>"; + } + } + echo "<table class='table table-striped table-bordered'>"; + echo "<tbody>"; + echo "<tr>"; + echo "<td colspan='2'><strong>Connection Data</strong></td>"; + echo "</tr>"; + echo "<tr>"; + // chain + echo "<td>Chain sent by Server <br>(in server order)</td>"; + echo "<td style='font-family: monospace;'>"; + foreach ($data["chain"] as $key => $value) { + if (!empty($value['name'])) { + echo "Name...........: <i>"; + echo htmlspecialchars(htmlspecialchars($value['name'])); + echo " </i><br>Issued by......:<i> "; + echo htmlspecialchars(htmlspecialchars($value['issuer'])); + echo "</i><br>"; + } + if (isset($value["error"])) { + echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>Error: Issuer does not match the next certificate CN. Chain order is probaby wrong.</span><br><br>"; + } + } + echo "<br>"; + if ($data["validation"]["status"] == "failed") { + echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>Validating certificate chain failed:</span><br>"; + echo "<pre>"; + echo htmlspecialchars($data["validation"]["error"]); + echo "</pre>"; + } else { + echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>Sucessfully validated certificate chain.</span><br>"; + } + echo "</td>"; + echo "</tr>"; + // ip hostname port + if ( $data["hostname"] ) { + echo "<tr>"; + echo "<td>IP / Hostname / Port</td>"; + echo "<td>"; + echo htmlspecialchars($data["ip"]); + echo " - "; + echo htmlspecialchars($data["hostname"]); + echo " - "; + echo htmlspecialchars($data["port"]); + echo "</td>"; + echo "</tr>"; + } + // protocols + echo "<tr>"; + echo "<td>Protocols</td>"; + echo "<td>"; + $protocols = $data["protocols"]; + foreach ($protocols as $key => $value) { + if ( $value == true ) { + if ( $key == "tlsv1.2") { + echo '<p><span class="text-success glyphicon glyphicon-ok"></span> - <span class="text-success">TLSv1.2 (Supported)</span></p>'; + } else if ( $key == "tlsv1.1") { + echo '<p><span class="glyphicon glyphicon-ok"></span> - TLSv1.1 (Supported)</p>'; + } else if ( $key == "tlsv1.0") { + echo '<p><span class="glyphicon glyphicon-ok"></span> - TLSv1.0 (Supported)</p>'; + } else if ( $key == "sslv3") { + echo '<p><span class="text-danger glyphicon glyphicon-ok"></span> - <span class="text-danger">SSLv3 (Supported)</span></p>'; + } else { + echo '<p><span class="glyphicon glyphicon-ok"></span> - <span>'.$key.' (Supported)</span></p>'; + } + } else { + if ( $key == "tlsv1.2") { + echo '<p><span class="text-danger glyphicon glyphicon-remove"></span> - <span class="text-danger">TLSv1.2 (Not supported)</span></p>'; + } else if ( $key == "tlsv1.1") { + echo '<p><span class="glyphicon glyphicon-remove"></span> - TLSv1.1 (Not supported)</p>'; + } else if ( $key == "tlsv1.0") { + echo '<p><span class="glyphicon glyphicon-remove"></span> - TLSv1.0 (Not supported)</p>'; + } else if ( $key == "sslv3") { + echo '<p><span class="text-success glyphicon glyphicon-remove"></span> - <span class="text-success">SSLv3 (Not supported)</span></p>'; + } else { + echo '<p><span class="glyphicon glyphicon-remove"></span> - <span>'.$key.'(Not supported)</span></p>'; + } + } + } + echo "</td>"; + echo "</tr>"; + //ciphersuites + if ($_GET['ciphersuites'] == 1) { + echo "<tr>"; + echo "<td>Ciphersuites supported by server</td>"; + echo "<td>"; + $bad_ciphersuites = array('ECDHE-RSA-DES-CBC3-SHA', + 'ECDHE-ECDSA-DES-CBC3-SHA', + 'EDH-RSA-DES-CBC3-SHA', + 'EDH-DSS-DES-CBC3-SHA', + 'DH-RSA-DES-CBC3-SHA', + 'DH-DSS-DES-CBC3-SHA', + 'ECDH-RSA-DES-CBC3-SHA', + 'ECDH-ECDSA-DES-CBC3-SHA', + 'DES-CBC3-SHA', + 'EDH-RSA-DES-CBC-SHA', + 'EDH-DSS-DES-CBC-SHA', + 'DH-RSA-DES-CBC-SHA', + 'DH-DSS-DES-CBC-SHA', + 'DES-CBC-SHA', + 'EXP-EDH-RSA-DES-CBC-SHA', + 'EXP-EDH-DSS-DES-CBC-SHA', + 'EXP-DH-RSA-DES-CBC-SHA', + 'EXP-DH-DSS-DES-CBC-SHA', + 'EXP-DES-CBC-SHA', + 'EXP-EDH-RSA-DES-CBC-SHA', + 'EXP-EDH-DSS-DES-CBC-SHA', + 'EXP-DH-RSA-DES-CBC-SHA', + 'EXP-DH-DSS-DES-CBC-SHA', + 'EXP-DES-CBC-SHA', + 'EXP-RC2-CBC-MD5', + 'EXP-RC4-MD5', + 'RC4-MD5', + 'EXP-RC2-CBC-MD5', + 'EXP-RC4-MD5', + 'ECDHE-RSA-RC4-SHA', + 'ECDHE-ECDSA-RC4-SHA', + 'ECDH-RSA-RC4-SHA', + 'ECDH-ECDSA-RC4-SHA', + 'RC4-SHA', + 'RC4-MD5', + 'PSK-RC4-SHA', + 'EXP-RC4-MD5', + 'ECDHE-RSA-NULL-SHA', + 'ECDHE-ECDSA-NULL-SHA', + 'AECDH-NULL-SHA', + 'RC4-SHA', + 'RC4-MD5', + 'ECDH-RSA-NULL-SHA', + 'ECDH-ECDSA-NULL-SHA', + 'NULL-SHA256', + 'NULL-SHA', + 'NULL-MD5'); + foreach ($data["supported_ciphersuites"] as $key => $value) { + if (in_array($value, $bad_ciphersuites)) { + $bad_ciphersuite = 1; + echo "<span class='text-danger glyphicon glyphicon-remove'></span>"; + echo "<span class='text-danger'> "; + echo htmlspecialchars($value); + echo "</span>"; + } else { + echo "<span class='glyphicon glyphicon-minus'></span> "; + echo htmlspecialchars($value); + } + echo "<br>"; + } + if ($bad_ciphersuite) { + echo "<p><br>Ciphersuites containing <a href='https://en.wikipedia.org/wiki/Null_cipher'>NULL</a>,"; + echo " <a href='https://en.wikipedia.org/wiki/Export_of_cryptography_from_the_United_States'>EXP(ort)</a>,"; + echo " <a href='https://en.wikipedia.org/wiki/Weak_key'>DES"; + echo " and RC4</a> are marked RED because they are suboptimal.</p>"; + } + echo "</td>"; + echo "</tr>"; + } else { + echo "<tr>"; + echo "<td>Ciphersuite Used</td>"; + echo "<td>"; + echo htmlspecialchars($data['used_ciphersuite']['name']); + echo " (".htmlspecialchars($data['used_ciphersuite']['bits'])." bits)"; + echo "</td>"; + echo "</tr>"; + } + //tls fallback scsv + echo "<tr>"; + echo "<td>"; + echo "<a href='http://googleonlinesecurity.blogspot.nl/2014/10/this-poodle-bites-exploiting-ssl-30.html'>TLS_FALLBACK_SCSV</a>"; + echo "</td>"; + echo "<td>"; + + if ($data["tls_fallback_scsv"] == "supported") { + echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>TLS_FALLBACK_SCSV supported.</span>"; + } elseif ($data["tls_fallback_scsv"] == "unsupported") { + echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>TLS_FALLBACK_SCSV not supported.</span>"; + } else { + echo "Only 1 protocol enabled, fallback not possible, TLS_FALLBACK_SCSV not required."; + } + echo "</td>"; + echo "</tr>"; + + // headers + echo "<tr>"; + echo "<td>"; + echo "<a href='https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html'>Strict Transport Security</a>"; + echo "</td>"; + echo "<td>"; + // hsts + if ( $data["strict_transport_security"] == "not set" ) { + echo '<span class="text-danger glyphicon glyphicon-remove"></span> - <span class="text-danger">Not Set</span>'; + } else { + echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>"; + echo htmlspecialchars($data["strict_transport_security"]); + echo "</span>"; + } + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + echo "<td>"; + echo "<a href='https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html'>HTTP Public Key Pinning Extension (HPKP)</a>"; + echo "</td>"; + echo "<td>"; + //hpkp + if ( $data["public_key_pins"] == "not set" ) { + echo '<span>Not Set</span>'; + } else { + echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>"; + echo htmlspecialchars($data["public_key_pins"]); + } + if ( $data["public_key-pins_report_only"] ) { + echo "<b>Report Only</b>: "; + echo htmlspecialchars($data["public_key_pins_report_only"]); + } - $bad_ciphersuites = array('ECDHE-RSA-DES-CBC3-SHA', - 'ECDHE-ECDSA-DES-CBC3-SHA', - 'EDH-RSA-DES-CBC3-SHA', - 'EDH-DSS-DES-CBC3-SHA', - 'DH-RSA-DES-CBC3-SHA', - 'DH-DSS-DES-CBC3-SHA', - 'ECDH-RSA-DES-CBC3-SHA', - 'ECDH-ECDSA-DES-CBC3-SHA', - 'DES-CBC3-SHA', - 'EDH-RSA-DES-CBC-SHA', - 'EDH-DSS-DES-CBC-SHA', - 'DH-RSA-DES-CBC-SHA', - 'DH-DSS-DES-CBC-SHA', - 'DES-CBC-SHA', - 'EXP-EDH-RSA-DES-CBC-SHA', - 'EXP-EDH-DSS-DES-CBC-SHA', - 'EXP-DH-RSA-DES-CBC-SHA', - 'EXP-DH-DSS-DES-CBC-SHA', - 'EXP-DES-CBC-SHA', - 'EXP-EDH-RSA-DES-CBC-SHA', - 'EXP-EDH-DSS-DES-CBC-SHA', - 'EXP-DH-RSA-DES-CBC-SHA', - 'EXP-DH-DSS-DES-CBC-SHA', - 'EXP-DES-CBC-SHA', - 'EXP-RC2-CBC-MD5', - 'EXP-RC4-MD5', - 'RC4-MD5', - 'EXP-RC2-CBC-MD5', - 'EXP-RC4-MD5', - 'ECDHE-RSA-RC4-SHA', - 'ECDHE-ECDSA-RC4-SHA', - 'ECDH-RSA-RC4-SHA', - 'ECDH-ECDSA-RC4-SHA', - 'RC4-SHA', - 'RC4-MD5', - 'PSK-RC4-SHA', - 'EXP-RC4-MD5', - 'ECDHE-RSA-NULL-SHA', - 'ECDHE-ECDSA-NULL-SHA', - 'AECDH-NULL-SHA', - 'RC4-SHA', - 'RC4-MD5', - 'ECDH-RSA-NULL-SHA', - 'ECDH-ECDSA-NULL-SHA', - 'NULL-SHA256', - 'NULL-SHA', - 'NULL-MD5'); - $supported_ciphersuites = ssl_conn_ciphersuites($host, $port, $ciphersuites_to_test); - - foreach ($supported_ciphersuites as $key => $value) { - if($value == true){ - if (in_array($key, $bad_ciphersuites)) { - $bad_ciphersuite = 1; - echo ""; - echo "<span class='text-danger glyphicon glyphicon-remove'></span> "; - } else { - echo "<span class='glyphicon glyphicon-minus'></span> "; - } - echo htmlspecialchars($key); - echo "<br>"; - } else { - echo "<!-- "; - echo "<span class='glyphicon glyphicon-remove'></span> - "; - echo htmlspecialchars($key); - echo " <br -->"; - } - } - if ($bad_ciphersuite) { - ?> - <p><br>Ciphersuites containing <a href="https://en.wikipedia.org/wiki/Null_cipher">NULL</a>, <a href="https://en.wikipedia.org/wiki/Export_of_cryptography_from_the_United_States">EXP(ort)</a>, <a href="https://en.wikipedia.org/wiki/Weak_key">DES and RC4</a> are marked RED because they are suboptimal.</p> - <?php - } - - ?> - </td> - </tr> - <?php - } else { - ?> - <tr> - <td>Ciphersuite</td> - <td> - <?php - echo htmlspecialchars($context_meta['cipher_name']); - echo " (".htmlspecialchars($context_meta['cipher_bits'])." bits)"; - ?> - </td> - </tr> - <?php - } - ?> - <tr> - <td> - <a href="http://googleonlinesecurity.blogspot.nl/2014/10/this-poodle-bites-exploiting-ssl-30.html">TLS_FALLBACK_SCSV</a> - </td> - <td> - <?php - $fallback = tls_fallback_scsv($host, $port); - // echo "<pre>"; - // var_dump($fallback); - // echo "</pre>"; - if ($fallback['protocol_count'] == 1) { - echo "Only 1 protocol enabled, fallback not possible, TLS_FALLBACK_SCSV not required."; - } else { - if ($fallback['tls_fallback_scsv_support'] == 1) { - echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>TLS_FALLBACK_SCSV supported.</span>"; - } else { - echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>TLS_FALLBACK_SCSV not supported.</span>"; - } - } - ?> - </td> - </tr> - <?php - $headers = server_http_headers($host, $port); - ?> - <tr> - <td><a href="https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html">Strict Transport Security</a></td> - <td> - <?php - if ( $headers["strict-transport-security"] ) { - echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>"; - if ( is_array($headers["strict-transport-security"])) { - echo htmlspecialchars(substr($headers["strict-transport-security"][0], 0, 50)); - echo "<br > <i>HSTS header was found multiple times. Only showing the first one.</i>"; - } else { - echo htmlspecialchars(substr($headers["strict-transport-security"], 0, 50)); - } - echo "</span>"; - } else { - echo '<span class="text-danger glyphicon glyphicon-remove"></span> - <span class="text-danger">Not Set</span>'; - } - ?> - </td> - </tr> - <tr> - <td><a href="https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html">HTTP Public Key Pinning Extension (HPKP)</a></td> - <td> - <?php - if ( $headers["public-key-pins"] ) { - echo "<span class='text-success glyphicon glyphicon-ok'></span> - <span class='text-success'>"; - if ( is_array($headers["public-key-pins"])) { - echo htmlspecialchars(substr($headers["public-key-pins"][0], 0, 255)); - echo "<br > <i>HPKP header was found multiple times. Only showing the first one.</i>"; - echo "</span>"; - } else { - echo htmlspecialchars(substr($headers["public-key-pins"], 0, 255)); - } - } else { - echo '<span>Not Set</span>'; - } - ?> - <?php - if ( $headers["public-key-pins-report-only"] ) { - echo "<b>Report Only</b>: "; - if ( is_array($headers["public-key-pins-report-only"])) { - echo htmlspecialchars(substr($headers["public-key-pins-report-only"][0], 0, 255)); - echo "<br > <i>HPKP Report Only header was found multiple times. Only showing the first one.</i>"; - } else { - echo htmlspecialchars(substr($headers["public-key-pins-report-only"], 0, 255)); - } - } - ?> - </td> - </tr> - <tr> - <td>OCSP Stapling</td> - <td> - <?php - $stapling = ocsp_stapling($host,$port); - if($stapling["working"] == 1) { - echo "<table class='table'>"; - foreach ($stapling as $key => $value) { - if ($key != "working") { - echo "<tr><td>" . $key . "</td><td>" . $value . "</td></tr>"; - } - } - echo "</table>"; - } else { - echo "No response received."; - } - ?> - </td> - </tr> - <tr> - <td>This Server' OpenSSL Version</td> - <td> - <?php - echo htmlspecialchars(shell_exec("openssl version")); - ?> - </td> - </tr> - <tr> - <td>This Server' Date (RFC 2822)</td> - <td> - <?php - echo htmlspecialchars(shell_exec("date --rfc-2822")); - ?> - </td> - </tr> - </tbody> - </table> - </section> - <?php + echo "</td>"; + echo "</tr>"; + // ocsp stapling + echo "<tr>"; + echo "<td>OCSP Stapling</td>"; + echo "<td>"; + if (isset($data["ocsp_stapling"]["working"])) { + if($data["ocsp_stapling"]["working"] == 1) { + echo "<table class='table'>"; + foreach ($data["ocsp_stapling"] as $key => $value) { + if ($key != "working") { + echo "<tr><td>" . htmlspecialchars($key) . "</td><td>" . htmlspecialchars($value) . "</td></tr>"; + } + } + echo "</table>"; } else { - return false; + echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>No OCSP stapling response received.</span>"; } + } else { + echo "<span class='text-danger glyphicon glyphicon-remove'></span> - <span class='text-danger'>No OCSP stapling response received.</span>"; } + echo "</td>"; + // openssl version + echo "</tr>"; + echo "<tr>"; + echo "<td>This Server's OpenSSL Version</td>"; + echo "<td>"; + echo htmlspecialchars(shell_exec("openssl version")); + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + //date + echo "<td>This Server's Date <br>(RFC 2822)</td>"; + echo "<td>"; + echo htmlspecialchars(shell_exec("date --rfc-2822")); + echo "</td>"; + echo "</tr>"; + echo "</tbody>"; + echo "</table>"; } - - - - - - - - - - - - - - - - - - - function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { $result = array(); global $random_blurp; @@ -641,10 +417,10 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { $context = stream_context_get_params($read_stream); $context_meta = stream_context_get_options($read_stream)['ssl']['session_meta']; $cert_data = openssl_x509_parse($context["options"]["ssl"]["peer_certificate"])[0]; + $result["checked_hostname"] = $host; //chain if (isset($context_meta)) { if (isset($chain_data)) { - $chain_length = count($chain_data); $certificate_chain = array(); if ($chain_length <= 10) { @@ -660,6 +436,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { } else { if ($i != $chain_length - 1) { $result["chain"][$i]["error"] = "Issuer does not match the next certificate CN. Chain order is probaby wrong."; + $result["warning"][] = "Issuer does not match the next certificate CN. Chain order is probaby wrong."; } } } @@ -672,10 +449,11 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { $verify_exec = exec(escapeshellcmd('openssl verify -verbose -purpose any -CAfile ' . getcwd() . '/cacert.pem /tmp/verify_cert.' . $random_blurp . '.pem') . "| grep -v OK", $verify_output, $verify_exit_code); if ($verify_exit_code != 1) { - $result["chain"]["validation"]["status"] = "failed"; - $result["chain"]["validation"]["error"] = "Error: Validating certificate chain failed: " . str_replace('/tmp/verify_cert.' . $random_blurp . '.pem: ', '', implode("\n", $verify_output)); + $result["validation"]["status"] = "failed"; + $result["validation"]["error"] = "Error: Validating certificate chain failed: " . str_replace('/tmp/verify_cert.' . $random_blurp . '.pem: ', '', implode("\n", $verify_output)); + $result["warning"][] = "Error: Validating certificate chain failed. Probably non-trusted root/self signed certificate, or the chain order is wrong."; } else { - $result["chain"]["validation"]["status"] = "success"; + $result["validation"]["status"] = "success"; } unlink('/tmp/verify_cert.' . $random_blurp . '.pem'); } @@ -688,6 +466,17 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { // protocols $result["protocols"] = array_reverse(ssl_conn_protocols($host, $port)); + foreach ($result["protocols"] as $key => $value) { + if ( $value == true ) { + if ( $key == "sslv3") { + $result["warning"][] = 'SSLv3 supported. Please disable and upgrade to a newer protocol like TLSv1.2.'; + } + } else { + if ( $key == "tlsv1.2") { + $result["warning"][] = 'TLSv1.2 unsupported. Please enable TLSv1.2.'; + } + } + } // ciphersuites if ($_GET['ciphersuites'] == 1) { @@ -809,55 +598,6 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { 'NULL-SHA256', 'NULL-SHA', 'NULL-MD5'); - - $bad_ciphersuites = array('ECDHE-RSA-DES-CBC3-SHA', - 'ECDHE-ECDSA-DES-CBC3-SHA', - 'EDH-RSA-DES-CBC3-SHA', - 'EDH-DSS-DES-CBC3-SHA', - 'DH-RSA-DES-CBC3-SHA', - 'DH-DSS-DES-CBC3-SHA', - 'ECDH-RSA-DES-CBC3-SHA', - 'ECDH-ECDSA-DES-CBC3-SHA', - 'DES-CBC3-SHA', - 'EDH-RSA-DES-CBC-SHA', - 'EDH-DSS-DES-CBC-SHA', - 'DH-RSA-DES-CBC-SHA', - 'DH-DSS-DES-CBC-SHA', - 'DES-CBC-SHA', - 'EXP-EDH-RSA-DES-CBC-SHA', - 'EXP-EDH-DSS-DES-CBC-SHA', - 'EXP-DH-RSA-DES-CBC-SHA', - 'EXP-DH-DSS-DES-CBC-SHA', - 'EXP-DES-CBC-SHA', - 'EXP-EDH-RSA-DES-CBC-SHA', - 'EXP-EDH-DSS-DES-CBC-SHA', - 'EXP-DH-RSA-DES-CBC-SHA', - 'EXP-DH-DSS-DES-CBC-SHA', - 'EXP-DES-CBC-SHA', - 'EXP-RC2-CBC-MD5', - 'EXP-RC4-MD5', - 'RC4-MD5', - 'EXP-RC2-CBC-MD5', - 'EXP-RC4-MD5', - 'ECDHE-RSA-RC4-SHA', - 'ECDHE-ECDSA-RC4-SHA', - 'ECDH-RSA-RC4-SHA', - 'ECDH-ECDSA-RC4-SHA', - 'RC4-SHA', - 'RC4-MD5', - 'PSK-RC4-SHA', - 'EXP-RC4-MD5', - 'ECDHE-RSA-NULL-SHA', - 'ECDHE-ECDSA-NULL-SHA', - 'AECDH-NULL-SHA', - 'RC4-SHA', - 'RC4-MD5', - 'ECDH-RSA-NULL-SHA', - 'ECDH-ECDSA-NULL-SHA', - 'NULL-SHA256', - 'NULL-SHA', - 'NULL-MD5'); - $tested_ciphersuites = ssl_conn_ciphersuites($host, $port, $ciphersuites_to_test); $result["supported_ciphersuites"] = array(); foreach ($tested_ciphersuites as $key => $value) { @@ -879,6 +619,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { $result["tls_fallback_scsv"] = "supported"; } else { $result["tls_fallback_scsv"] = "unsupported"; + $result["warning"][] = "TLS_FALLBACK_SCSV unsupported. Please upgrade OpenSSL to enable. This offers downgrade attack protection."; } } //hsts @@ -891,6 +632,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { } } else { $result["strict_transport_security"] = 'not set'; + $result["warning"][] = "HTTP Strict Transport Security not set."; } //hpkp if ( $headers["public-key-pins"] ) { @@ -915,6 +657,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { $result["ocsp_stapling"] = $stapling; } else { $result["ocsp_stapling"] = "not set"; + $result["warning"][] = "OCSP Stapling not enabled."; } $result["openssl_version"] = shell_exec("openssl version"); diff --git a/functions/json.php b/functions/json.php new file mode 100644 index 0000000..26058a6 --- /dev/null +++ b/functions/json.php @@ -0,0 +1,61 @@ +<?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 check_json($host,$port) { + $data = []; + $stream = stream_context_create (array("ssl" => + array("capture_peer_cert" => true, + "capture_peer_cert_chain" => true, + "verify_peer" => false, + "verify_peer_name" => false, + "allow_self_signed" => true, + "capture_session_meta" => true, + "sni_enabled" => true))); + $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); + if ( $read_stream === false ) { + $data["error"] = ["Failed to connect: " . htmlspecialchars($errstr)]; + return $data; + } else { + $context = stream_context_get_params($read_stream); + $context_meta = stream_context_get_options($read_stream)['ssl']['session_meta']; + $cert_data = openssl_x509_parse($context["options"]["ssl"]["peer_certificate"]); + $chain_data = $context["options"]["ssl"]["peer_certificate_chain"]; + $chain_length = count($chain_data); + if (isset($chain_data) && $chain_length < 10) { + $chain_length = count($chain_data); + $chain_arr_keys = ($chain_data); + foreach(array_keys($chain_arr_keys) as $key) { + $curr = $chain_data[$key]; + $next = $chain_data[$key+1]; + $prev = $chain_data[$key-1]; + $chain_key = (string)$key+1; + if ($key == 0) { + $data["connection"] = ssl_conn_metadata_json($host, $port, $read_stream, $chain_data); + $data["chain"][$chain_key] = cert_parse_json($curr, $next, $host, true); + } else { + $data["chain"][$chain_key] = cert_parse_json($curr, $next, null, false); + } + } + } else { + $data["error"] = ["Chain too long."]; + return $data; + } + } + return $data; +} + +?>
\ No newline at end of file diff --git a/functions/ocsp.php b/functions/ocsp.php index c9d43eb..ca8ada6 100644 --- a/functions/ocsp.php +++ b/functions/ocsp.php @@ -20,7 +20,6 @@ function ocsp_stapling($host, $port){ if (strpos($output, "no response sent") !== false) { $result = array("working" => 0, "cert_status" => "No response sent"); - return; } if (strpos($output, "OCSP Response Data:") !== false) { $lines = array(); @@ -45,65 +44,6 @@ function ocsp_stapling($host, $port){ return $result; } -function ocsp_verify($raw_cert_data, $raw_next_cert_data) { - global $random_blurp; - $cert_data = openssl_x509_parse($raw_cert_data); - $tmp_dir = '/tmp/'; - $root_ca = getcwd() . '/cacert.pem'; - - $pem_issuer = ""; - $pem_client = ""; - $ocsp_uri = explode("OCSP - URI:", $cert_data['extensions']['authorityInfoAccess'])[1]; - $ocsp_uri = explode("\n", $ocsp_uri)[0]; - $ocsp_uri = explode(" ", $ocsp_uri)[0]; - if (empty($ocsp_uri) ) { - $result = array('unknown' => "Could not find OCSP URI", ); - return $result; - } - openssl_x509_export($raw_cert_data, $pem_client); - 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'); - openssl_x509_export_to_file($raw_cert_data, $tmp_dir.$random_blurp.'.cert_client.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); - - //echo '<pre>' . htmlspecialchars('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$tmp_dir.$random_blurp.'.cert_issuer.pem -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1') . '</pre>'; - - $output = shell_exec('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$tmp_dir.$random_blurp.'.cert_issuer.pem -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1'); - $filter_output = shell_exec('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$tmp_dir.$random_blurp.'.cert_issuer.pem -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"'); - - - - $lines = array(); - $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); - $lines[trim($k)] = trim($v); - } - } - - $result = array("This Update" => $lines["This Update"], - "Next Update" => $lines["Next Update"], - "Reason" => $lines["Reason"], - "Revocation Time" => $lines["Revocation Time"], - "ocsp_verify_status" => $lines[$tmp_dir . $random_blurp . ".cert_client.pem"]); - if ($result["ocsp_verify_status"] == "good") { - $result["good"] = $filter_output; - } else if ($result["ocsp_verify_status"] == "revoked") { - $result["revoked"] = $filter_output; - } else { - $result["unknown"] = $filter_output; - } - unlink($tmp_dir.$random_blurp.'.cert_client.pem'); - unlink($tmp_dir.$random_blurp.'.cert_issuer.pem'); - return $result; -} - - function ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri) { global $random_blurp; $result = array(); @@ -112,16 +52,19 @@ function ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri) { $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'); - openssl_x509_export_to_file($raw_cert_data, $tmp_dir.$random_blurp.'.cert_client.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('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$tmp_dir.$random_blurp.'.cert_issuer.pem -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1'); + //pre_dump('openssl ocsp -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'); + + $output = shell_exec('openssl ocsp -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('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$tmp_dir.$random_blurp.'.cert_issuer.pem -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"'); + $filter_output = shell_exec('openssl ocsp -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"'); $output = preg_replace("/[[:blank:]]+/"," ", $output); $ocsp_status_lines = explode("\n", $output); diff --git a/functions/parse_certificate.php b/functions/parse_certificate.php index 1c7c959..e926e47 100644 --- a/functions/parse_certificate.php +++ b/functions/parse_certificate.php @@ -14,653 +14,636 @@ // 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 get_cert_cn($raw_cert_data){ - $cert_data = openssl_x509_parse($raw_cert_data); - if ($cert_data['subject']['CN']) { - return $cert_data['subject']['CN']; + +function csr_parse($data) { + echo "<table class='table table-striped table-bordered'>"; + echo "<tr>"; + echo "<td colspan='2'><strong>Certificate Data</strong></td>"; + echo "</tr>"; + foreach ($data['subject'] as $key => $value) { + echo "<tr><td>"; + switch ($key) { + case 'C': + echo "Country"; + break; + case 'ST': + echo "State"; + break; + case 'L': + echo "City"; + break; + case 'O': + echo "Organization"; + break; + case 'OU': + echo "Organizational Unit"; + break; + case 'CN': + echo "Common Name"; + break; + case 'mail': + echo "Email Address"; + break; + default: + echo htmlspecialchars($key); + break; + } + echo "</td><td>"; + switch ($key) { + case 'C': + echo htmlspecialchars($value); + echo ' <img src="'.htmlspecialchars($current_folder) . 'img/blank.gif" class="flag flag-'; + echo strtolower(htmlspecialchars($value)); + echo '" alt="" />'; + break; + case 'DC': + foreach ($value as $key => $value) { + echo htmlspecialchars($value) . "."; + } + break; + default: + if (is_array($value)) { + foreach ($value as $key => $value) { + echo htmlspecialchars($value) . " "; + } + } else { + echo htmlspecialchars($value); + } + break; + } + echo "</td></tr>\n"; + } + echo "<tr><td>Public Key PEM ("; + echo htmlspecialchars($data['details']['bits']); + if ($data['details']['rsa']) { + echo " RSA"; + } + if ($data['details']['dsa']) { + echo " DSA"; + } + if ($data['details']['dh']) { + echo " DH"; } + if ($data['details']['ec']) { + echo " ECDSA"; + } + echo ")</td><td><pre>"; + echo htmlspecialchars($data['details']['key']); + echo "</pre></td>"; + echo "</table>"; } -function cert_parse($raw_cert_data, $raw_next_cert_data=null, $csr=false, $host=null, $port=null, $is_issuer=false) { - global $random_blurp; - global $ev_oids; - if ($csr == true && strpos($raw_cert_data, "BEGIN CERTIFICATE REQUEST") !== false) { - ?> - <table class="table table-striped table-bordered"> - <tr> - <td colspan="2"><strong>Certificate Data</strong></td> - </tr> - <?php - $cert_data = openssl_csr_get_public_key($raw_cert_data); - - $cert_details = openssl_pkey_get_details($cert_data); - $cert_key = $cert_details['key']; - $cert_subject = openssl_csr_get_subject($raw_cert_data); - - foreach ($cert_subject as $key => $value) { - echo "<tr><td>"; - switch ($key) { - case 'C': - echo "Country"; - break; - case 'ST': - echo "State"; - break; - case 'L': - echo "City"; - break; - case 'O': - echo "Organization"; - break; - case 'OU': - echo "Organizational Unit"; - break; - case 'CN': - echo "Common Name"; - break; - case 'mail': - echo "Email Address"; - break; - default: - echo htmlspecialchars($key); - break; +function cert_parse($data) { + if (is_array($data["warning"]) && count($data["warning"]) >= 1) { + $data["warning"] = array_unique($data["warning"]); + if (count($data["warning"]) == 1) { + echo "<h3>" . count($data["warning"]) . " warning!</h3>"; + } else { + echo "<h3>" . count($data["warning"]) . " warnings!</h3>"; + } + foreach ($data["warning"] as $key => $value) { + echo "<div class='alert alert-danger' role='alert'>"; + echo htmlspecialchars($value); + echo "</div>"; + } + } + echo "<table class='table table-striped table-bordered'>"; + echo "<tr>"; + echo "<td colspan='2'><strong>Certificate Data</strong></td>"; + echo "</tr>"; + $today = date("Y-m-d"); + echo "<tr><td colspan='2'>\n"; + echo "<table class='table'>\n"; + echo "<thead><tr>\n"; + echo "<th>Hostname</th>\n"; + echo "<th>Not Expired</th>\n"; + echo "<th>Issuer</th>\n"; + echo "<th>CRL</th>\n"; + echo "<th>OCSP</th>\n"; + echo "<th>Signing Type</th>\n"; + echo "</tr>\n</thead>\n<tbody>\n<tr>"; + // hostname validation + if ($data["hostname_in_san_or_cn"] == "true") { + echo '<td><h1><span class="text-success glyphicon glyphicon-ok"></span> </h1></td>'; + } elseif ($data["hostname_in_san_or_cn"] == "false") { + echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; + } elseif ($data["hostname_in_san_or_cn"] == "n/a; ca signing certificate") { + echo "<td></td>"; + } else { + echo "<td><h1><span class='text-danger glyphicon glyphicon-question-sign'></span> </h1></td>"; + } + // expired + if ( $today > date(DATE_RFC2822,$data['cert_data']['validFrom_time_t']) || strtotime($today) < strtotime(date(DATE_RFC2822,$data['cert_data']['validTo_time_t'])) ) { + echo '<td><h1><span class="text-success glyphicon glyphicon-ok"></span> </h1></td>'; + } else { + echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; + } + // issuer + if (!empty($data["issuer_valid"])) { + if ($data["issuer_valid"] == true) { + echo '<td><h1><span class="text-success glyphicon glyphicon-ok"></span> </h1></td>'; + } else { + echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; + } + } else { + echo '<td> </td>'; + } + // crl + if ( !empty($data['crl'][1]['status']) ) { + if ($data['crl'][1]['status'] == "ok") { + echo "<td><h1><span class='text-success glyphicon glyphicon-ok'></span> </h1></td>"; + } else { + echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; + } + } else { + echo '<td> </td>'; + } + // ocsp + if (!empty($data['ocsp'][1]['ocsp_uri'])) { + echo "<td>"; + if ($data['ocsp'][1]["status"] == "good") { + echo '<h1><span class="text-success glyphicon glyphicon-ok"></span> </h1>'; + } else if ($data['ocsp'][1]["status"] == "revoked") { + echo '<h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1>'; + } else { + echo '<h1><span class="text-danger glyphicon glyphicon-question-sign"></span> </h1>'; + } + echo "</td>"; + } else { + echo "<td> </td>"; + } + // self signed/ca/ca root + if (strpos($data['cert_data']['extensions']['basicConstraints'], "CA:TRUE") !== false && $data['cert_data']['issuer']['CN'] == $data['cert_data']['subject']['CN'] ) { + echo '<td><span class="text-success">CA Root Certificate</span></td>'; + } else if (strpos($data['cert_data']['extensions']['basicConstraints'], "CA:TRUE") !== false) { + echo '<td><span class="text-success">CA Certificate</span></td>'; + } else if ($data['cert_data']['issuer']['CN'] == $data['cert_data']['subject']['CN']) { + echo '<td><span class="text-danger">Self Signed</span></td>'; + } else { + echo "<td>Signed by CA</td>"; + } + echo "</tr>"; + echo "</tbody></table>"; + echo "</td></tr>"; + if (!empty($data['cert_data']['subject']) ) { + foreach ($data['cert_data']['subject'] as $key => $value) { + echo "<tr><td>"; + switch ($key) { + case 'C': + echo "Country"; + break; + case 'ST': + echo "State"; + break; + case 'L': + echo "City"; + break; + case 'O': + echo "Organization"; + break; + case 'OU': + echo "Organizational Unit"; + break; + case 'CN': + echo "Common Name"; + break; + case 'mail': + echo "Email Address"; + break; + case 'businessCategory': + echo "Business Type"; + break; + default: + echo htmlspecialchars($key); + break; + } + echo "</td><td>"; + switch ($key) { + case 'C': + echo htmlspecialchars($value); + echo ' <img src="'.htmlspecialchars($current_folder) . 'img/blank.gif" class="flag flag-'; + echo strtolower(htmlspecialchars($value)); + echo '" alt="" />'; + break; + case 'DC': + foreach ($value as $key => $value) { + echo htmlspecialchars($value) . "."; } - - echo "</td><td>"; - switch ($key) { - case 'C': - echo htmlspecialchars($value); - echo ' <img src="'.htmlspecialchars($current_folder) . 'img/blank.gif" class="flag flag-'; - echo strtolower(htmlspecialchars($value)); - echo '" alt="" />'; - break; - case 'DC': + break; + default: + if (is_array($value)) { foreach ($value as $key => $value) { - echo htmlspecialchars($value) . "."; + echo htmlspecialchars($value) . " "; } - break; - default: - if (is_array($value)) { - foreach ($value as $key => $value) { - echo htmlspecialchars($value) . " "; - } - } else { - echo htmlspecialchars($value); - } - break; + } else { + echo htmlspecialchars($value); } - - echo "</td></tr>\n"; + break; } - echo "</table>"; - return; - } else { - $cert_data = openssl_x509_parse($raw_cert_data); + echo "</td>"; + echo "</tr>"; } - if (empty($cert_data)) { - echo "Data not valid."; - continue; + } + // san + if (!empty($data['cert_data']['extensions']['subjectAltName'])) { + echo "<tr>"; + echo "<td>Subject Alternative Names</td>"; + echo "<td>"; + foreach ( explode("DNS:", $data['cert_data']['extensions']['subjectAltName']) as $altName ) { + if ( !empty(str_replace(',', " ", "$altName"))) { + echo htmlspecialchars(str_replace(',', " ", "$altName")); + echo "<br>"; } - ?> - <table class="table table-striped table-bordered"> - <tr> - <td colspan="2"><strong>Certificate Data</strong></td> - </tr> - <?php - $next_cert_data = openssl_x509_parse($raw_next_cert_data); - $today = date("Y-m-d"); - echo "<tr><td colspan='2'>\n"; - echo "<table class='table'>\n"; - echo "<thead><tr>\n"; - echo "<th>Hostname</th>\n"; - echo "<th>Not Expired</th>\n"; - echo "<th>Issuer</th>\n"; - echo "<th>CRL</th>\n"; - echo "<th>OCSP</th>\n"; - echo "<th>Signing Type</th>\n"; - echo "</tr>\n</thead>\n<tbody>\n<tr>"; - // hostname - if ($is_issuer == false) { - if ($csr == false) { - if ($cert_data['subject']['CN']) { - if ( verify_certificate_hostname($raw_cert_data, $host) ) { - echo '<td><h1><span class="text-success glyphicon glyphicon-ok"></span> </h1></td>'; - } else { - echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; - } + } + echo "</td>"; + echo "</tr>"; + } + // validation type + echo "<tr>"; + echo "<td>Type</td>"; + echo "<td>"; + if ($data["validation_type"] == "extended") { + echo '<span class="text-success">Extended Validation</span>'; + } elseif ($data["validation_type"] == "organization") { + echo "Organization Validation"; + } elseif ($data["validation_type"] == "domain") { + echo "Domain Validation"; + } + // full subject + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + echo "<td>Full Subject</td>"; + echo "<td>"; + echo htmlspecialchars($data['cert_data']['name']); + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + echo "<td colspan='2'><strong>Issuer</strong></td>"; + echo "</tr>"; + if (!empty($data['cert_data']['issuer']) ) { + foreach ($data['cert_data']['issuer'] as $key => $value) { + echo "<tr><td>"; + switch ($key) { + case 'C': + echo "Country"; + break; + case 'ST': + echo "State"; + break; + case 'L': + echo "City"; + break; + case 'O': + echo "Organization"; + break; + case 'OU': + echo "Organizational Unit"; + break; + case 'CN': + echo "Common Name"; + break; + case 'mail': + echo "Email Address"; + break; + case 'emailAddress': + echo "Email Address"; + break; + default: + echo htmlspecialchars($key); + break; + } + echo "</td><td>"; + switch ($key) { + case 'C': + echo htmlspecialchars($value); + echo ' <img src="'.htmlspecialchars($current_folder) . 'img/blank.gif" class="flag flag-'; + echo strtolower(htmlspecialchars($value)); + echo '" alt="" />'; + break; + case 'DC': + foreach ($value as $key => $value) { + echo htmlspecialchars($value) . "."; + } + break; + default: + if (is_array($value)) { + foreach ($value as $key => $value) { + echo htmlspecialchars($value) . " "; } } else { - echo "<td></td>"; + echo htmlspecialchars($value); } - } else { - echo "<td></td>"; - } -// expired - if ( $today > date(DATE_RFC2822,$cert_data['validFrom_time_t']) || strtotime($today) < strtotime(date(DATE_RFC2822,$cert_data['validTo_time_t'])) ) { - echo '<td><h1><span class="text-success glyphicon glyphicon-ok"></span> </h1></td>'; - } else { - echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; + break; } -// issuer - if ($raw_next_cert_data) { - if (verify_cert_issuer_by_subject_hash($raw_cert_data, $raw_next_cert_data) ) { - echo '<td><h1><span class="text-success glyphicon glyphicon-ok"></span> </h1></td>'; + echo "</td>"; + echo "</tr>"; + } + } + // valid from + echo "<tr>"; + echo "<td colspan='2'><strong>Validity</strong></td>"; + echo "</tr>"; + if ( !empty($data['cert_data']['validFrom_time_t']) ) { + echo "<tr>"; + echo "<td>Valid From</td>"; + echo "<td>"; + if ( $today < date(DATE_RFC2822,$data['cert_data']['validFrom_time_t']) ) { + echo '<span class="text-success glyphicon glyphicon-ok-sign"></span>'; + echo '<span class="text-success"> - '; + } else { + echo '<span class="text-danger glyphicon glyphicon-exclamation-sign"></span>'; + echo '<span class="text-danger"> - '; + } + echo htmlspecialchars(date(DATE_RFC2822,$data['cert_data']['validFrom_time_t'])); + echo "</span>"; + echo "</td>"; + echo "</tr>"; + } + // issued to expired + if ( !empty($data['cert_data']['validTo_time_t']) ) { + echo "<tr>"; + echo "<td>Valid Until</td>"; + echo "<td>"; + if ( strtotime($today) < strtotime(date(DATE_RFC2822,$data['cert_data']['validTo_time_t'])) ) { + echo '<span class="text-success glyphicon glyphicon-ok-sign"></span>'; + echo '<span class="text-success"> - '; + } else { + echo '<span class="text-danger glyphicon glyphicon-exclamation-sign"></span>'; + echo '<span class="text-danger"> - '; + } + echo htmlspecialchars(date(DATE_RFC2822,$data['cert_data']['validTo_time_t'])); + echo "</span>"; + echo "</td>"; + echo "</tr>"; + }; + if ( is_array($data['crl']) ) { + echo "<tr>"; + echo "<td>CRL</td>"; + echo "<td>"; + foreach ($data['crl'] as $key => $value) { + if ($value) { + if ($value["status"] == "ok") { + echo "<span class='text-success glyphicon glyphicon-ok-sign'></span>"; + echo "<span class='text-success'> - Not on CRL: " . htmlspecialchars($value["crl_uri"]) . "</span><br>"; + echo "Last update: " . htmlspecialchars($value['crl_last_update']) . "<br>\n"; + echo "Next update: " . htmlspecialchars($value['crl_next_update']) . "<br>\n"; + } elseif ($value["status"] == "revoked") { + echo "<span class='text-danger glyphicon glyphicon-exclamation-sign'></span>"; + echo "<span class='text-danger'> - Revoked on CRL: " . htmlspecialchars($value["crl_uri"]) . "</span><br>\n"; + echo "<span class='text-danger'>Revocation date: " . htmlspecialchars($value["revoked_on"]) . "</span><br>\n"; + echo "<br>Last update: " . htmlspecialchars($value['crl_last_update']) . "<br>\n"; + echo "Next update: " . htmlspecialchars($value['crl_next_update']) . "<br>\n"; } else { - echo '<td><h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1></td>'; + echo "<span class='text-danger glyphicon glyphicon-exclamation-sign'></span>"; + echo "<span class='text-danger'> - CRL invalid: (" . htmlspecialchars($value["crl_uri"]) . ")</span><br>"; + echo "<pre> " . htmlspecialchars($value["error"]) . "</pre>"; } - } else { - echo '<td> </td>'; } -// crl - if ( !empty($cert_data['extensions']['crlDistributionPoints']) ) { - echo "<td><h1>" . crl_verify($raw_cert_data, false) . " </h1></td>"; - } else { - echo '<td> </td>'; + if (count($data['ocsp']) > 1) { + echo "<hr>"; } -// ocsp - if ( !empty($cert_data['extensions']['authorityInfoAccess']) && !empty($next_cert_data) ) { - echo "<td>"; - $ocsp_uri = explode("OCSP - URI:", $cert_data['extensions']['authorityInfoAccess'])[1]; - $ocsp_uri = explode("\n", $ocsp_uri)[0]; - $ocsp_uri = explode(" ", $ocsp_uri)[0]; - if (!empty($ocsp_uri)) { - $ocsp_result = ocsp_verify($raw_cert_data, $raw_next_cert_data); - if ($ocsp_result["ocsp_verify_status"] == "good") { - echo '<h1><span class="text-success glyphicon glyphicon-ok"></span> </h1>'; - } else if ($ocsp_result["ocsp_verify_status"] == "revoked") { - echo '<h1><span class="text-danger glyphicon glyphicon-remove"></span> </h1>'; - } else { - echo '<h1><span class="text-danger glyphicon glyphicon-question-sign"></span> </h1>'; - } + } + echo "</td>"; + echo "</tr>"; + } else { + echo "<tr><td>CRL</td><td>No CRL URI found in certificate</td></tr>"; + } + // ocsp + if ( is_array($data['ocsp'])) { + echo "<tr>"; + echo "<td>OCSP</td>"; + echo "<td>"; + foreach ($data['ocsp'] as $key => $value) { + if ($value) { + if ($value["status"] == "good") { + echo '<span class="text-success glyphicon glyphicon-ok-sign"></span> '; + echo '<span class="text-success"> - OK: '; + echo htmlspecialchars($value['ocsp_uri']); + echo "</span><br>"; + echo "Last update: " . htmlspecialchars($value["this_update"]) . "<br>\n"; + echo "Next update: " . htmlspecialchars($value["next_update"]) . "<br>\n"; + } else if ( $value["status"] == "revoked") { + echo '<span class="text-danger glyphicon glyphicon-remove-sign"></span>'; + echo '<span class="text-danger"> - REVOKED: '; + echo htmlspecialchars($value['ocsp_uri']); + echo "</span><br>"; + echo "<span class='text-danger'>Revocation Time: " . htmlspecialchars($value["revocation_time"]) . "<br>\n"; + echo "Revocation Reason: " . htmlspecialchars($value["reason"]). "</span><br>"; + echo "<br>Last update: " . htmlspecialchars($value["this_update"]) . "<br>\n"; + echo "Next update: " . htmlspecialchars($value["next_update"]) . "<br>\n"; } else { - echo "<td></td>"; + echo '<span class="text-danger glyphicon glyphicon-question-sign"></span>'; + echo '<span class="text-danger"> - UNKNOWN: '; + echo " - " . htmlspecialchars($value['ocsp_uri']) . "</span><br>"; + echo "<pre>" . htmlspecialchars($value["error"]) . "</pre>"; } - echo "</td>"; - } else { - echo "<td> </td>"; } - // self signed/ca/ca root - if (strpos($cert_data['extensions']['basicConstraints'], "CA:TRUE") !== false && $cert_data['issuer']['CN'] == $cert_data['subject']['CN'] ) { - echo '<td><span class="text-success">CA Root Certificate</span></td>'; - } else if (strpos($cert_data['extensions']['basicConstraints'], "CA:TRUE") !== false) { - echo '<td><span class="text-success">CA Certificate</span></td>'; - } else if ($cert_data['issuer']['CN'] == $cert_data['subject']['CN']) { - echo '<td><span class="text-danger">Self Signed</span></td>'; - } else { - echo "<td>Signed by CA</td>"; + if (count($data['ocsp']) > 1) { + echo "<hr>"; } - echo "</tr>"; - echo "</tbody></table>"; - echo "</td></tr>"; - - - if (!empty($cert_data['subject']) ) { - foreach ($cert_data['subject'] as $key => $value) { - echo "<tr><td>"; - switch ($key) { - case 'C': - echo "Country"; - break; - case 'ST': - echo "State"; - break; - case 'L': - echo "City"; - break; - case 'O': - echo "Organization"; - break; - case 'OU': - echo "Organizational Unit"; - break; - case 'CN': - echo "Common Name"; - break; - case 'mail': - echo "Email Address"; - break; - case 'businessCategory': - echo "Business Type"; - break; - default: - echo htmlspecialchars($key); - break; - } - echo "</td><td>"; - switch ($key) { - case 'C': - echo htmlspecialchars($value); - echo ' <img src="'.htmlspecialchars($current_folder) . 'img/blank.gif" class="flag flag-'; - echo strtolower(htmlspecialchars($value)); - echo '" alt="" />'; - break; - case 'DC': - foreach ($value as $key => $value) { - echo htmlspecialchars($value) . "."; - } - break; - default: - if (is_array($value)) { - foreach ($value as $key => $value) { - echo htmlspecialchars($value) . " "; - } - } else { - echo htmlspecialchars($value); - } - break; - } - echo "</td></tr>\n"; - } - - + } + } else { + if ($data["ocsp"] == "No issuer cert provided. Unable to send OCSP request.") { + echo "<tr><td>OCSP</td><td>No issuer certificate provided. Unable to send OCSP request.</td></tr>"; + } else { + echo "<tr><td>OCSP</td><td>No OCSP URI found in certificate</td></tr>"; + } + } + echo "<tr>"; + echo "<td>Hostname Validation</td>"; + echo "<td>"; + // hostname validation + if ($data["hostname_in_san_or_cn"] == "true") { + echo "<span class='text-success glyphicon glyphicon-ok'></span>\n<span class='text-success'> - "; + echo htmlspecialchars($data['hostname_checked']); + echo " found in CN or SAN.</span>"; + } elseif ($data["hostname_in_san_or_cn"] == "false") { + echo '<span class="text-danger glyphicon glyphicon-remove"></span><span class="text-danger"> - '; + echo htmlspecialchars($data['hostname_checked']); + echo ' NOT found in CN or SAN.</span>'; + } elseif ($data["hostname_in_san_or_cn"] == "n/a; ca signing certificate") { + echo "Not applicable, this seems to be a CA signing certificate."; + } else { + echo "Not applicable, this seems to be a CA signing certificate."; + } + echo "</td>"; + echo "</tr>"; + // details + echo "<tr>"; + echo "<td colspan='2'><strong>Details</strong></td>"; + echo "</tr>"; + if ( !empty($data['cert_data']['purposes']) ) { + echo "<tr>"; + echo "<td>Purposes</td>"; + echo "<td>"; + foreach ($data['cert_data']['purposes'] as $key => $purpose) { + if ($purpose["general"]) { + echo htmlspecialchars($key); + echo " "; } - if (!empty($cert_data['extensions']['subjectAltName'])) { - ?> - <tr> - <td>Subject Alternative Names</td> - <td> + } + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + echo "<td>Purposes CA</td>"; + echo "<td>"; + foreach ($data['cert_data']['purposes'] as $key => $purpose) { + if ($purpose["ca"]) { + echo htmlspecialchars($key); + echo " "; + } + } + echo "</td>"; + echo "</tr>"; + } + // serial number + if (!empty($data['serialNumber']) ) { + echo "<tr>"; + echo "<td>Serial</td>"; + echo "<td>"; + echo htmlspecialchars($data['serialNumber']); + echo "</td>"; + echo "</tr>"; + } + echo "<tr>"; + echo "<td>Key Size / Type</td>"; + echo "<td>"; + // key details + echo htmlspecialchars($data["key"]['bits']); + echo " bits "; + echo htmlspecialchars($data["key"]['type']); + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + echo "<td>Signature Algorithm</td>"; + echo "<td>"; + echo $data["key"]["signature_algorithm"]; + echo "</td>"; + echo "</tr>"; + if (count($data['cert_data']['extensions']) >= 1) { + echo "<tr>"; + echo "<td>Extensions</td>"; + echo "<td>"; + ?> + <div class="panel-group" id="accordion<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="heading<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + <h4 class="panel-title"> + <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" aria-expanded="false" aria-controls="collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + Click to Open/Close + </a> + </h4> + </div> + <div id="collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + <div class="panel-body"> <?php - foreach ( explode("DNS:", $cert_data['extensions']['subjectAltName']) as $altName ) { - if ( !empty(str_replace(',', " ", "$altName"))) { - echo htmlspecialchars(str_replace(',', " ", "$altName")); - echo "<br>"; + foreach ($data['cert_data']['extensions'] as $name=>$extension) { + + if ( !empty(str_replace(',', " ", "$extension"))) { + echo "<strong>" . htmlspecialchars("$name") . "</strong>"; + echo "<pre>"; + echo htmlspecialchars($extension); + echo "</pre>"; } } - ?> - </td> - </tr> - <?php - } - ?> - <tr> - <td>Type</td> - <td> - <?php - if ( array_search(explode("Policy: ", explode("\n", $cert_data['extensions']['certificatePolicies'])[0])[1], $ev_oids) ) { - echo '<span class="text-success">Extended Validation</span>'; - } else if ( isset($cert_data['subject']['O'] ) ) { - echo "Organisation Validation"; - } else if ( isset($cert_data['subject']['CN'] ) ) { - echo "Domain Validation"; - } - ?> - </td> - </tr> - <tr> - <td>Full Subject</td> - <td><?php echo htmlspecialchars($cert_data['name']); ?></td> - </tr> - <tr> - <td colspan="2"><strong>Issuer</strong></td> - </tr> - <?php - if (!empty($cert_data['issuer']) ) { - foreach ($cert_data['issuer'] as $key => $value) { - echo "<tr><td>"; - switch ($key) { - case 'C': - echo "Country"; - break; - case 'ST': - echo "State"; - break; - case 'L': - echo "City"; - break; - case 'O': - echo "Organization"; - break; - case 'OU': - echo "Organizational Unit"; - break; - case 'CN': - echo "Common Name"; - break; - case 'mail': - echo "Email Address"; - break; - case 'emailAddress': - echo "Email Address"; - break; - default: - echo htmlspecialchars($key); - break; - } - echo "</td><td>"; - switch ($key) { - case 'C': - echo htmlspecialchars($value); - echo ' <img src="'.htmlspecialchars($current_folder) . 'img/blank.gif" class="flag flag-'; - echo strtolower(htmlspecialchars($value)); - echo '" alt="" />'; - break; - case 'DC': - foreach ($value as $key => $value) { - echo htmlspecialchars($value) . "."; - } - break; - default: - if (is_array($value)) { - foreach ($value as $key => $value) { - echo htmlspecialchars($value) . " "; - } - } else { - echo htmlspecialchars($value); - } - break; - } - echo "</td></tr>\n"; - } - } - ?> - <tr> - <td colspan="2"><strong>Validity</strong></td> - </tr> - <?php - if ( !empty($cert_data['validFrom_time_t']) ) { - ?> - <tr> - <td>Valid From</td> - <td> - <?php - if ( $today < date(DATE_RFC2822,$cert_data['validFrom_time_t']) ) { - echo '<span class="text-success glyphicon glyphicon-ok-sign"></span>'; - echo '<span class="text-success"> - '; - } else { - echo '<span class="text-danger glyphicon glyphicon-exclamation-sign"></span>'; - echo '<span class="text-danger"> - '; - - } - echo htmlspecialchars(date(DATE_RFC2822,$cert_data['validFrom_time_t'])); - echo "</span>"; - ?> - </td> - </tr> - - <?php - }; - if ( !empty($cert_data['validTo_time_t']) ) { - ?> - <tr> - <td>Valid Until</td> - <td> + echo "</div>"; + echo "</div>"; + echo "</div>"; + echo "</div>"; + echo "</td>"; + echo "</tr>"; + } else { + echo "<tr>"; + echo "<td>Extensions</td>"; + echo "<td>"; + echo "None"; + echo "</td>"; + echo "</tr>"; + } + if(!empty($data["key"]["certificate_pem"])) { + echo "<tr>"; + echo "<td>Certificate PEM </td>"; + echo "<td>"; + ?> + <div class="panel-group" id="pem-accordion<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="pem-heading<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + <h4 class="panel-title"> + <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#pem-collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" aria-expanded="false" aria-controls="pem-collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + Click to Open/Close + </a> + </h4> + </div> + <div id="pem-collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="pem-heading<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + <div class="panel-body"> <?php - if ( strtotime($today) < strtotime(date(DATE_RFC2822,$cert_data['validTo_time_t'])) ) { - echo '<span class="text-success glyphicon glyphicon-ok-sign"></span>'; - echo '<span class="text-success"> - '; - } else { - echo '<span class="text-danger glyphicon glyphicon-exclamation-sign"></span>'; - echo '<span class="text-danger"> - '; - } - echo htmlspecialchars(date(DATE_RFC2822,$cert_data['validTo_time_t'])); - echo "</span>"; - ?> - </td> - </tr> - <?php - }; - if ( !empty($cert_data['extensions']['crlDistributionPoints']) ) { - ?> - <tr> - <td>CRL</td> - <td> - <?php - echo crl_verify($raw_cert_data); - ?> - </td> - </tr> - <?php - } else { - echo "<tr><td>CRL</td><td>No CRL URI found in certificate</td></tr>"; - } - if ( !empty($cert_data['extensions']['authorityInfoAccess']) && !empty($next_cert_data) ) { - ?> - <tr> - <td>OCSP</td> - <td> - <?php - $ocsp_uri = explode("OCSP - URI:", $cert_data['extensions']['authorityInfoAccess'])[1]; - $ocsp_uri = explode("\n", $ocsp_uri)[0]; - $ocsp_uri = explode(" ", $ocsp_uri)[0]; - - if ( isset($raw_next_cert_data) && !empty($ocsp_uri) ) { - if ($ocsp_result["ocsp_verify_status"] == "good") { - echo '<span class="text-success glyphicon glyphicon-ok-sign"></span> '; - echo '<span class="text-success"> - OK: '; - echo htmlspecialchars($ocsp_uri); - echo "</span><br><pre>This update: " . htmlspecialchars($ocsp_result["This Update"]) . " - "; - echo "<br>Next update: " . htmlspecialchars($ocsp_result["Next Update"]) . "</pre>"; - } else if ( $ocsp_result["ocsp_verify_status"] == "revoked") { - echo '<span class="text-danger glyphicon glyphicon-remove-sign"></span>'; - echo '<span class="text-danger"> - REVOKED: '; - echo htmlspecialchars($ocsp_uri); - echo "</span><br><pre>This update: " . htmlspecialchars($ocsp_result["This Update"]); - echo "<br>Next update: " . htmlspecialchars($ocsp_result["Next Update"]); - echo "<br>Revocation Time: " . htmlspecialchars($ocsp_result["Revocation Time"]); - echo "<br>Revocation Reason: " . htmlspecialchars($ocsp_result["Reason"]). "</pre>"; - } else { - echo '<span class="text-danger glyphicon glyphicon-question-sign"></span>'; - echo '<span class="text-danger"> - UNKNOWN: '; - - echo " - " . htmlspecialchars($ocsp_uri) . "</span><br>"; - echo "<pre>" . htmlspecialchars($ocsp_result["unknown"]) . "</pre>"; - } - } else { - echo "No OCSP URI found in certificate"; - } - ?> - </td> - </tr> - <?php - } else { - echo "<tr><td>OCSP</td><td>No OCSP URI found in certificate</td></tr>"; - } - if ($is_issuer == false && $csr == false) { - if ($cert_data['subject']['CN']) { - echo '<tr><td>Hostname</td>'; - if ( verify_certificate_hostname($raw_cert_data, $host, $port) ) { - echo "<td><span class='text-success glyphicon glyphicon-ok'></span>\n<span class='text-success'> - "; - echo htmlspecialchars($host); - echo " found in CN or SAN.</span></td></tr>"; - } else { + echo "<pre>"; + echo htmlspecialchars($data["key"]["certificate_pem"]); + echo "</pre>"; + echo "</div>"; + echo "</div>"; + echo "</div>"; + echo "</div>"; + echo "</td>"; + echo "</tr>"; + } - echo '<td><span class="text-danger glyphicon glyphicon-remove"></span><span class="text-danger"> - '; - echo htmlspecialchars($host); - echo ' NOT found in CN or SAN.</span></td></tr>'; - } - } - } else { - if ($csr == false) { - echo "<tr><td>Hostname</td><td>Not applicable, this seems to be a CA signing certificate.</td></tr>"; - } else { - echo "<tr><td>Hostname</td><td>Not applicable, this seems to be a CSR.</td></tr>"; - } - } - ?> - <tr> - <td colspan="2"><strong>Details</strong></td> - </tr> - <?php - if ( !empty($cert_data['purposes']) ) { - ?> - <tr> - <td>Purposes</td> - <td> - <?php - $purposes_len = count($cert_data['purposes']); - foreach ($cert_data['purposes'] as $key => $purpose) { - echo htmlspecialchars($purpose[2]); - if ( $key != $purposes_len - 1) { - echo ", "; - } - } - ?> - </td> - </tr> - <?php - }; - if ( !empty($cert_data['serialNumber']) ) { - ?> - <tr> - <td>Serial</td> - <td><code> - <?php - $sn = str_split(strtoupper(bcdechex($cert_data['serialNumber'])), 2); - $sn_len = count($sn); - foreach ($sn as $key => $s) { - echo htmlspecialchars($s); - if ( $key != $sn_len - 1) { - echo ":"; - } - } - ?> - </code></td> - </tr> - <?php - } - ?> - <tr> - <td>Key Size / Type</td> - <td> + if(!empty($data['key']['public_key_pem'])) { + echo "<tr>"; + echo "<td>Public Key PEM </td>"; + echo "<td>"; + ?> + <div class="panel-group" id="pub-pem-accordion<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="pub-pem-heading<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + <h4 class="panel-title"> + <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#pub-pem-collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" aria-expanded="false" aria-controls="pub-pem-collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + Click to Open/Close + </a> + </h4> + </div> + <div id="pub-pem-collapse<?php echo bcdechex($data['cert_data']['serialNumber']); ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="pub-pem-heading<?php echo bcdechex($data['cert_data']['serialNumber']); ?>"> + <div class="panel-body"> <?php - + echo "<pre>"; + echo htmlspecialchars($data['key']['public_key_pem']); + echo "</pre>"; + echo "</div>"; + echo "</div>"; + echo "</div>"; + echo "</div>"; + echo "</td>"; + echo "</tr>"; + echo "<tr>"; + echo "<td><a href='https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html'>SPKI Hash</a></td>"; + echo "<td>"; + print(htmlspecialchars($data['key']['spki_hash'])); + echo "</td>"; + echo "</tr>"; + } + echo "</tbody>"; + echo "</table>"; +} + + + + + + + + + + + + + + + + + - $key_details = openssl_pkey_get_details(openssl_pkey_get_public($raw_cert_data)); - $export_pem = ""; - openssl_x509_export($raw_cert_data, $export_pem); - - if ( $key_details['rsa'] ) { - echo htmlspecialchars($key_details['bits']); - echo " bits RSA"; - } else if ( $key_details['dsa'] ) { - echo htmlspecialchars($key_details['bits']); - echo " bits DSA"; - } else if ( $key_details['dh'] ) { - echo htmlspecialchars($key_details['bits']); - echo " bits DH"; - } else { - echo htmlspecialchars(var_dump($key_details['bits'])); - echo " bits"; - } - ?> - </td> - </tr> - <tr> - <td>Signature Algorithm</td> - <td> - <?php - $signature_algorithm = cert_signature_algorithm($raw_cert_data); - echo htmlspecialchars($signature_algorithm); - ?> - </td> - </tr> - <tr> - <td>Extensions</td> - <td> - <div class="panel-group" id="accordion<?php echo bcdechex($cert_data['serialNumber']); ?>" role="tablist" aria-multiselectable="true"> - <div class="panel panel-default"> - <div class="panel-heading" role="tab" id="heading<?php echo bcdechex($cert_data['serialNumber']); ?>"> - <h4 class="panel-title"> - <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapse<?php echo bcdechex($cert_data['serialNumber']); ?>" aria-expanded="false" aria-controls="collapse<?php echo bcdechex($cert_data['serialNumber']); ?>"> - Click to Open/Close - </a> - </h4> - </div> - <div id="collapse<?php echo bcdechex($cert_data['serialNumber']); ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading<?php echo bcdechex($cert_data['serialNumber']); ?>"> - <div class="panel-body"> - <?php - foreach ( $cert_data['extensions'] as $name=>$extension ) { - if ( !empty(str_replace(',', " ", "$extension"))) { - echo "<strong>" . htmlspecialchars("$name") . "</strong>"; - echo "<pre>"; - echo htmlspecialchars($extension); - echo "</pre>"; - } - } - ?> - </div> - </div> - </div> - </div> - </td> - </tr> - <?php - if(!empty($export_pem)) { - ?> - <tr> - <td>Certificate PEM </td> - <td> - <div class="panel-group" id="pem-accordion<?php echo bcdechex($cert_data['serialNumber']); ?>" role="tablist" aria-multiselectable="true"> - <div class="panel panel-default"> - <div class="panel-heading" role="tab" id="pem-heading<?php echo bcdechex($cert_data['serialNumber']); ?>"> - <h4 class="panel-title"> - <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#pem-collapse<?php echo bcdechex($cert_data['serialNumber']); ?>" aria-expanded="false" aria-controls="pem-collapse<?php echo bcdechex($cert_data['serialNumber']); ?>"> - Click to Open/Close - </a> - </h4> - </div> - <div id="pem-collapse<?php echo bcdechex($cert_data['serialNumber']); ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="pem-heading<?php echo bcdechex($cert_data['serialNumber']); ?>"> - <div class="panel-body"> - <?php - echo "<pre>"; - echo htmlspecialchars($export_pem); - ?> - </pre> - </div> - </div> - </div> - </div> - </td> - </tr> - <?php - } - ?> - <?php - if(!empty($key_details['key'])) { - ?> - <tr> - <td>Public Key PEM </td> - <td> - <div class="panel-group" id="pub-pem-accordion<?php echo bcdechex($cert_data['serialNumber']); ?>" role="tablist" aria-multiselectable="true"> - <div class="panel panel-default"> - <div class="panel-heading" role="tab" id="pub-pem-heading<?php echo bcdechex($cert_data['serialNumber']); ?>"> - <h4 class="panel-title"> - <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#pub-pem-collapse<?php echo bcdechex($cert_data['serialNumber']); ?>" aria-expanded="false" aria-controls="pub-pem-collapse<?php echo bcdechex($cert_data['serialNumber']); ?>"> - Click to Open/Close - </a> - </h4> - </div> - <div id="pub-pem-collapse<?php echo bcdechex($cert_data['serialNumber']); ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="pub-pem-heading<?php echo bcdechex($cert_data['serialNumber']); ?>"> - <div class="panel-body"> - - <?php - echo "<pre>"; - echo htmlspecialchars($key_details['key']); - ?> - </pre> - </div> - </div> - </div> - </div> - </td> - </tr> - <tr> - <td><a href="https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html">SPKI Hash</a></td> - <td> - <?php - $spki_hash = spki_hash($export_pem); - print(htmlspecialchars($spki_hash)); - ?> - </td> - </tr> - <?php - } - ?> - </tbody> - </table> - <?php - } @@ -692,7 +675,7 @@ function csr_parse_json($csr) { $cert_subject = openssl_csr_get_subject($csr); $result["subject"] = $cert_subject; $result["key"] = $cert_key; - $result["details"] = $cert_details; + $result["details"] = $cert_details; } elseif (strpos($csr, "BEGIN CERTIFICATE") !== false) { $result = cert_parse_json($csr); } else { @@ -722,30 +705,74 @@ function cert_parse_json($raw_cert_data, $raw_next_cert_data=null, $host=null, $ $cert_data['purposes'] = $purposes; $result["cert_data"] = $cert_data; } + +// valid from + if ( !empty($result['cert_data']['validFrom_time_t']) ) { + if ( $today < date(DATE_RFC2822,$result['cert_data']['validFrom_time_t']) ) { + $result['cert_issued_in_future'] = false; + } else { + $result['cert_issued_in_future'] = true; + $result['warning'][] = "Certificate issue date is in the future: " . date(DATE_RFC2822,$data['cert_data']['validFrom_time_t']); + } + } + // expired + if (!empty($cert_data['validTo_time_t'])) { + if ($today > date(DATE_RFC2822,$cert_data['validFrom_time_t']) || strtotime($today) < strtotime(date(DATE_RFC2822,$cert_data['validTo_time_t']))) { + $result['cert_expired'] = false; + } else { + $result['cert_expired'] = true; + $result['warning'][] = "Certificate expired! Expiration date: " . date(DATE_RFC2822,$cert_data['validTo_time_t']); + } + } + if ( array_search(explode("Policy: ", explode("\n", $cert_data['extensions']['certificatePolicies'])[0])[1], $ev_oids) ) { $result["validation_type"] = "extended"; } else if ( isset($cert_data['subject']['O'] ) ) { - $result["validation_type"] = "organisation"; + $result["validation_type"] = "organization"; } else if ( isset($cert_data['subject']['CN'] ) ) { $result["validation_type"] = "domain"; } + // issuer + if ($raw_next_cert_data) { + if (verify_cert_issuer_by_subject_hash($raw_cert_data, $raw_next_cert_data) ) { + $result["issuer_valid"] = true; + } else { + $result["issuer_valid"] = false; + $result['warning'][] = "Provided certificate issuer does not match issuer in certificate. Sent chain order wrong."; + } + } // crl if (isset($cert_data['extensions']['crlDistributionPoints']) ) { $result["crl"] = crl_verify_json($raw_cert_data); + if (is_array($result["crl"])) { + foreach ($result["crl"] as $key => $value) { + if ($value["status"] == "revoked") { + $result['warning'][] = "Certificate revoked on CRL: " . $value['crl_uri'] . ". Revocation time: " . $value['revoked_on'] . "."; + } + } + } } else { $result["crl"] = "No CRL URI found in certificate"; } // ocsp - if (isset($cert_data['extensions']['authorityInfoAccess']) && isset($next_cert_data) ) { + if (isset($cert_data['extensions']['authorityInfoAccess'])) { $ocsp_uris = explode("OCSP - URI:", $cert_data['extensions']['authorityInfoAccess']); unset($ocsp_uris[0]); - if ( isset($raw_next_cert_data) && isset($ocsp_uris) ) { - foreach ($ocsp_uris as $key => $ocsp_uri) { - $ocsp_uri = explode("\n", $ocsp_uri)[0]; - $ocsp_uri = explode(" ", $ocsp_uri)[0]; - $result["ocsp"]["$key"] = ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri); + if (isset($ocsp_uris) ) { + if (isset($raw_next_cert_data)) { + foreach ($ocsp_uris as $key => $ocsp_uri) { + $ocsp_uri = explode("\n", $ocsp_uri)[0]; + $ocsp_uri = explode(" ", $ocsp_uri)[0]; + $result["ocsp"]["$key"] = ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri); + if ($result['ocsp'][$key]["status"] == "revoked") { + $result['warning'][] = "Certificate revoked on OCSP: " . $result['ocsp'][$key]['ocsp_uri'] . ". Revocation time: " . $result['ocsp'][$key]['revocation_time'] . "."; + } elseif ($result['ocsp'][$key]["status"] == "unknown") { + $result['warning'][] = "OCSP error on: " . $result['ocsp'][$key]['ocsp_uri'] . "."; + } + } + } else { + $result["ocsp"] = "No issuer cert provided. Unable to send OCSP request."; } - } else { $result["ocsp"] = "No OCSP URI found in certificate"; } @@ -754,28 +781,30 @@ function cert_parse_json($raw_cert_data, $raw_next_cert_data=null, $host=null, $ } // hostname validation if ($validate_hostname == true) { + $result["hostname_checked"] = $host; if (isset($cert_data['subject']['CN'])) { if ( verify_certificate_hostname($raw_cert_data, $host) ) { $result["hostname_in_san_or_cn"] = "true"; } else { $result["hostname_in_san_or_cn"] = "false"; + $result['warning'][] = "Hostname " . $host . " not found in certificate."; } } } else { $result["hostname_in_san_or_cn"] = "n/a; ca signing certificate"; } - //serial + //serial number if ( isset($cert_data['serialNumber']) ) { - $serial = ""; + $serial = []; $sn = str_split(strtoupper(bcdechex($cert_data['serialNumber'])), 2); $sn_len = count($sn); foreach ($sn as $key => $s) { - $serial += htmlspecialchars($s); + $serial[] = htmlspecialchars($s); if ( $key != $sn_len - 1) { - $serial += ":"; + $serial[] = ":"; } } - $result["serial"] = $serial; + $result["serialNumber"] = implode("", $serial); } // key details @@ -785,6 +814,9 @@ function cert_parse_json($raw_cert_data, $raw_next_cert_data=null, $host=null, $ if (isset($key_details['rsa'])) { $result["key"]["type"] = "rsa"; $result["key"]["bits"] = $key_details['bits']; + if ($key_details['bits'] < 2048) { + $result['warning'][] = $key_details['bits'] . " bit RSA key is not safe. Upgrade to at least 4096 bits."; + } } else if (isset($key_details['dsa'])) { $result["key"]["type"] = "dsa"; $result["key"]["bits"] = $key_details['bits']; @@ -800,6 +832,9 @@ function cert_parse_json($raw_cert_data, $raw_next_cert_data=null, $host=null, $ } // signature algorithm $result["key"]["signature_algorithm"] = cert_signature_algorithm($raw_cert_data); + if ($result["key"]["signature_algorithm"] == "sha1WithRSAEncryption") { + $result['warning'][] = "SHA-1 certificate. Upgrade (re-issue) to SHA-256 or better."; + } if(isset($export_pem)) { $result["key"]["certificate_pem"] = $export_pem; } diff --git a/functions/textual.php b/functions/textual.php index 93a5838..4a1a48d 100644 --- a/functions/textual.php +++ b/functions/textual.php @@ -17,7 +17,20 @@ function pre_dump($var) { echo "<pre>"; var_dump($var); - echo "<pre>"; + echo "</pre>"; +} + +function utf8encodeNestedArray($arr) { + // json_encode fails with binary data. utf-8 encode that first, some ca's like to encode images in their OID's (verisign, 1.3.6.1.5.5.7.1.12)... + $encoded_arr = array(); + foreach ($arr as $key => $value) { + if (is_array($value)) { + $encoded_arr[utf8_encode($key)] = utf8encodeNestedArray($value); + } else { + $encoded_arr[utf8_encode($key)] = utf8_encode($value); + } + } + return $encoded_arr; } function startsWith($haystack, $needle) { @@ -31,7 +44,6 @@ function endsWith($haystack, $needle) { } } - function get_current_folder(){ $url = $_SERVER['REQUEST_URI']; $parts = explode('/',$url); diff --git a/functions/variables.php b/functions/variables.php index e58b59e..1154bb4 100644 --- a/functions/variables.php +++ b/functions/variables.php @@ -14,6 +14,8 @@ // 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/>. +date_default_timezone_set('UTC'); + $random_blurp = rand(1000,99999); # 2014-11-10 (nov) from wikipedia diff --git a/inc/footer.php b/inc/footer.php new file mode 100644 index 0000000..410777d --- /dev/null +++ b/inc/footer.php @@ -0,0 +1,75 @@ +<?php +if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { + ?> + <div class="footer"> + <div class="col-md-6 col-md-offset-1 container"> + <p class="text-muted">By <a href="https://raymii.org/s/software/OpenSSL_Decoder.html">Remy van Elst</a>. License: GNU AGPLv3. <a href="https://github.com/RaymiiOrg/ssl-decoder">Source code</a>. <a href="https://github.com/RaymiiOrg/ssl-decoder#json-api">JSON API</a>. <strong><a href="https://cipherli.st/">Strong SSL Ciphers & Config settings @ Cipherli.st</a></strong>. Version: 2.1</p> + </div> + </div> + </div> +</div> +<?php +} +?> + + +<!-- Piwik --> +<script type="text/javascript"> + var _paq = _paq || []; + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="//hosted-oswa.org/piwik/"; + _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setSiteId', 34]); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + })(); +</script> +<noscript><p><img src="//hosted-oswa.org/piwik/piwik.php?idsite=34" style="border:0;" alt="" /></p></noscript> +<!-- End Piwik Code --> + +<script> + + $(document).ready(function(){ + var aChildren = $("nav li").children(); // find the a children of the list items + var aArray = []; // create the empty aArray + for (var i=0; i < aChildren.length; i++) { + var aChild = aChildren[i]; + var ahref = $(aChild).attr('href'); + if(ahref && strStartsWith(ahref, "#") ) { + aArray.push(ahref); + } + } // this for loop fills the aArray with attribute href values + + $(window).scroll(function(){ + + var windowPos = $(window).scrollTop(); // get the offset of the window from the top of page + var windowHeight = $(window).height(); // get the height of the window + var docHeight = $(document).height(); + + for (var i=0; i < aArray.length; i++) { + var theID = aArray[i]; + var divPos = $(theID).offset().top; // get the offset of the div from the top of page + var divHeight = $(theID).height(); // get the height of the div in question + if (windowPos >= divPos && windowPos < (divPos + divHeight)) { + $("a[href='" + theID + "']").addClass("nav-active"); + } else { + $("a[href='" + theID + "']").removeClass("nav-active"); + } + } + + if(windowPos + windowHeight == docHeight) { + if (!$("nav li:last-child a").hasClass("nav-active")) { + var navActiveCurrent = $(".nav-active").attr("href"); + $("a[href='" + navActiveCurrent + "']").removeClass("nav-active"); + $("nav li:last-child a").addClass("nav-active"); + } + } + }); + }); + +</script> + + </body> + </html>
\ No newline at end of file diff --git a/inc/form.php b/inc/form.php new file mode 100644 index 0000000..ef00824 --- /dev/null +++ b/inc/form.php @@ -0,0 +1,56 @@ +<div id='page-content-wrapper'> + <div class='container-fluid'> + <div class='row'> + <div class="col-md-10 col-md-offset-1"> + <div class="page-header" > + <h1>SSL Decoder</h1> + </div> + <div id='sslform'> + <form class="form-horizontal"> + <p>Fill in either host + port or paste a CSR/Certficiate. Port defaults to 443.<br></p> + <fieldset> + <div class="form-group"> + <label class="col-md-1 control-label" for="host">Host</label> + <div class="col-md-5"> + <input id="host" name="host" type="text" placeholder="raymii.org" class="form-control input-md" > + </div> + <label class="col-md-1 control-label" for="port">Port</label> + <div class="col-md-2"> + <input id="port" name="port" type="text" placeholder="443" class="form-control input-md"> + </div> + </div> + <div class="form-group"> + <div class="col-md-4 col-md-offset-1"> + <div class="checkbox"> + <label for="ciphersuites"> + <!-- <input type="checkbox" name="ciphersuites" id="ciphersuites" value="1" checked="checked"> --> + <input type="checkbox" name="ciphersuites" id="ciphersuites" value="1" checked="checked"> + Enumerate Ciphersuites (takes longer) + </label> + </div> + </div> + </div> + <hr> + <div class="form-group"> + <label class="col-md-1 control-label" for="csr">CSR / Certificate</label> + <div class="col-md-5"> + <textarea class="form-control" rows=6 id="csr" name="csr"></textarea> + </div> + </div> + <div class="form-group"> + <div class="col-md-4"> + <label class="col-md-2 col-md-offset-1 control-label" for="s"></label> + <button id="s" name="s" class="btn btn-primary" onsubmit="showElementbyID(true, 'preloader'); showElementbyID(false, 'sslform'); makeRequest('/ssl/?port=' + this.form.port.value + '&csr=' + this.form.csr.value + '&s=&host=' + this.form.host.value,, 'showContent');return false" onclick="showElementbyID(true, 'preloader'); showElementbyID(false, 'sslform'); makeRequest('/ssl/?port=' + this.form.port.value + '&csr=' + this.form.csr.value + '&ciphersuites=' + this.form.ciphersuites.value + '&s=&host=' + this.form.host.value, 'showContent');return false">Submit</button> + </div> + </div> + </fieldset> + </form> + </div> + <div id="preloader"> + <p> + <img src="<?php echo(htmlspecialchars($current_folder)); ?>img/ajax-loader.gif" /> + <br> <br> + The SSL Decoder is processing your request. Please wait a few moments.<br> + </p> + </div> + <div id="resultDiv"></div>
\ No newline at end of file @@ -41,8 +41,9 @@ foreach (glob("functions/*.php") as $filename) { <a id="top-of-page"></a> <?php - if ( isset($_GET['host']) && !empty($_GET['host'])) { + if ( isset($_GET['host']) && !empty($_GET['host'])) { echo '<div id="wrapper">'; + $data = []; $hostname = mb_strtolower(get($_GET['host'])); $host = parse_hostname($hostname); if ($host['port']) { @@ -51,340 +52,139 @@ foreach (glob("functions/*.php") as $filename) { $port = get($_GET['port'], '443'); } $host = $host['hostname']; - $csr = get($_GET['csr'], ''); if ( !is_numeric($port) ) { $port = 443; } - $stream = stream_context_create (array("ssl" => - array("capture_peer_cert" => true, - "capture_peer_cert_chain" => true, - "verify_peer" => false, - "verify_peer_name" => false, - "allow_self_signed" => true, - "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); - if ( $read_stream !== false ) { - $context = stream_context_get_params($read_stream); - $chain_data = $context["options"]["ssl"]["peer_certificate_chain"]; - $chain_length = count($chain_data); - if (!empty($chain_data) && $chain_length < 10) { + $data["data"] = check_json($host,$port); + if(isset($data["data"]["error"])) { + $data["error"] = $data["data"]["error"]; + unset($data["data"]); + } + + $chain_length = count($data["data"]["chain"]); + $chain_data = $data["data"]["chain"]; + if ($chain_length >= 1 && $chain_length < 10) { ?> <!-- Sidebar --> <div id="sidebar-wrapper"> <nav> - <ul class="sidebar-nav"> - <br> - <li class="sidebar-brand"> - <h2>Navigation</h2> - </li> - <li><a href="#conndata"><strong>0</strong>: Connection Data</a></li> - <?php + <ul class="sidebar-nav"> + <br> + <li class="sidebar-brand"> + <h2>Navigation</h2> + </li> + <li><a href="#conndata"><strong>0</strong>: Connection Data</a></li> + <?php foreach ($chain_data as $key => $value) { - $nextkey = $key + 1; - echo "<li><a href='#cert".$nextkey."'><strong>".$nextkey."</strong> : ". htmlspecialchars(get_cert_cn($value)) ."</a></li>"; + echo "<li><a href='#cert".(string)$key."'><strong>".$key."</strong> : ". htmlspecialchars($value["cert_data"]["subject"]["CN"]) ."</a></li>"; } - ?> - <li><a href="<?php echo(htmlspecialchars($current_folder)); ?>">Try another website</a></li> - <li><hr></li> - <li><a href="https://cipherli.st/">Strong Cipherlists</a></li> - <li><a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html">Apache SSL Tutorial</a></li> - <li><a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html">NGINX SSL Tutorial</a></li> - <li><a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_lighttpd.html">Lighttpd SSL Tutorial</a></li> - <li><a href="https://raymii.org">Raymii.org</a></li> - </ul> + ?> + <li><a href="<?php echo(htmlspecialchars($current_folder)); ?>">Try another website</a></li> + <li><hr></li> + <li><a href="https://cipherli.st/">Strong Cipherlists</a></li> + <li><a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html">Apache SSL Tutorial</a></li> + <li><a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html">NGINX SSL Tutorial</a></li> + <li><a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_lighttpd.html">Lighttpd SSL Tutorial</a></li> + <li><a href="https://raymii.org">Raymii.org</a></li> + </ul> </nav> </div> <!-- /#sidebar-wrapper --> - <?php - } - } + <?php + } + } + + if ( !isset($_GET['host']) || !isset($_GET['csr']) ) { + require_once("inc/form.php"); + } else { + echo "<div id='page-content-wrapper'>"; + echo "<div class='container-fluid'>"; + echo "<div class='row'>"; + // if ajax-ed, don't show header again + if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { + echo "<div class='col-md-10 col-md-offset-1'>"; + echo "<div class='page-header'>"; + echo "<h1><a style='color:black;' href=\""; + echo(htmlspecialchars($current_folder)); + echo "\">SSL Decoder</a></h1>"; + echo "</div>"; + // set back to 1 after debugging + $write_cache = 1; + if (!is_dir('results')) { + mkdir('results'); } - ?> -<div id="page-content-wrapper"> - <div class="container-fluid"> - <div class="row"> - <?php - if ( !isset($_GET['host']) || !isset($_GET['csr']) ) { - ?> - <div class="col-md-10 col-md-offset-1"> - <div class="page-header" > - <h1>SSL Decoder</h1> - </div> - <div id='sslform'> - <form class="form-horizontal"> - <p>Fill in either host + port or paste a CSR/Certficiate. Port defaults to 443.<br></p> - <fieldset> - - <div class="form-group"> - <label class="col-md-1 control-label" for="host">Host</label> - <div class="col-md-5"> - <input id="host" name="host" type="text" placeholder="raymii.org" class="form-control input-md" > - </div> - <label class="col-md-1 control-label" for="port">Port</label> - <div class="col-md-2"> - <input id="port" name="port" type="text" placeholder="443" class="form-control input-md"> - </div> - </div> - <div class="form-group"> - <div class="col-md-4 col-md-offset-1"> - <div class="checkbox"> - <label for="ciphersuites"> - <input type="checkbox" name="ciphersuites" id="ciphersuites" value="1" checked="checked"> - Enumerate Ciphersuites (takes longer) - </label> - </div> - </div> - </div> - - <hr> - - <div class="form-group"> - <label class="col-md-1 control-label" for="csr">CSR / Certificate</label> - <div class="col-md-5"> - <textarea class="form-control" rows=6 id="csr" name="csr"></textarea> - </div> - </div> - - <div class="form-group"> - <div class="col-md-4"> - <label class="col-md-2 col-md-offset-1 control-label" for="s"></label> - <button id="s" name="s" class="btn btn-primary" onsubmit="showElementbyID(true, 'preloader'); showElementbyID(false, 'sslform'); makeRequest('/ssl/?port=' + this.form.port.value + '&csr=' + this.form.csr.value + '&s=&host=' + this.form.host.value,, 'showContent');return false" onclick="showElementbyID(true, 'preloader'); showElementbyID(false, 'sslform'); makeRequest('/ssl/?port=' + this.form.port.value + '&csr=' + this.form.csr.value + '&ciphersuites=' + this.form.ciphersuites.value + '&s=&host=' + this.form.host.value, 'showContent');return false">Submit</button> - </div> - </div> - - </fieldset> - </form> - </div> - - <div id="preloader"><p><img src="<?php echo(htmlspecialchars($current_folder)); ?>img/ajax-loader.gif" /><br> <br>The SSL Decoder is processing your request. Please wait a few moments.<br></p></div> - - <div id="resultDiv"></div> - - - <?php - } else { - if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { - ?> - <div class="col-md-10 col-md-offset-1"> - <div class="page-header" > - <h1>SSL Decoder</h1> - </div> - <?php - // set back to 1 after debugging - $write_cache = 1; - if (!is_dir('results')) { - mkdir('results'); - } - $epoch = date('U'); - $random_bla = md5(uniqid(rand(), true)); - } - $hostname = mb_strtolower(get($_GET['host'])); - $host = parse_hostname($hostname); - if ($host['port']) { - $port = $host['port']; - } else { - $port = get($_GET['port'], '443'); - } - $host = $host['hostname']; - $csr = get($_GET['csr'], ''); - if ( !is_numeric($port) ) { - $port = 443; - } - - if ( empty($csr) && !empty($host) ) { - - echo "<p><strong>This tool does not make conclusions. Please check the data and define the validity yourself!</strong></p><br>"; - - $stream = stream_context_create (array("ssl" => - array("capture_peer_cert" => true, - "capture_peer_cert_chain" => true, - "verify_peer" => false, - "capture_session_meta" => true, - "verify_peer_name" => false, - "allow_self_signed" => true, - "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, - STREAM_CLIENT_CONNECT, $stream); - - if ( $read_stream === false ) { - echo "<span class='text-danger'> Failed to connect:" . htmlspecialchars($errno) ." " . htmlspecialchars($errstr) . "</span>"; - echo "<hr>"; - $write_cache = 0; - } else { - $hostfilename = preg_replace("([^\w\s\d\-_~,;:\[\]\(\).])", '', $host); - $hostfilename = preg_replace("([\.]{2,})", '', $host); - $hostfilename = preg_replace("([^a-z0-9])", '', $host); - $cache_filename = (string) "results/saved." . $hostfilename . "." . $epoch . "." . $random_bla . ".html"; - - - if ($write_cache == 1) { - ?> - <p>This result is saved at most 60 days on <a href="<?php echo(htmlspecialchars($current_folder) . $cache_filename); ?>">the following URL</a>. Do note that this might be deleted earlier if space runs out.</p> - <?php - } - $context = stream_context_get_params($read_stream); - $context_meta = stream_context_get_options($read_stream)['ssl']['session_meta']; - $cert_data = openssl_x509_parse($context["options"]["ssl"]["peer_certificate"]); - $chain_data = $context["options"]["ssl"]["peer_certificate_chain"]; - if (!empty($chain_data)) { - $chain_length = count($chain_data); - $chain_arr_keys = ($chain_data); - foreach(array_keys($chain_arr_keys) as $key) { - $curr = $chain_data[$key]; - $next = $chain_data[$key+1]; - $prev = $chain_data[$key-1]; - - if ($key == 0) { - - echo ssl_conn_metadata($host, $port, $chain_data); - echo "<div class='content'><section id='cert1'>"; - echo "<header><h2 class='sticky'>Certificate for '". htmlspecialchars($host) ."'</h2></header>"; - - if ( $chain_length > $key) { - cert_parse($curr, $next, false, $host, $port, false); - } else { - cert_parse($curr, null, false, $host, $port, false); - } - echo "</section></div>"; - } else { - if ($key == 10) { - echo "<span class='text-danger'>Error: Certificate Chain to long.</span><br>."; - $write_cache = 0; - continue; - } - if ($key > 10) { - $write_cache = 0; - continue; - } - $nextkey = $key + 1; - echo "<div class='content'><section id='cert" . $nextkey . "'>"; - echo "<header><h2 class='sticky'>Chain $key - " . htmlspecialchars(get_cert_cn($curr)) . "</h2></header>"; - - if ( $chain_length > $key) { - cert_parse($curr, $next, false, null, null, true); - } else { - cert_parse($curr, null, false, null, null, true); - } - echo "</section></div>"; - } - - } - } - - } - } else if (!empty($csr) && empty($host) ) { - - $cache_filename = (string) "results/saved.csr." . $epoch . "." . $random_bla . ".html"; - - echo "<p><strong>This tool does not make conclusions. Please check the data and define the validity yourself!</strong><br>\n </p> <br>"; - if (strpos($csr, "BEGIN CERTIFICATE REQUEST") !== false) { - echo "<header><h2>CSR </h2></header><p>"; - } else { - echo "<header><h2>Certificate </h2></header><p>"; - } - cert_parse($csr, null, true); - - } else { - echo "<span class='text-danger'> Host or Certificate required.</span>"; - echo "<hr>"; - $write_cache = 0; - } - } + $epoch = date('U'); + $random_bla = md5(uniqid(rand(), true)); + } + + if ( empty($_GET['csr']) && !empty($host) ) { + echo "<p><strong>This tool does not make conclusions. Please check the data and define the validity yourself!</strong></p>"; + if ( !empty($data["error"]) ) { + echo "<span class='text-danger'>" . htmlspecialchars($data["error"][0]) . "</span>"; + echo "<hr>"; + $write_cache = 0; + } else { + $hostfilename = preg_replace("([^\w\s\d\-_~,;:\[\]\(\).])", '', $host); + $hostfilename = preg_replace("([\.]{2,})", '', $host); + $hostfilename = preg_replace("([^a-z0-9])", '', $host); + $cache_filename = (string) "results/saved." . $hostfilename . "." . $epoch . "." . $random_bla . ".html"; if ($write_cache == 1) { - ?> - <div class="panel panel-default"> - <div class="panel-heading"> - <h2 class="panel-title">Saved result</h2> - </div> - <div class="panel-body"> - <p>This result is saved at most 60 days on <a href="<?php echo(htmlspecialchars($current_folder) . $cache_filename); ?>">the following URL</a>. Do note that this might be deleted earlier if space runs out.</p> - </div> - </div> - <?php + echo "This result is saved at most 60 days on <a href=\""; + echo(htmlspecialchars($current_folder) . $cache_filename); + echo "\">the following URL</a>. Do note that this might be deleted earlier if space runs out."; } - ?> - </div> - </div> - </div> - - <?php - if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { - ?> - <div class="footer"> - <div class="col-md-6 col-md-offset-1 container"> - <p class="text-muted">By <a href="https://raymii.org/s/software/OpenSSL_Decoder.html">Remy van Elst</a>. License: GNU AGPLv3. <a href="https://github.com/RaymiiOrg/ssl-decoder">Source code</a>. <strong><a href="https://cipherli.st/">Strong SSL Ciphers & Config settings @ Cipherli.st</a></strong>. Version: 2.1</p> - </div> - </div> - </div> - </div> - <?php - } - ?> - -<!-- Piwik --> -<script type="text/javascript"> - var _paq = _paq || []; - _paq.push(['trackPageView']); - _paq.push(['enableLinkTracking']); - (function() { - var u="//hosted-oswa.org/piwik/"; - _paq.push(['setTrackerUrl', u+'piwik.php']); - _paq.push(['setSiteId', 34]); - var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; - g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); - })(); -</script> -<noscript><p><img src="//hosted-oswa.org/piwik/piwik.php?idsite=34" style="border:0;" alt="" /></p></noscript> -<!-- End Piwik Code --> + // connection data + echo "<div class='content'><section id='conndata'>"; + echo "<header><h2>Connection Data for " . htmlspecialchars($host) . "</h2></header>"; + ssl_conn_metadata($data["data"]["connection"]); + echo "</section></div>"; + + // certificates + foreach ($data["data"]["chain"] as $key => $value) { + echo "<div class='content'><section id='cert" . $key . "'>"; + echo "<header><h2>Certificate for '". htmlspecialchars($value["cert_data"]["subject"]["CN"]) ."'</h2></header>"; + //pre_dump($value); + cert_parse($value); + echo "</section></div>"; + } + } + } elseif (!empty($_GET['csr']) && empty($host) ) { + $data = csr_parse_json($_GET['csr']); + echo "<p><strong>This tool does not make conclusions. Please check the data and define the validity yourself!</strong><br>\n </p>"; + $cache_filename = (string) "results/saved.csr." . $epoch . "." . $random_bla . ".html"; + if ($write_cache == 1) { + echo "This result is saved at most 60 days on <a href=\""; + echo(htmlspecialchars($current_folder) . $cache_filename); + echo "\">the following URL</a>. Do note that this might be deleted earlier if space runs out."; + } -<script> - - $(document).ready(function(){ - var aChildren = $("nav li").children(); // find the a children of the list items - var aArray = []; // create the empty aArray - for (var i=0; i < aChildren.length; i++) { - var aChild = aChildren[i]; - var ahref = $(aChild).attr('href'); - if(ahref && strStartsWith(ahref, "#") ) { - aArray.push(ahref); - } - } // this for loop fills the aArray with attribute href values - - $(window).scroll(function(){ - - var windowPos = $(window).scrollTop(); // get the offset of the window from the top of page - var windowHeight = $(window).height(); // get the height of the window - var docHeight = $(document).height(); - - for (var i=0; i < aArray.length; i++) { - var theID = aArray[i]; - var divPos = $(theID).offset().top; // get the offset of the div from the top of page - var divHeight = $(theID).height(); // get the height of the div in question - if (windowPos >= divPos && windowPos < (divPos + divHeight)) { - $("a[href='" + theID + "']").addClass("nav-active"); - } else { - $("a[href='" + theID + "']").removeClass("nav-active"); - } - } - - if(windowPos + windowHeight == docHeight) { - if (!$("nav li:last-child a").hasClass("nav-active")) { - var navActiveCurrent = $(".nav-active").attr("href"); - $("a[href='" + navActiveCurrent + "']").removeClass("nav-active"); - $("nav li:last-child a").addClass("nav-active"); - } - } - }); - }); + if (strpos($_GET['csr'], "BEGIN CERTIFICATE REQUEST") !== false) { + echo "<header><h2>CSR </h2></header><p>"; + csr_parse($data); + } else { + echo "<header><h2>Certificate </h2></header><p>"; + cert_parse($data); + } + } else { + echo "<span class='text-danger'> Host or Certificate required.</span>"; + echo "<hr>"; + $write_cache = 0; + } + } -</script> + + + ?> + </div> + </div> + </div> - </body> - </html> <?php +require_once("inc/footer.php"); + if ($write_cache == 1) { if (!file_exists($cache_filename)) { file_put_contents($cache_filename, ob_get_contents()); @@ -4,62 +4,6 @@ foreach (glob("functions/*.php") as $filename) { include $filename; } -function utf8encodeNestedArray($arr) { - // json_encode fails with binary data. utf-8 encode that first, some ca's like to encode images in their OID's (verisign, 1.3.6.1.5.5.7.1.12)... - $encoded_arr = array(); - foreach ($arr as $key => $value) { - if (is_array($value)) { - $encoded_arr[utf8_encode($key)] = utf8encodeNestedArray($value); - } else { - $encoded_arr[utf8_encode($key)] = utf8_encode($value); - } - } - return $encoded_arr; -} - -function check_json($host,$port) { - $data = []; - $stream = stream_context_create (array("ssl" => - array("capture_peer_cert" => true, - "capture_peer_cert_chain" => true, - "verify_peer" => false, - "verify_peer_name" => false, - "allow_self_signed" => true, - "capture_session_meta" => true, - "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); - if ( $read_stream === false ) { - $data["error"] = ["Failed to connect: " . htmlspecialchars($errstr)]; - return $data; - } else { - $context = stream_context_get_params($read_stream); - $context_meta = stream_context_get_options($read_stream)['ssl']['session_meta']; - $cert_data = openssl_x509_parse($context["options"]["ssl"]["peer_certificate"]); - $chain_data = $context["options"]["ssl"]["peer_certificate_chain"]; - $chain_length = count($chain_data); - if (isset($chain_data) && $chain_length < 10) { - $chain_length = count($chain_data); - $chain_arr_keys = ($chain_data); - foreach(array_keys($chain_arr_keys) as $key) { - $curr = $chain_data[$key]; - $next = $chain_data[$key+1]; - $prev = $chain_data[$key-1]; - $chain_key = (string)$key+1; - if ($key == 0) { - $data["connection"] = ssl_conn_metadata_json($host, $port, $read_stream, $chain_data); - $data["chain"][$chain_key] = cert_parse_json($curr, $next, false, $host, true); - } else { - $data["chain"][$chain_key] = cert_parse_json($curr, $next, false, null, false); - } - } - } else { - $data["error"] = ["Chain too long."]; - return $data; - } - } - return $data; -} - if ( isset($_GET['host']) && !empty($_GET['host'])) { $data = []; $hostname = mb_strtolower(get($_GET['host'])); |