. function get_sans_from_csr($csr) { global $random_blurp; global $timeout; //openssl_csr_get_subject doesn't support SAN names. $filename = "/tmp/csr-" . $random_blurp . "-" . gen_uuid() . ".csr.pem"; $write_csr = file_put_contents($filename, $csr); if($write_csr !== FALSE) { $openssl_csr_output = trim(shell_exec("timeout " . $timeout . " openssl req -noout -text -in " . $filename . " | grep -e 'DNS:' -e 'IP:'")); } unlink($filename); if($openssl_csr_output) { $sans = array(); $csr_san_dns = explode("DNS:", $openssl_csr_output); $csr_san_ip = explode("IP:", $openssl_csr_output); if(count($csr_san_dns) > 1) { foreach ($csr_san_dns as $key => $value) { if($value) { $san = trim(str_replace(",", "", str_replace("DNS:", "", $value))); array_push($sans, $san); } } } if(count($csr_san_ip) > 1) { foreach ($csr_san_ip as $key => $value) { if($value) { $san = trim(str_replace(",", "", str_replace("IP:", "", $value))); array_push($sans, $san); } } } } if(count($sans) >= 1) { return $sans; } } function csr_parse($data) { //parses the json data from csr_parse_json() to a nice html page. echo ""; echo ""; echo ""; echo ""; foreach ($data['subject'] as $key => $value) { echo "\n"; } if($data['csr_sans']) { echo ""; } echo ""; echo ""; echo "
Certificate Signing Request Data
"; 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 ""; switch ($key) { case 'C': echo htmlspecialchars($value); echo ' '; 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 "
Subject Alternative Names
    "; foreach ($data['csr_sans'] as $key => $value) { echo "
  • "; echo htmlspecialchars($value); echo "
  • "; } echo "
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 ")
";
  echo htmlspecialchars($data['details']['key']);
  echo "
CSR PEM
";
  echo htmlspecialchars($data['csr_pem']);
  echo "
"; } function cert_parse($data) { //parses the json data from cert_parse_json() to a nice html page. //does output formatting based on some parts, like red if cert expired. if (is_array($data["warning"]) && count($data["warning"]) >= 1) { $data["warning"] = array_unique($data["warning"]); if (count($data["warning"]) == 1) { echo "

" . count($data["warning"]) . " warning!

"; } else { echo "

" . count($data["warning"]) . " warnings!

"; } foreach ($data["warning"] as $key => $value) { echo ""; } } echo ""; echo ""; echo ""; echo ""; $today = date("Y-m-d"); echo ""; if (!empty($data['cert_data']['subject']) ) { foreach ($data['cert_data']['subject'] as $key => $value) { echo ""; echo ""; } } // san if (!empty($data['cert_data']['extensions']['subjectAltName'])) { echo ""; echo ""; echo ""; echo ""; } // validation type echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; if (!empty($data['cert_data']['issuer']) ) { foreach ($data['cert_data']['issuer'] as $key => $value) { echo ""; echo ""; } } // valid from echo ""; echo ""; echo ""; if ( !empty($data['cert_data']['validFrom_time_t']) ) { echo ""; echo ""; echo ""; echo ""; } // issued to expired if ( !empty($data['cert_data']['validTo_time_t']) ) { echo ""; echo ""; echo ""; echo ""; }; if ( is_array($data['crl']) ) { echo ""; echo ""; echo ""; echo ""; } else { echo ""; } // ocsp if ( is_array($data['ocsp'])) { echo ""; echo ""; echo ""; } else { echo ""; } } if(!empty($_GET['host'])) { echo ""; echo ""; echo ""; echo ""; } // details echo ""; echo ""; echo ""; if ( !empty($data['cert_data']['purposes']) ) { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } // serial number if (!empty($data['serialNumber']) ) { echo ""; echo ""; echo ""; echo ""; } echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; if ($data["key"]["weak_debian_rsa_key"] == 1) { echo ""; } else { echo ""; } echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; if ($_GET['fastcheck'] == 0 && !empty($_GET['host'])) { echo ""; echo ""; echo ""; echo ""; } if (count($data['cert_data']['extensions']) >= 1) { echo ""; echo ""; echo ""; echo ""; } else { echo ""; echo ""; echo ""; echo ""; } if(!empty($data["key"]["certificate_pem"])) { echo ""; echo ""; echo ""; echo ""; } if(!empty($data['key']['public_key_pem'])) { echo ""; echo ""; echo ""; echo ""; // correct chain if (is_array($data["correct_chain"]["chain"])) { echo ""; echo ""; echo ""; echo ""; } echo ""; echo ""; echo ""; echo ""; } echo ""; echo "
Certificate Data
\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n\n\n"; // hostname validation if ($data["hostname_in_san_or_cn"] == "true") { echo ''; } elseif ($data["hostname_in_san_or_cn"] == "false") { echo ''; } elseif ($data["hostname_in_san_or_cn"] == "n/a; ca signing certificate") { echo ""; } else { echo ""; } // 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 ''; } else { echo ''; } // issuer if (!empty($data["issuer_valid"])) { if ($data["issuer_valid"] == true) { echo ''; } else { echo ''; } } else { echo ''; } // crl if ( !empty($data['crl'][1]['status']) ) { if ($data['crl'][1]['status'] == "ok") { echo ""; } else { echo ''; } } else { echo ''; } // ocsp if (!empty($data['ocsp'][1]['ocsp_uri'])) { echo ""; } else { echo ""; } // 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 ''; } else if (strpos($data['cert_data']['extensions']['basicConstraints'], "CA:TRUE") !== false) { echo ''; } else if ($data['cert_data']['issuer']['CN'] == $data['cert_data']['subject']['CN']) { echo ''; } else { echo ""; } echo ""; echo "
HostnameNot ExpiredIssuerCRLOCSPSigning Type

 

 

 

 

 

 

 

 

 

"; if ($data['ocsp'][1]["status"] == "good") { echo '

 

'; } else if ($data['ocsp'][1]["status"] == "revoked") { echo '

 

'; } else { echo '

 

'; } echo "
CA Root CertificateCA CertificateSelf SignedSigned by CA
"; echo "
"; 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 ""; switch ($key) { case 'C': echo htmlspecialchars($value); echo ' '; 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 "
Subject Alternative Names"; foreach ( explode("DNS:", $data['cert_data']['extensions']['subjectAltName']) as $altName ) { if ( !empty(str_replace(',', " ", "$altName"))) { echo ""; echo htmlspecialchars(str_replace(',', " ", "$altName")); echo "
"; } } echo "
Type"; if ($data["validation_type"] == "extended") { echo 'Extended Validation'; } elseif ($data["validation_type"] == "organization") { echo "Organization Validation"; } elseif ($data["validation_type"] == "domain") { echo "Domain Validation"; } // full subject echo "
Full Subject"; echo htmlspecialchars($data['cert_data']['name']); echo "
Issuer
"; 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 ""; switch ($key) { case 'C': echo htmlspecialchars($value); echo ' '; 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 "
Validity
Valid From"; if ( $today < date(DATE_RFC2822,$data['cert_data']['validFrom_time_t']) ) { echo ''; echo ' - '; } else { echo ''; echo ' - '; } echo htmlspecialchars(date(DATE_RFC2822,$data['cert_data']['validFrom_time_t'])); echo ""; echo "
Valid Until"; if ( strtotime($today) < strtotime(date(DATE_RFC2822,$data['cert_data']['validTo_time_t'])) ) { echo ''; echo ' - '; } else { echo ''; echo ' - '; } echo htmlspecialchars(date(DATE_RFC2822,$data['cert_data']['validTo_time_t'])); echo ""; echo "
CRL"; foreach ($data['crl'] as $key => $value) { if ($value) { if ($value["status"] == "ok") { echo ""; echo " - Not on CRL: " . htmlspecialchars($value["crl_uri"]) . "
"; echo "Last update: " . htmlspecialchars($value['crl_last_update']) . "
\n"; echo "Next update: " . htmlspecialchars($value['crl_next_update']) . "
\n"; } elseif ($value["status"] == "revoked") { echo ""; echo " - Revoked on CRL: " . htmlspecialchars($value["crl_uri"]) . "
\n"; echo "Revocation date: " . htmlspecialchars($value["revoked_on"]) . "
\n"; echo "
Last update: " . htmlspecialchars($value['crl_last_update']) . "
\n"; echo "Next update: " . htmlspecialchars($value['crl_next_update']) . "
\n"; } else { echo ""; echo " - CRL invalid: (" . htmlspecialchars($value["crl_uri"]) . ")
"; echo "
 " . htmlspecialchars($value["error"]) . "
"; } } if (count($data['ocsp']) > 1) { echo "
"; } } echo "
CRLNo CRL URI found in certificate
OCSP"; foreach ($data['ocsp'] as $key => $value) { if ($value) { if ($value["status"] == "good") { echo ' '; echo ' - OK: '; echo htmlspecialchars($value['ocsp_uri']); echo "
"; echo "Last update: " . htmlspecialchars($value["this_update"]) . "
\n"; echo "Next update: " . htmlspecialchars($value["next_update"]) . "
\n"; } else if ( $value["status"] == "revoked") { echo ''; echo ' - REVOKED: '; echo htmlspecialchars($value['ocsp_uri']); echo "
"; echo "Revocation Time: " . htmlspecialchars($value["revocation_time"]) . "
\n"; echo "Revocation Reason: " . htmlspecialchars($value["reason"]). "

"; echo "
Last update: " . htmlspecialchars($value["this_update"]) . "
\n"; echo "Next update: " . htmlspecialchars($value["next_update"]) . "
\n"; } else { echo ''; echo ' - UNKNOWN: '; echo " - " . htmlspecialchars($value['ocsp_uri']) . "
"; echo "
" . htmlspecialchars($value["error"]) . "
"; } } if (count($data['ocsp']) > 1) { echo "
"; } } } else { if ($data["ocsp"] == "No issuer cert provided. Unable to send OCSP request.") { echo "
OCSPNo issuer certificate provided. Unable to send OCSP request.
OCSPNo OCSP URI found in certificate
Hostname Validation"; // hostname validation if ($data["hostname_in_san_or_cn"] == "true") { echo "\n - "; echo htmlspecialchars($data['hostname_checked']); echo " found in CN or SAN."; } elseif ($data["hostname_in_san_or_cn"] == "false") { echo ' - '; echo htmlspecialchars($data['hostname_checked']); echo ' NOT found in CN or SAN.'; } 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 "
Details
Purposes"; foreach ($data['cert_data']['purposes'] as $key => $purpose) { if ($purpose["general"]) { echo htmlspecialchars($key); echo " "; } } echo "
Purposes CA"; foreach ($data['cert_data']['purposes'] as $key => $purpose) { if ($purpose["ca"]) { echo htmlspecialchars($key); echo " "; } } echo "
Serial"; echo "" . htmlspecialchars($data['serialNumber']) . ""; echo "
Key Size / Type"; // key details echo htmlspecialchars($data["key"]['bits']); echo " bits "; echo htmlspecialchars($data["key"]['type']); echo "
"; echo "Weak debian key"; echo ""; echo " - This is a weak debian key. Replace it as soon as possible."; echo ""; echo "This is not a weak debian key."; echo "
Signature Algorithm"; echo $data["key"]["signature_algorithm"]; echo "
Hashes"; echo ""; foreach ($data["hash"] as $key => $value) { echo ""; } echo "
"; echo htmlspecialchars(strtoupper($key)); echo ""; echo wordwrap(htmlspecialchars($value), 64, "
\n", TRUE); echo "
"; echo "
TLSA DNS "; if($data['tlsa']['error'] == 'none' && !empty($data['tlsa'])) { echo ""; foreach ($data["tlsa"] as $key => $value) { switch ($key) { case 'tlsa_hash': echo ""; break; case 'tlsa_usage': echo ""; } if ($data['tlsa']['tlsa_matching_type'] == "1" || $data['tlsa']['tlsa_matching_type'] == 2) { echo "
Record Data" . htmlspecialchars($value) . "
Usage"; switch ($value) { case '0': echo "0: PKIX-TA: Certificate Authority Constraint"; break; case '1': echo "1: PKIX-EE: Service Certificate Constraint"; break; case '2': echo "2: DANE-TA: Trust Anchor Assertion"; break; case '3': echo "3: DANE-EE: Domain Issued Certificate"; break; default: echo " - Incorrect usage parameter: ". htmlspecialchars($value) . ""; break; } break; case 'tlsa_selector': echo "
Selector"; switch ($value) { case '0': echo "0: Cert: Use full certificate"; break; case '1': echo "1: SPKI: Use subject public key"; break; default: echo " - Incorrect selector parameter: ". htmlspecialchars($value) . ""; break; } break; case 'tlsa_matching_type': echo "
Matching Type"; switch ($value) { case '0': echo "0: Full: No Hash"; break; case '1': echo "1: SHA-256 hash"; break; case '2': echo "2: SHA-512 hash"; break; default: echo " - Incorrect matching type parameter: ". htmlspecialchars($value) . ""; break; } break; } echo "
DNS Hash Matches Certificate Hash"; if($data['tlsa']['tlsa_matching_type'] == '1') { echo "SHA 256 "; if ($data['tlsa']['tlsa_hash'] == $data['hash']['sha256']) { echo " - Hash match"; } else { echo " - Hash does not match"; } } if($data['tlsa']['tlsa_matching_type'] == '2') { echo "SHA 512 "; if ($data['tlsa']['tlsa_hash'] == $data['hash']['sha512']) { echo " Hash match"; } else { echo " - Hash does not match"; } } } echo "
"; } else { echo "

"; echo htmlspecialchars($data['tlsa']['error']); if($data['tlsa']['example']) { echo "Here's an example TLSA record based on this certificate's SHA-256 hash:

";
        echo htmlspecialchars($data['tlsa']['example']);
        echo "

"; } } echo "

Please note that the DNSSEC chain is not validated. The status of the DNSSEC signature will not show up here.
More information about TLSA and DNSSEC. - Simple TLSA record generator here."; echo "

Extensions"; ?>
$extension) { if ( !empty(str_replace(',', " ", "$extension"))) { echo "" . htmlspecialchars("$name") . ""; echo "
";
                echo htmlspecialchars($extension);
                echo "
"; } } echo "
"; echo "
"; echo "
"; echo "
"; echo "
Extensions"; echo "None"; echo "
Certificate PEM "; ?>
"; echo htmlspecialchars($data["key"]["certificate_pem"]); echo ""; echo "
"; echo "
"; echo "
"; echo "
"; echo "
Public Key PEM "; ?>
"; echo htmlspecialchars($data['key']['public_key_pem']); echo ""; echo "
"; echo "
"; echo "
"; echo "
"; echo "
Certificate Chain"; echo "

We've constructed the certificate chain in the correct order of this certificate based on the 'authorityInfoAccess' extension and earlier saved certificates. The result also contains this certificate as the first one.
"; echo "

This is our best guess at the correct CA Chain:

    "; foreach ($data['correct_chain']['cns'] as $cn_key => $cn_value) { foreach ($cn_value as $cnn_key => $cnn_value) { echo "
  • "; if($cnn_key == 'cn') { echo "Name.......: "; echo htmlspecialchars($cnn_value); echo "
  • "; } if ($cnn_key == 'issuer') { echo "Issued by..: "; echo htmlspecialchars($cnn_value); echo "
    "; } } } echo "

"; echo "

Click below to see the full chain output in PEM format, copy-pastable in most software.

"; ?>
"; foreach ($data['correct_chain']['chain'] as $cert) { echo htmlspecialchars($cert); echo "
"; } echo ""; echo "
"; echo "
"; echo "
"; echo "
"; echo "
SPKI Hash"; print("" . htmlspecialchars($data['key']['spki_hash']) . ""); echo "
"; } function cert_parse_json($raw_cert_data, $raw_next_cert_data=null, $host=null, $validate_hostname=false, $port="443", $include_chain=null) { global $random_blurp; global $ev_oids; global $timeout; $result = array(); $cert_data = openssl_x509_parse($raw_cert_data); if (isset($raw_next_cert_data)) { $next_cert_data = openssl_x509_parse($raw_next_cert_data); } $today = date("Y-m-d"); //cert if (isset($cert_data) ) { // purposes $purposes = array(); foreach ($cert_data['purposes'] as $key => $purpose) { $purposes[$purpose[2]]["ca"] = $purpose[1]; $purposes[$purpose[2]]["general"] = $purpose[0]; } unset($cert_data['purposes']); $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']); } } // almost expired if (!empty($cert_data['validTo_time_t'])) { $certExpiryDate = strtotime(date(DATE_RFC2822,$cert_data['validTo_time_t'])); $certExpiryDiff = $certExpiryDate - strtotime($today); if ($certExpiryDiff < 2592000) { $result['cert_expires_in_less_than_thirty_days'] = true; $result['warning'][] = "Certificate expires in " . round($certExpiryDiff / 84600) . " days!. Expiration date: " . date(DATE_RFC2822,$certExpiryDate); } else { $result['cert_expires_in_less_than_thirty_days'] = false; } } 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"] = "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'])) { $ocsp_uris = explode("OCSP - URI:", $cert_data['extensions']['authorityInfoAccess']); unset($ocsp_uris[0]); 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"; } } else { $result["ocsp"] = "No OCSP URI found in certificate"; } // 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 number if ( isset($cert_data['serialNumber']) ) { $serial = []; $sn = str_split(strtoupper(bcdechex($cert_data['serialNumber'])), 2); $sn_len = count($sn); foreach ($sn as $key => $s) { $serial[] = htmlspecialchars($s); if ( $key != $sn_len - 1) { $serial[] = ":"; } } $result["serialNumber"] = implode("", $serial); } // key details $key_details = openssl_pkey_get_details(openssl_pkey_get_public($raw_cert_data)); $export_pem = ""; openssl_x509_export($raw_cert_data, $export_pem); // save pem. this because the reconstruct chain function works better // this way. not all certs have authorityinfoaccess. We first check if // we already have a matching cert. if (!is_dir('crt_hash')) { mkdir('crt_hash'); } // filenames of saved certs are hashes of the asort full subject. $sort_subject = $cert_data['subject']; asort($sort_subject); foreach ($sort_subject as $key => $value) { $name_full = "/" . $key . "=" . $value . $name_full; } $crt_hash = hash("sha256", $name_full); $crt_hash_folder = "crt_hash/"; $crt_hash_file = $crt_hash_folder . $crt_hash . ".pem"; if(file_exists($crt_hash_file)) { if (time()-filemtime($crt_hash_file) > 5 * 84600) { // file older than 5 days. crt might have changed, retry. $content_hash = sha1_file($crt_hash_file); rename($crt_hash_file, $crt_hash_folder . $content_hash . "content_hash_save.pem"); file_put_contents($crt_hash_file, $export_pem); } } else { file_put_contents($crt_hash_file, $export_pem); } if(stat($crt_hash_file)['size'] < 10 ) { //probably a corrupt file. sould be at least +100KB. unlink($crt_hash_file); } //chain reconstruction if($include_chain && $raw_cert_data) { $return_chain = array(); $export_pem = ""; openssl_x509_export($raw_cert_data, $export_pem); $crt_cn = openssl_x509_parse($raw_cert_data)['name']; $export_pem = "#start " . $crt_cn . "\n" . $export_pem . "\n#end " . $crt_cn . "\n"; array_push($return_chain, $export_pem); $certificate_chain = array(); $issuer_crt = get_issuer_chain($raw_cert_data); if (count($issuer_crt['certs']) >= 1) { $issuercrts = array_unique($issuer_crt['certs']); foreach ($issuercrts as $key => $value) { array_push($return_chain, $value); } } $return_chain = array_unique($return_chain); if(count($return_chain) > 1) { $result["correct_chain"]["cns"] = array(); $crt_cn = array(); foreach ($return_chain as $retc_key => $retc_value) { $issuer_full = ""; $subject_full = ""; $sort_issuer = openssl_x509_parse($retc_value)['issuer']; $sort_subject = openssl_x509_parse($retc_value)['subject']; asort($sort_subject); foreach ($sort_subject as $sub_key => $sub_value) { $subject_full = "/" . $sub_key . "=" . $sub_value . $subject_full; } asort($sort_issuer); foreach ($sort_issuer as $iss_key => $iss_value) { $issuer_full = "/" . $iss_key . "=" . $iss_value . $issuer_full; } $crt_cn['cn'] = $subject_full; $crt_cn['issuer'] = $issuer_full; array_push($result["correct_chain"]["cns"], $crt_cn); } $result["correct_chain"]["chain"] = $return_chain; } } //hashes $string = $export_pem; $pattern = '/-----(.*)-----/'; $replacement = ''; $string = preg_replace($pattern, $replacement, $string); $pattern = '/\n/'; $replacement = ''; $export_pem_preg = preg_replace($pattern, $replacement, $string); $export_pem_preg = wordwrap($export_pem_preg, 77, "\n", TRUE); $result['hash']['md5'] = cert_hash('md5', $export_pem_preg); $result['hash']['sha1'] = cert_hash('sha1', $export_pem_preg); $result['hash']['sha256'] = cert_hash('sha256', $export_pem_preg); $result['hash']['sha384'] = cert_hash('sha384', $export_pem_preg); $result['hash']['sha512'] = cert_hash('sha512', $export_pem_preg); //TLSA check if (!empty($cert_data['subject']['CN']) && !empty($host)) { if ($validate_hostname == true) { $tlsa_record = shell_exec("timeout " . $timeout . " dig +short +dnssec +time=" . $timeout . " TLSA _" . escapeshellcmd($port) . "._tcp." . escapeshellcmd($host) . " 2>&1 | head -n 1"); if (!empty($tlsa_record)) { $tlsa = explode(" ", $tlsa_record, 4); $pattern = '/ /'; $replacement = ''; $result['tlsa']['tlsa_hash'] = trim(strtolower(preg_replace($pattern, $replacement, $tlsa[3]))); $result['tlsa']['tlsa_usage'] = $tlsa[0]; $result['tlsa']['tlsa_selector'] = $tlsa[1]; $result['tlsa']['tlsa_matching_type'] = $tlsa[2]; $result['tlsa']['error'] = 'none'; } else { $result['tlsa']['error'] = 'No TLSA record found.'; $result['tlsa']['example'] = '_'. htmlspecialchars($port) . '._tcp.' . htmlspecialchars($host) . ' IN TLSA 3 0 1 ' . $result['hash']['sha256'] . ';'; } } else { $result['tlsa']['error'] = 'CA certificate, TLSA not applicable.'; } } 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."; } // weak debian key check $bin_modulus = $key_details['rsa']['n']; # blacklist format requires sha1sum of output from "openssl x509 -noout -modulus" including the Modulus= and newline. # create the blacklist: # https://packages.debian.org/source/squeeze/openssl-blacklist # svn co svn://svn.debian.org/pkg-openssl/openssl-blacklist/ # find openssl-blacklist/trunk/blacklists/ -iname "*.db" -exec cat {} >> unsorted_blacklist.db \; # sort -u unsorted_blacklist.db > debian_blacklist.db $mod_sha1sum = sha1("Modulus=" . strtoupper(bin2hex($bin_modulus)) . "\n"); $blacklist_file = fopen('inc/debian_blacklist.db', 'r'); $key_in_blacklist = false; while (($buffer = fgets($blacklist_file)) !== false) { if (strpos($buffer, $mod_sha1sum) !== false) { $key_in_blacklist = true; break; } } fclose($blacklist_file); if ($key_in_blacklist == true) { $result["key"]["weak_debian_rsa_key"] = "true"; $result['warning'][] = "Weak debian key found. Remove this key right now and create a new one."; } } else if (isset($key_details['dsa'])) { $result["key"]["type"] = "dsa"; $result["key"]["bits"] = $key_details['bits']; } else if (isset($key_details['dh'])) { $result["key"]["type"] = "dh"; $result["key"]["bits"] = $key_details['bits']; } else if (isset($key_details['ec'])) { $result["key"]["type"] = "ecdsa"; $result["key"]["bits"] = $key_details['bits']; } else { $result["key"]["type"] = "unknown"; $result["key"]["bits"] = $key_details['bits']; } // 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; } if(isset($key_details['key'])) { $result["key"]["public_key_pem"] = $key_details['key']; $result["key"]["spki_hash"] = spki_hash($export_pem); } return $result; } function csr_parse_json($csr) { //if csr or cert is pasted in form tis function parses the csr or it send the cert to cert_parse. global $random_blurp; global $timeout; $result = array(); if (strpos($csr, "BEGIN CERTIFICATE REQUEST") !== false) { $cert_data = openssl_csr_get_public_key($csr); $cert_details = openssl_pkey_get_details($cert_data); $cert_key = $cert_details['key']; $cert_subject = openssl_csr_get_subject($csr); $result["subject"] = $cert_subject; $result["key"] = $cert_key; $result["details"] = $cert_details; if ($cert_details) { $result["csr_pem"] = $csr; $sans = get_sans_from_csr($csr); if(count($sans) > 1) { $result["csr_sans"] = $sans; } } } elseif (strpos($csr, "BEGIN CERTIFICATE") !== false) { $result = cert_parse_json($csr, null, null, null, null, true); } else { $result = array("error" => "data not valid csr"); } return $result; } ?>