Last active
September 28, 2023 21:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--- 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