DEV Community

James Moberg
James Moberg

Posted on

1

How to Check SSL Certificate using ColdFusion & CURL.exe

A CFML developer in the ColdFusion Programmers Facebook Group referenced my DEV article regarding how to identify the SSL expiration date using ColdFusion as they were encountering some issues and thought it may be due to the version of Java that was being using.

Here's a UDF that I wrote a couple years ago that leverages CURL (open source) to fetch & identify the current SSL certificate data in use.

I've added a resolveIp option so that you can override DNS lookup and bind the hostname to any IP so that both origin & WAF IP addresses can be tested. (Some web applications often have more than 1 IP address and both certificates should to be tested.)

There's also a useragent option to pass a custom user agent in case you require something specific to bypass security restrictions. (I recommend perform requests for static robots.txt files. Even if robots.txt doesn't exist, the "404 Not Found" message will return the error using the SSL connection and this is all that really matters.)

BTW: If you're going to CFSummit2023 in Las Vegas, come find me. I enjoy meeting other CFDevs. (The person that I usually talk about tech with is my .NET brother.)

result = checkSSLCertificate("https://www.adobe.com/robots.txt");

writedump(result);
Enter fullscreen mode Exit fullscreen mode

Image description

ColdFusion/CFML Source Code

Enjoy!

https://gist.github.com/JamoCA/fa7449d1f1a8b920d901b9b14a773e96

<!--- 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">
Retry later

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

Retry later