Skip to content

Instantly share code, notes, and snippets.

@JamoCA
Last active September 28, 2023 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamoCA/fa7449d1f1a8b920d901b9b14a773e96 to your computer and use it in GitHub Desktop.
Save JamoCA/fa7449d1f1a8b920d901b9b14a773e96 to your computer and use it in GitHub Desktop.
CheckSSLCertificate UDF - Using ColdFusion & CURL to connect to remote HOST to identify SSL data (start/end dates, subject, subjectAltName, issuer & status) #cfml
<!--- checkSSLCertificate UDF - I use ColdFusion & CURL to connect to remote HOST to identify SSL data (start/end dates, subject, subjectAltName, issuer & status) #cfml
GIST: https://gist.github.com/JamoCA/fa7449d1f1a8b920d901b9b14a773e96
BLOG: https://dev.to/gamesover/how-to-check-ssl-certificate-using-coldfusion-curlexe-2c92
TWITTER: https://twitter.com/gamesover/status/1707506769466216593
NOTE: This UDF requires CURL. https://curl.se/
--->
<cfscript>
struct function checkSSLCertificate(required string targetUrl, string userAgent="", string resolveIp="", string exePath="", boolean debug=false) output=false hint="I use CURL to connect to remote HOST to identify SSL data (start/end dates, subject, subjectAltName, issuer & status)" {
arguments.exePath = (len(arguments.exePath)) ? arguments.exePath : "C:\CURL\CURL.exe"; // set to default CURL exe path
arguments.useAgent = (len(arguments.userAgent)) ? arguments.userAgent : "FireFox 13|Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1";
local.errorCodes = ["1": "UNSUPPORTED_PROTOCOL", "2": "FAILED_INIT", "3": "URL_MALFORMAT", "4": "NOT_BUILT_IN", "5": "COULDNT_RESOLVE_PROXY", "6": "COULDNT_RESOLVE_HOST", "7": "COULDNT_CONNECT", "8": "FTP_WEIRD_SERVER_REPLY", "9": "REMOTE_ACCESS_DENIE", "10": "FTP_ACCEPT_FAILED", "11": "FTP_WEIRD_PASS_REPLY", "12": "FTP_ACCEPT_TIMEOUT", "13": "FTP_WEIRD_PASV_REPLY", "14": "FTP_WEIRD_227_FORMAT", "15": "FTP_CANT_GET_HOST", "16": "HTTP2", "17": "FTP_COULDNT_SET_TYPE", "18": "PARTIAL_FILE", "19": "FTP_COULDNT_RETR_FILE", "21": "QUOTE_ERROR", "22": "HTTP_RETURNED_ERROR", "23": "WRITE_ERROR", "25": "UPLOAD_FAILED", "26": "READ_ERROR", "27": "OUT_OF_MEMORY", "28": "OPERATION_TIMEDOUT", "30": "FTP_PORT_FAILED", "31": "FTP_COULDNT_USE_REST", "33": "RANGE_ERROR", "34": "HTTP_POST_ERROR", "35": "SSL_CONNECT_ERROR", "36": "BAD_DOWNLOAD_RESUME", "37": "FILE_COULDNT_READ_FILE", "38": "LDAP_CANNOT_BIND", "39": "LDAP_SEARCH_FAILED", "41": "FUNCTION_NOT_FOUND", "42": "ABORTED_BY_CALLBACK", "43": "BAD_FUNCTION_ARGUMENT", "45": "INTERFACE_FAILED", "47": "TOO_MANY_REDIRECTS", "48": "UNKNOWN_OPTION", "49": "TELNET_OPTION_SYNTAX", "51": "PEER_FAILED_VERIFICATION", "52": "GOT_NOTHING", "53": "SSL_ENGINE_NOTFOUND", "54": "SSL_ENGINE_SETFAILED", "55": "SEND_ERROR", "56": "RECV_ERROR", "58": "SSL_CERTPROBLEM", "59": "SSL_CIPHER", "60": "SSL_CACERT", "61": "BAD_CONTENT_ENCODING", "62": "LDAP_INVALID_URL", "63": "FILESIZE_EXCEEDED", "64": "USE_SSL_FAILED", "65": "SEND_FAIL_REWIND", "66": "SSL_ENGINE_INITFAILED", "67": "LOGIN_DENIED", "68": "TFTP_NOTFOUND", "69": "TFTP_PERM", "70": "REMOTE_DISK_FULL", "71": "TFTP_ILLEGAL", "72": "TFTP_UNKNOWNID", "73": "REMOTE_FILE_EXISTS", "74": "TFTP_NOSUCHUSER", "75": "CONV_FAILED", "76": "CONV_REQD", "77": "SSL_CACERT_BADFILE", "78": "REMOTE_FILE_NOT_FOUND", "79": "SSH", "80": "SSL_SHUTDOWN_FAILED", "81": "AGAIN", "82": "SSL_CRL_BADFILE", "83": "SSL_ISSUER_ERROR", "84": "FTP_PRET_FAILED", "85": "RTSP_CSEQ_ERROR", "86": "RTSP_SESSION_ERROR", "87": "FTP_BAD_FILE_LIST", "88": "CHUNK_FAILED", "89": "NO_CONNECTION_AVAILABLE", "90": "SSL_PINNEDPUBKEYNOTMATCH", "91": "SSL_INVALIDCERTSTATUS", "92": "HTTP2_STREAM", "93": "RECURSIVE_API_CALL", "94": "AUTH_ERROR", "95": "HTTP3", "96": "QUIC_CONNECT_ERROR"];
local.result = [
"ssl": [:]
,"duration": javacast("int", 0)
,"headers": [
"ip": "0.0.0.0"
,"status": javacast("int", 0)
]
,"args": [
"arguments": arguments
,"params": "-s -verbose"
,"isValidURL": isvalid("url", arguments.targetUrl)
]
,"raw": ""
];
if (len(arguments.resolveIp) && refindnocase("^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)", arguments.resolveIp)) {
local.port = "80";
local.hostname = listgetat(arguments.targetUrl, 2, "/");
if (findnocase("https://", arguments.targetUrl)) {
local.port = "443";
}
local.result.args.params = local.result.args.params & " --resolve #local.hostname#:#local.port#:#arguments.resolveIp#";
}
local.result.args.params = local.result.args.params & " -A ""#arguments.userAgent#"" #listfirst(arguments.targetUrl,'?')#";
if (find("?", arguments.targetUrl)) {
local.result.args.params = local.result.args.params & " -d """ & listrest(arguments.targetUrl, "?") & """";
}
local.result.args.params = local.result.args.params & " --stderr - 2>&1";
local.timeStart = gettickcount();
if (local.result.args.isValidURL) {
cfexecute(arguments=local.result.args.params, variable="local.result.Raw", name=arguments.exePath, timeout=15);
local.result.duration = javacast("int", gettickcount() - local.timeStart);
for (local.thisLine in listtoarray(local.result.Raw, chr(13) & chr(10))) {
if (left(trim(local.thisLine), 2) eq "< " && listlen(trim(local.thisLine), ":") gte 2) {
local.result.headers["#listrest(trim(listfirst(local.thisLine, ":")), " ")#"] = trim(listrest(local.thisLine, ":"));
} else if (left(trim(local.thisLine), 6) eq "< HTTP") {
local.result.headers["Status"] = trim(listrest(listrest(trim(local.thisLine), " "), " "));
} else if (left(trim(local.thisLine), 10) eq "* Trying") {
local.result.headers["IP"] = trim(listLast(listfirst(trim(local.thisLine), ":"), " "));
} else if (left(trim(local.thisLine), 14) eq "* Connected to") {
local.result.headers["IP"] = trim(listrest(listfirst(trim(local.thisLine), ")"), "("));
} else if (left(trim(local.thisLine), 6) eq "curl: ") {
if (!local.result.keyExists("error")) {
local.result["error"] = [:];
}
local.result.error["message"] = trim(listrest(local.thisline, ":"));
local.result.error["id"] = javacast("int", 0);
local.result.error["code"] = "";
if (find("(", local.result.error.message) && find(")", local.result.error.message)) {
local.result.error.id = javacast("int", listfirst(local.result.error.message, " ").replaceAll("\D", ""));
local.result.error.message = trim(listrest(local.result.error.message, " "));
if (local.errorCodes.keyExists("#local.result.error.id#")) {
local.result.error.code = local.errorCodes["#local.result.error.id#"];
}
}
} else if (left(trim(local.thisLine), 19) eq "More Details here: ") {
if (!local.result.keyExists("error")) {
local.result["error"] = [:];
}
local.result.error["details"] = trim(listrest(local.thisline, ":"));
} else if (left(trim(local.thisLine), 3) eq "* ") {
if (listlen(trim(local.thisLine), ":") gte 2) {
local.result.ssl["#trim(replace(listrest(trim(listfirst(local.thisLine, ":")), " "), " ", "_", "all"))#"] = trim(listrest(local.thisLine, ":"));
} else {
local.result.ssl["status"] = trim(listrest(trim(local.thisLine), " "));
}
}
}
local.result.headers.ip = local.result.headers.ip.replaceAll("\.\.\.", "");
for (local.keyname in local.result.ssl) {
if (isdate(local.result.ssl["#local.keyname#"].replaceAll("\s\d+:\d+:\d+\s", " ").replaceAll(" GMT", ""))) {
local.result.ssl["#local.keyname#"] = dateformat(local.result.ssl["#local.keyname#"].replaceAll("\s\d+:\d+:\d+\s", " ").replaceAll(" GMT", ""), "yyyy-mm-dd");
}
}
} else {
local.result.headers.status = javacast("int", 0);
local.result.error = [
"message": "Invalid URL"
,"id": javacast("int", 0)
,"code": "INVALID_URL"
];
}
if (!arguments.debug) {
structdelete(local.result, "headers");
structdelete(local.result, "args");
structdelete(local.result, "raw");
}
return local.result;
}
</cfscript>
<cfset result = CheckSSLCertificate(targetURL="https://www.coldfusion.com/robots.txt", debug=true)>
<cfdump var="#result#" label="CheckSSLCertificate UDF Results">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment