ID SSL_CERT_EXPIRY.NASL Type nessus Reporter This script is Copyright (C) 2004-2020 George A. Theall Modified 2004-12-03T00:00:00
Description
This plugin checks expiry dates of certificates associated with SSL-
enabled services on the target and reports whether any have already
expired.
#TRUSTED ac8aeee04d38ce931cd0c24a8003e0ed67efd176b56524d2a20350e174ae986b3113696f92aaf0bb53900e44cea006b5ff122033f379ce99542f36d63eaf9d5be20209f19366dc40bcdbcab600ad04cd46dfb56ac0a2319606e7a46afd08f72c8bf580c88f9246a64f96471c92bc8c9bf0a4e644b6d97ba897ca443ed9b9f20d558c58622488216a49c2c0b56efc8f5c9f9bf223a44eab81cf66746ca30a5df26354dc473f38624d4d039a1538a8a331b3a5d0f02437f539e86b7efa1415c3711210f2909e5fbefb760e94ee6b91e29a27606943963cc676b0b346000c0e9b96fba449ab41327325ec2160a739b95ffe3a5b1f0c7076c9f60c5e2761ecbd9384341b9bebdaf445c9d931e1936e1ddb2133e86dd0d51b72e9b50abdcd339f1b512d7e5e4048fcf485545ce8462c3f45e72da196dbf0ab9c03110d157aeeb45b30634a9323f02f081beb4d5f4eab3c1b38c9e4562b204c538267391b7ff2356d72cf7244a43a84f0795c581660eca8b304ed15a356e771bab43f38dac891d8a2b5767770194c9768192f6dbd19874ca5a286289019419e1703094e080cd6dff6de0daa144f23406d9b11518fe047fc81ac77d8898f734696907e0144da6391480ded259ea1488be56624c44b6707c769e870797cdd229960f29bd640d4280b0ffbf7a9fe40c5b5bf22d7eb1c48c027d7d3dd9a8bef1e0a8b67e3794b7bd6ea39d3
#
# @PREFERENCES@
#
# This script was written by George A. Theall, <theall@tifaware.com>.
#
# See the Nessus Scripts License for details.
#
# Changes by Tenable :
# - Updated to use compat.inc, made report severity consistent (11/23/09)
# - Added CVSS score, KBs. (11/23/09)
# - Signed. (10/18/2013)
# - Made expiration warning period user-configurable. (05/12/15)
# - Added rsync. (2016/01/07)
if ( ! defined_func("localtime") ) exit(0);
include("compat.inc");
if (description)
{
script_id(15901);
script_version("1.48");
script_set_attribute(attribute:"plugin_modification_date", value:"2020/06/12");
script_name(english:"SSL Certificate Expiry");
script_summary(english:"Checks the SSL certificate expiry.");
script_set_attribute(attribute:"synopsis", value:
"The remote server's SSL certificate has already expired.");
script_set_attribute(attribute:"description", value:
"This plugin checks expiry dates of certificates associated with SSL-
enabled services on the target and reports whether any have already
expired.");
script_set_attribute(attribute:"solution", value:
"Purchase or generate a new SSL certificate to replace the existing
one.");
script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:N/I:P/A:N");
script_set_cvss3_base_vector("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N");
script_set_attribute(attribute:"cvss_score_source", value:"manual");
script_set_attribute(attribute:"cvss_score_rationale", value:"Expired certificates cannot be validated.");
script_set_attribute(attribute:"plugin_publication_date", value:"2004/12/03");
script_set_attribute(attribute:"plugin_type", value:"remote");
script_end_attributes();
script_category(ACT_GATHER_INFO);
script_family(english:"General");
script_copyright(english:"This script is Copyright (C) 2004-2020 George A. Theall");
script_dependencies("ssl_supported_versions.nasl");
script_require_keys("SSL/Supported");
script_add_preference(name:"Identify certificates that expire within x days", type:"entry", value:"60");
exit(0);
}
include("ftp_func.inc");
include("global_settings.inc");
include("datetime.inc");
include("ldap_func.inc");
include("nntp_func.inc");
include("smtp_func.inc");
include("telnet2_func.inc");
include("x509_func.inc");
include("audit.inc");
include("rsync.inc");
# How far (in days) to warn of certificate expiry.
# Default to 60, and allow the user to customize as long as a non-null, non-zero int is provided
lookahead = 60;
pref = script_get_preference("Identify certificates that expire within x days");
if (pref =~ "^\d+$")
{
pref = int(pref);
if (pref > 0)
lookahead = pref;
}
set_kb_item(name:'SSL/settings/future_warning_days', value:lookahead);
# This function converts a date expressed as:
# Year(4)|Month(2)|Day(2)|Hour(2)|Min(2)|Sec(2)
# and returns it in a more human-friendly format.
function x509time_to_gtime(x509time) {
local_var gtime, i, mm, mon, mons, parts, year;
mons = "JanFebMarAprMayJunJulAugSepOctNovDec";
if (x509time && x509time =~ "^[0-9]{14}Z?$") {
parts[0] = substr(x509time, 0, 3);
for (i=1; i<= 6; ++i) {
parts[i] = substr(x509time, 2+i*2, 2+i*2+1);
}
year = int(parts[0]);
mm = int(parts[1]);
if (mm >= 1 && mm <= 12) {
--mm;
mon = substr(mons, mm*3, mm*3+2);
}
else {
mon = "unk";
}
parts[2] = ereg_replace(string:parts[2], pattern:"^0", replace:" ");
gtime = mon + " " +
parts[2] + " " +
parts[3] + ":" + parts[4] + ":" + parts[5] + " " +
year + " GMT";
}
return gtime;
}
function x509time_to_bn_epoch(x509time)
{
local_var gtime, i, mon, parts, year, day, hour, min, sec;
if (x509time && x509time =~ "^[0-9]{14}Z?$")
{
parts[0] = substr(x509time, 0, 3);
for (i=1; i<= 6; ++i) {
parts[i] = substr(x509time, 2+i*2, 2+i*2+1);
}
year = int(parts[0]);
mon = int(parts[1]);
day = int(parts[2]);
hour = int(parts[3]);
min = int(parts[4]);
sec = int(parts[5]);
gtime = calendar_to_bn_epoch(year:year, mon:mon, day:day, hour:hour, min:min, sec:sec);
}
return gtime;
}
get_kb_item_or_exit("SSL/Supported");
port = get_ssl_ports(fork:TRUE);
if (isnull(port))
exit(1, "The host does not appear to have any SSL-based services.");
# Find out if the port is open.
if (!get_port_state(port))
exit(0, "Port " + port + " is not open.");
# Allow the plugin to be tested with just certificates in a KB with -k,
# instead of having to have an SSL server somewhere.
if (!get_kb_item("TEST_ssl_cert_expiry_do_not_open_socket"))
{
# Open socket, sending StartTLS commands if necessary.
soc = open_sock_ssl(port);
if (!soc)
exit(1, "Failed to connect to port " + port + ".");
}
# Retrieve the certificate the server is using for this port.
cert = get_server_cert(socket:soc, port:port, encoding:"der");
if (isnull(cert))
exit(1, "Failed to read server cert from port " + port + ".");
# nb: maybe someday I'll actually *parse* ASN.1.
v = stridx(cert, raw_string(0x30, 0x1e, 0x17, 0x0d));
if (v >= 0) {
v += 4;
valid_start = substr(cert, v, v+11);
v += 15;
valid_end = substr(cert, v, v+11);
if (valid_start =~ "^[0-9]{12}$" && valid_end =~ "^[0-9]{12}$") {
# nb: YY >= 50 => YYYY = 19YY per RFC 3280 (4.1.2.5.1)
if (int(substr(valid_start, 0, 1)) >= 50) valid_start = "19" + valid_start;
else valid_start = "20" + valid_start;
if (int(substr(valid_end, 0, 1)) >= 50) valid_end = "19" + valid_end;
else valid_end = "20" + valid_end;
# Get dates, expressed in UTC, for checking certs.
# - right now.
tm = localtime(unixtime(), utc:TRUE);
now = string(tm["year"]);
foreach field (make_list("mon", "mday", "hour", "min", "sec")) {
if (tm[field] < 10) now += "0";
now += tm[field];
}
# - 'lookahead' days in the future.
tm = localtime(unixtime() + lookahead*24*60*60, utc:TRUE);
future = string(tm["year"]);
foreach field (make_list("mon", "mday", "hour", "min", "sec")) {
if (tm[field] < 10) future += "0";
future += tm[field];
}
debug_print("now: ", now, ".");
debug_print("future: ", future, ".");
valid_start_alt = x509time_to_gtime(x509time:valid_start);
valid_end_alt = x509time_to_gtime(x509time:valid_end);
debug_print("valid not before: ", valid_start_alt, " (", valid_start, "Z).");
debug_print("valid not after: ", valid_end_alt, " (", valid_end, "Z).");
key = 'Transport/SSL/' + port + '/';
replace_kb_item(name:key + 'valid_end', value:valid_end_alt);
replace_kb_item(name:key + 'valid_start', value:valid_start_alt);
replace_kb_item(name:key + 'valid_end_alt', value:hexstr(x509time_to_bn_epoch(x509time:valid_end)));
replace_kb_item(name:key + 'valid_start_alt', value:hexstr(x509time_to_bn_epoch(x509time:valid_start)));
debug_print("The SSL certificate on port ", port, " is valid between ", valid_start_alt, " and ", valid_end_alt, ".", level:1);
# Extract the issuer / subject.
cert2 = parse_der_cert(cert:cert);
if (isnull(cert2))
exit(1, "Failed to parse the SSL certificate associated with the service on port " + port + ".");
tbs = cert2["tbsCertificate"];
if(is_subscriber_cert(tbs))
set_kb_item(name:key + 'subscriber_cert', value:1);
issuer_seq = tbs["issuer"];
subject_seq = tbs["subject"];
issuer = '';
foreach seq (issuer_seq)
{
o = oid_name[seq[0]];
if (isnull(o)) continue;
attr = "";
if (o == "Common Name") attr = "CN";
else if (o == "Surname") attr = "SN";
else if (o == "Country") attr = "C";
else if (o == "Locality") attr = "L";
else if (o == "State/Province") attr = "ST";
else if (o == "Street") attr = "street";
else if (o == "Organization") attr = "O";
else if (o == "Organization Unit") attr = "OU";
else if (o == "Email Address") attr = "emailAddress";
if (attr) issuer += ', ' + attr + '=' + seq[1];
}
if (issuer) issuer = substr(issuer, 2);
else issuer = 'n/a';
subject = '';
foreach seq (subject_seq)
{
o = oid_name[seq[0]];
if (isnull(o)) continue;
attr = "";
if (o == "Common Name") attr = "CN";
else if (o == "Surname") attr = "SN";
else if (o == "Country") attr = "C";
else if (o == "Locality") attr = "L";
else if (o == "State/Province") attr = "ST";
else if (o == "Street") attr = "street";
else if (o == "Organization") attr = "O";
else if (o == "Organization Unit") attr = "OU";
else if (o == "Email Address") attr = "emailAddress";
if (attr) subject += ', ' + attr + '=' + seq[1];
}
if (subject) subject = substr(subject, 2);
else subject = 'n/a';
replace_kb_item(name:key + 'issuer', value:issuer);
replace_kb_item(name:key + 'subject', value:subject);
if (valid_start > now)
{
replace_kb_item(name:key + 'future_validity_date', value:valid_start_alt);
}
else if (valid_end < now)
{
if (report_verbosity > 0)
{
report =
'\n' + 'The SSL certificate has already expired :' +
'\n' +
'\n Subject : ' + subject +
'\n Issuer : ' + issuer +
'\n Not valid before : ' + valid_start_alt +
'\n Not valid after : ' + valid_end_alt + '\n';
security_warning(port:port, extra:report);
}
else security_warning(port);
replace_kb_item(name:key + 'expired_cert', value:TRUE);
}
else if (valid_end < future)
{
replace_kb_item(name:key + 'days_to_expire', value:lookahead);
replace_kb_item(name:key + 'future_expiry_date', value:valid_end_alt);
}
}
}
{"id": "SSL_CERT_EXPIRY.NASL", "bulletinFamily": "scanner", "title": "SSL Certificate Expiry", "description": "This plugin checks expiry dates of certificates associated with SSL-\nenabled services on the target and reports whether any have already\nexpired.", "published": "2004-12-03T00:00:00", "modified": "2004-12-03T00:00:00", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:N/I:P/A:N"}, "href": "https://www.tenable.com/plugins/nessus/15901", "reporter": "This script is Copyright (C) 2004-2020 George A. Theall", "references": [], "cvelist": [], "type": "nessus", "lastseen": "2020-06-16T04:24:15", "edition": 10, "viewCount": 471, "enchantments": {"dependencies": {"references": [{"type": "nessus", "idList": ["SSL_CERT_FUTURE_VALIDITY.NASL", "SSL_CERTIFICATE_CHAIN.NASL", "SSL_CERT_FUTURE_EXPIRY.NASL", "SSL_CERT_LONG_DURATION.NASL"]}], "modified": "2020-06-16T04:24:15", "rev": 2}, "score": {"value": -0.1, "vector": "NONE", "modified": "2020-06-16T04:24:15", "rev": 2}, "vulnersScore": -0.1}, "sourceData": "#TRUSTED ac8aeee04d38ce931cd0c24a8003e0ed67efd176b56524d2a20350e174ae986b3113696f92aaf0bb53900e44cea006b5ff122033f379ce99542f36d63eaf9d5be20209f19366dc40bcdbcab600ad04cd46dfb56ac0a2319606e7a46afd08f72c8bf580c88f9246a64f96471c92bc8c9bf0a4e644b6d97ba897ca443ed9b9f20d558c58622488216a49c2c0b56efc8f5c9f9bf223a44eab81cf66746ca30a5df26354dc473f38624d4d039a1538a8a331b3a5d0f02437f539e86b7efa1415c3711210f2909e5fbefb760e94ee6b91e29a27606943963cc676b0b346000c0e9b96fba449ab41327325ec2160a739b95ffe3a5b1f0c7076c9f60c5e2761ecbd9384341b9bebdaf445c9d931e1936e1ddb2133e86dd0d51b72e9b50abdcd339f1b512d7e5e4048fcf485545ce8462c3f45e72da196dbf0ab9c03110d157aeeb45b30634a9323f02f081beb4d5f4eab3c1b38c9e4562b204c538267391b7ff2356d72cf7244a43a84f0795c581660eca8b304ed15a356e771bab43f38dac891d8a2b5767770194c9768192f6dbd19874ca5a286289019419e1703094e080cd6dff6de0daa144f23406d9b11518fe047fc81ac77d8898f734696907e0144da6391480ded259ea1488be56624c44b6707c769e870797cdd229960f29bd640d4280b0ffbf7a9fe40c5b5bf22d7eb1c48c027d7d3dd9a8bef1e0a8b67e3794b7bd6ea39d3\n#\n# @PREFERENCES@\n#\n# This script was written by George A. Theall, <theall@tifaware.com>.\n#\n# See the Nessus Scripts License for details.\n#\n# Changes by Tenable :\n# - Updated to use compat.inc, made report severity consistent (11/23/09)\n# - Added CVSS score, KBs. (11/23/09)\n# - Signed. (10/18/2013)\n# - Made expiration warning period user-configurable. (05/12/15)\n# - Added rsync. (2016/01/07)\n\nif ( ! defined_func(\"localtime\") ) exit(0);\n\ninclude(\"compat.inc\");\n\nif (description)\n{\n script_id(15901);\n script_version(\"1.48\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2020/06/12\");\n\n script_name(english:\"SSL Certificate Expiry\");\n script_summary(english:\"Checks the SSL certificate expiry.\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"The remote server's SSL certificate has already expired.\");\n script_set_attribute(attribute:\"description\", value:\n\"This plugin checks expiry dates of certificates associated with SSL-\nenabled services on the target and reports whether any have already\nexpired.\");\n script_set_attribute(attribute:\"solution\", value:\n\"Purchase or generate a new SSL certificate to replace the existing\none.\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:N/I:P/A:N\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"manual\");\n script_set_attribute(attribute:\"cvss_score_rationale\", value:\"Expired certificates cannot be validated.\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2004/12/03\");\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"General\");\n\n script_copyright(english:\"This script is Copyright (C) 2004-2020 George A. Theall\");\n\n script_dependencies(\"ssl_supported_versions.nasl\");\n script_require_keys(\"SSL/Supported\");\n\n script_add_preference(name:\"Identify certificates that expire within x days\", type:\"entry\", value:\"60\");\n\n exit(0);\n}\n\ninclude(\"ftp_func.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"datetime.inc\");\ninclude(\"ldap_func.inc\");\ninclude(\"nntp_func.inc\");\ninclude(\"smtp_func.inc\");\ninclude(\"telnet2_func.inc\");\ninclude(\"x509_func.inc\");\ninclude(\"audit.inc\");\ninclude(\"rsync.inc\");\n\n# How far (in days) to warn of certificate expiry.\n# Default to 60, and allow the user to customize as long as a non-null, non-zero int is provided\nlookahead = 60;\npref = script_get_preference(\"Identify certificates that expire within x days\");\nif (pref =~ \"^\\d+$\")\n{\n pref = int(pref);\n if (pref > 0)\n lookahead = pref;\n}\n\nset_kb_item(name:'SSL/settings/future_warning_days', value:lookahead);\n\n# This function converts a date expressed as:\n# Year(4)|Month(2)|Day(2)|Hour(2)|Min(2)|Sec(2)\n# and returns it in a more human-friendly format.\nfunction x509time_to_gtime(x509time) {\n local_var gtime, i, mm, mon, mons, parts, year;\n mons = \"JanFebMarAprMayJunJulAugSepOctNovDec\";\n\n if (x509time && x509time =~ \"^[0-9]{14}Z?$\") {\n parts[0] = substr(x509time, 0, 3);\n for (i=1; i<= 6; ++i) {\n parts[i] = substr(x509time, 2+i*2, 2+i*2+1);\n }\n\n year = int(parts[0]);\n\n mm = int(parts[1]);\n if (mm >= 1 && mm <= 12) {\n --mm;\n mon = substr(mons, mm*3, mm*3+2);\n }\n else {\n mon = \"unk\";\n }\n parts[2] = ereg_replace(string:parts[2], pattern:\"^0\", replace:\" \");\n\n gtime = mon + \" \" +\n parts[2] + \" \" +\n parts[3] + \":\" + parts[4] + \":\" + parts[5] + \" \" +\n year + \" GMT\";\n }\n return gtime;\n}\n\n\nfunction x509time_to_bn_epoch(x509time)\n{\n local_var gtime, i, mon, parts, year, day, hour, min, sec;\n\n if (x509time && x509time =~ \"^[0-9]{14}Z?$\")\n {\n parts[0] = substr(x509time, 0, 3);\n for (i=1; i<= 6; ++i) {\n parts[i] = substr(x509time, 2+i*2, 2+i*2+1);\n }\n\n year = int(parts[0]);\n mon = int(parts[1]);\n day = int(parts[2]);\n hour = int(parts[3]);\n min = int(parts[4]);\n sec = int(parts[5]);\n\n gtime = calendar_to_bn_epoch(year:year, mon:mon, day:day, hour:hour, min:min, sec:sec);\n }\n\n return gtime;\n}\n\n\nget_kb_item_or_exit(\"SSL/Supported\");\n\nport = get_ssl_ports(fork:TRUE);\nif (isnull(port))\n exit(1, \"The host does not appear to have any SSL-based services.\");\n\n# Find out if the port is open.\nif (!get_port_state(port))\n exit(0, \"Port \" + port + \" is not open.\");\n\n# Allow the plugin to be tested with just certificates in a KB with -k,\n# instead of having to have an SSL server somewhere.\nif (!get_kb_item(\"TEST_ssl_cert_expiry_do_not_open_socket\"))\n{\n # Open socket, sending StartTLS commands if necessary.\n soc = open_sock_ssl(port);\n if (!soc)\n exit(1, \"Failed to connect to port \" + port + \".\");\n}\n\n# Retrieve the certificate the server is using for this port.\ncert = get_server_cert(socket:soc, port:port, encoding:\"der\");\nif (isnull(cert))\n exit(1, \"Failed to read server cert from port \" + port + \".\");\n\n# nb: maybe someday I'll actually *parse* ASN.1.\nv = stridx(cert, raw_string(0x30, 0x1e, 0x17, 0x0d));\nif (v >= 0) {\n v += 4;\n valid_start = substr(cert, v, v+11);\n v += 15;\n valid_end = substr(cert, v, v+11);\n\n if (valid_start =~ \"^[0-9]{12}$\" && valid_end =~ \"^[0-9]{12}$\") {\n # nb: YY >= 50 => YYYY = 19YY per RFC 3280 (4.1.2.5.1)\n if (int(substr(valid_start, 0, 1)) >= 50) valid_start = \"19\" + valid_start;\n else valid_start = \"20\" + valid_start;\n\n if (int(substr(valid_end, 0, 1)) >= 50) valid_end = \"19\" + valid_end;\n else valid_end = \"20\" + valid_end;\n\n # Get dates, expressed in UTC, for checking certs.\n # - right now.\n tm = localtime(unixtime(), utc:TRUE);\n now = string(tm[\"year\"]);\n foreach field (make_list(\"mon\", \"mday\", \"hour\", \"min\", \"sec\")) {\n if (tm[field] < 10) now += \"0\";\n now += tm[field];\n }\n # - 'lookahead' days in the future.\n tm = localtime(unixtime() + lookahead*24*60*60, utc:TRUE);\n future = string(tm[\"year\"]);\n foreach field (make_list(\"mon\", \"mday\", \"hour\", \"min\", \"sec\")) {\n if (tm[field] < 10) future += \"0\";\n future += tm[field];\n }\n debug_print(\"now: \", now, \".\");\n debug_print(\"future: \", future, \".\");\n\n valid_start_alt = x509time_to_gtime(x509time:valid_start);\n valid_end_alt = x509time_to_gtime(x509time:valid_end);\n debug_print(\"valid not before: \", valid_start_alt, \" (\", valid_start, \"Z).\");\n debug_print(\"valid not after: \", valid_end_alt, \" (\", valid_end, \"Z).\");\n\n key = 'Transport/SSL/' + port + '/';\n replace_kb_item(name:key + 'valid_end', value:valid_end_alt);\n replace_kb_item(name:key + 'valid_start', value:valid_start_alt);\n replace_kb_item(name:key + 'valid_end_alt', value:hexstr(x509time_to_bn_epoch(x509time:valid_end)));\n replace_kb_item(name:key + 'valid_start_alt', value:hexstr(x509time_to_bn_epoch(x509time:valid_start)));\n\n debug_print(\"The SSL certificate on port \", port, \" is valid between \", valid_start_alt, \" and \", valid_end_alt, \".\", level:1);\n\n # Extract the issuer / subject.\n cert2 = parse_der_cert(cert:cert);\n if (isnull(cert2))\n exit(1, \"Failed to parse the SSL certificate associated with the service on port \" + port + \".\");\n\n tbs = cert2[\"tbsCertificate\"];\n if(is_subscriber_cert(tbs))\n set_kb_item(name:key + 'subscriber_cert', value:1);\n\n issuer_seq = tbs[\"issuer\"];\n subject_seq = tbs[\"subject\"];\n\n issuer = '';\n foreach seq (issuer_seq)\n {\n o = oid_name[seq[0]];\n if (isnull(o)) continue;\n\n attr = \"\";\n if (o == \"Common Name\") attr = \"CN\";\n else if (o == \"Surname\") attr = \"SN\";\n else if (o == \"Country\") attr = \"C\";\n else if (o == \"Locality\") attr = \"L\";\n else if (o == \"State/Province\") attr = \"ST\";\n else if (o == \"Street\") attr = \"street\";\n else if (o == \"Organization\") attr = \"O\";\n else if (o == \"Organization Unit\") attr = \"OU\";\n else if (o == \"Email Address\") attr = \"emailAddress\";\n\n if (attr) issuer += ', ' + attr + '=' + seq[1];\n }\n if (issuer) issuer = substr(issuer, 2);\n else issuer = 'n/a';\n\n subject = '';\n foreach seq (subject_seq)\n {\n o = oid_name[seq[0]];\n if (isnull(o)) continue;\n\n attr = \"\";\n if (o == \"Common Name\") attr = \"CN\";\n else if (o == \"Surname\") attr = \"SN\";\n else if (o == \"Country\") attr = \"C\";\n else if (o == \"Locality\") attr = \"L\";\n else if (o == \"State/Province\") attr = \"ST\";\n else if (o == \"Street\") attr = \"street\";\n else if (o == \"Organization\") attr = \"O\";\n else if (o == \"Organization Unit\") attr = \"OU\";\n else if (o == \"Email Address\") attr = \"emailAddress\";\n\n if (attr) subject += ', ' + attr + '=' + seq[1];\n }\n if (subject) subject = substr(subject, 2);\n else subject = 'n/a';\n\n replace_kb_item(name:key + 'issuer', value:issuer);\n replace_kb_item(name:key + 'subject', value:subject);\n\n if (valid_start > now)\n {\n replace_kb_item(name:key + 'future_validity_date', value:valid_start_alt);\n }\n else if (valid_end < now)\n {\n if (report_verbosity > 0)\n {\n report =\n '\\n' + 'The SSL certificate has already expired :' +\n '\\n' +\n '\\n Subject : ' + subject +\n '\\n Issuer : ' + issuer +\n '\\n Not valid before : ' + valid_start_alt +\n '\\n Not valid after : ' + valid_end_alt + '\\n';\n security_warning(port:port, extra:report);\n }\n else security_warning(port);\n\n replace_kb_item(name:key + 'expired_cert', value:TRUE);\n }\n else if (valid_end < future)\n {\n replace_kb_item(name:key + 'days_to_expire', value:lookahead);\n replace_kb_item(name:key + 'future_expiry_date', value:valid_end_alt);\n }\n }\n}\n", "naslFamily": "General", "pluginID": "15901", "cpe": [], "scheme": null, "cvss3": {"score": 5.3, "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}}
{"nessus": [{"lastseen": "2021-01-01T05:49:59", "description": "The CA/Browser Forum has passed a resolution setting the maximum\nvalidity period for SSL/TLS subscriber certificates via ballot 193.\n\nCertificates issued after March 1, 2018 may not be valid longer than\n825 days. Certificates issued after July 1, 2016 through\nMarch 1, 2018 may not be valid longer than 39 months. Certificates\nissued on or before July 1, 2016 may not be valid longer than 60\nmonths.\n\nLong validity periods encourage certificate owners to keep\ncertificates in production that have vulnerabilities associated\nwith weak cryptography and that may be out of compliance with other\nsecurity guidelines.\n\nNote: CA/Browser Forum ballot 193 specifies policy based on the\nday the certificate was issued. SSL/TLS certificates do not carry an\nissuance date. This plugin uses a certificate's 'Not Valid Before'\ndate as a proxy for the date the certificate was issued.", "edition": 26, "cvss3": {"score": 4.8, "vector": "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N"}, "published": "2019-01-08T00:00:00", "title": "SSL Certificate Validity - Duration", "type": "nessus", "bulletinFamily": "scanner", "cvelist": [], "modified": "2021-01-02T00:00:00", "cpe": [], "id": "SSL_CERT_LONG_DURATION.NASL", "href": "https://www.tenable.com/plugins/nessus/121009", "sourceData": "#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude(\"compat.inc\");\n\nif(description)\n{\n script_id(121009);\n script_version(\"1.9\");\n script_cvs_date(\"Date: 2019/03/27 13:17:50\");\n\n script_name(english:\"SSL Certificate Validity - Duration\");\n script_summary(english:\"Checks SSL certificate validity duration\");\n\n script_set_attribute(\n attribute:'synopsis',\n value:\n\"The SSL certificate is valid over a time period that is too long.\"\n );\n script_set_attribute(\n attribute:'description',\n value:\n\"The CA/Browser Forum has passed a resolution setting the maximum\nvalidity period for SSL/TLS subscriber certificates via ballot 193.\n\nCertificates issued after March 1, 2018 may not be valid longer than\n825 days. Certificates issued after July 1, 2016 through\nMarch 1, 2018 may not be valid longer than 39 months. Certificates\nissued on or before July 1, 2016 may not be valid longer than 60\nmonths.\n\nLong validity periods encourage certificate owners to keep\ncertificates in production that have vulnerabilities associated\nwith weak cryptography and that may be out of compliance with other\nsecurity guidelines.\n\nNote: CA/Browser Forum ballot 193 specifies policy based on the\nday the certificate was issued. SSL/TLS certificates do not carry an\nissuance date. This plugin uses a certificate's 'Not Valid Before'\ndate as a proxy for the date the certificate was issued.\"\n );\n script_set_attribute(\n attribute:\"solution\",\n value:\n\"Replace the SSL certificate with a certificate having a validity\nperiod less than or equal to 825 days.\"\n );\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:H/Au:N/C:P/I:P/A:N\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"manual\");\n script_set_attribute(attribute:\"cvss_score_rationale\", value:\"Certificates that are outdated despite their validity period can have cryptographic and protocol weaknesses.\");\n #https://cabforum.org/2017/03/17/ballot-193-825-day-certificate-lifetimes/\n script_set_attribute(attribute:\"see_also\", value:\"http://www.nessus.org/u?5c70535d\");\n\n\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2019/01/08\");\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2019 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n script_family(english:\"General\");\n\n script_dependencies(\"ssl_cert_expiry.nasl\");\n script_require_keys(\"SSL/Supported\");\n\n exit(0);\n}\n\ninclude(\"global_settings.inc\");\ninclude(\"audit.inc\");\ninclude(\"datetime.inc\");\ninclude(\"ssl_funcs.inc\");\n\nget_kb_item_or_exit(\"SSL/Supported\");\n\norig_date_of_inception = calendar_to_bn_epoch(year:2016, mon:6, day:30, hour:0, min:0, sec:1);\nnew_date_of_inception = calendar_to_bn_epoch(year:2018, mon:3, day:1, hour:0, min:0, sec:1);\n\nfunction more_than_x_months(start, end, x)\n{\n var start_human = localtime(bn_raw2dec(start), utc:TRUE);\n var period_end = calendar_to_bn_epoch(year:start_human.year, mon:start_human.mon + x,\n day:start_human.mday, hour:start_human.hour, min:start_human.min,\n sec:start_human.sec);\n\n return bn_cmp(key1:end, key2:period_end) > 0;\n}\n\nports = get_kb_list(\"Transport/SSL\");\n\n# Get list of ports that use SSL or StartTLS.\nif (isnull(ports))\n audit(AUDIT_HOST_NONE, \"SSL-based services\");\n\nstarts = get_kb_list(\"Transport/SSL/*/valid_start_alt\");\nends = get_kb_list(\"Transport/SSL/*/valid_end_alt\");\nreadable_starts = get_kb_list(\"Transport/SSL/*/valid_start\");\nreadable_ends = get_kb_list(\"Transport/SSL/*/valid_end\");\nsub_certs = get_kb_list(\"Transport/SSL/*/subscriber_cert\");\nissuers = get_kb_list(\"Transport/SSL/*/issuer\");\nsubjects = get_kb_list(\"Transport/SSL/*/subject\");\n\nports = make_list(ports);\nstarttls_ports = get_kb_list(\"*/*/starttls\");\nforeach key (keys(starttls_ports))\n{\n # Extract port from KB item name.\n port = split(key, sep:\"/\", keep:FALSE);\n port = int(port[1]);\n\n # Ignore invalid ports.\n if (port < 1 || port > 65535)\n continue;\n\n ports = add_port_in_list(list:ports, port:port);\n}\n\nnum_ports = len(ports);\n\nfor(i = 0; i < num_ports; i++)\n{\n port = ports[i];\n\n if (!get_port_state(port)) continue;\n\n key = 'Transport/SSL/' + port + '/';\n\n if (!sub_certs[key + 'subscriber_cert']) continue;\n\n readable_valid_start = readable_starts[key + 'valid_start'];\n readable_valid_end = readable_ends[key + 'valid_end'];\n\n valid_start = starts[key + 'valid_start_alt'];\n valid_end = ends[key + 'valid_end_alt'];\n if (!valid_start) continue;\n if (!valid_end) continue;\n valid_too_long = FALSE;\n\n epoch_start_validity = bn_hex2raw(valid_start);\n epoch_end_validity = bn_hex2raw(valid_end);\n\n one_day_in_secs = bn_dec2raw(60 * 60 * 24);\n epochdiff = bn_sub(epoch_end_validity, epoch_start_validity);\n\n\n cert_duration_days = int(bn_raw2dec(bn_div(epochdiff, one_day_in_secs)));\n if(bn_mod(epochdiff, one_day_in_secs) > 0)\n cert_duration_days++;\n\n if(!epoch_start_validity || !epoch_end_validity || !cert_duration_days) continue;\n\n if(bn_cmp(key1:epoch_start_validity, key2:new_date_of_inception) >= 0)\n {\n if(cert_duration_days > 825) valid_too_long = TRUE;\n }\n else if(bn_cmp(key1:epoch_start_validity, key2:orig_date_of_inception) >= 0)\n {\n valid_too_long = more_than_x_months(start:epoch_start_validity, end:epoch_end_validity, x:39);\n }\n else\n {\n valid_too_long = more_than_x_months(start:epoch_start_validity, end:epoch_end_validity, x:60);\n }\n\n if(valid_too_long)\n {\n if (report_verbosity > 0)\n {\n issuer = issuers[key + 'issuer'];\n subject = subjects[key + 'subject'];\n\n report =\n '\\n' + 'The SSL certificate has a valid duration of ' + cert_duration_days + ' days.' +\n '\\n' +\n '\\n Subject : ' + subject +\n '\\n Issuer : ' + issuer +\n '\\n Not valid before : ' + readable_valid_start +\n '\\n Not valid after : ' + readable_valid_end + '\\n';\n\n security_warning(port:port, extra:report);\n }\n else security_warning(port);\n }\n}\n", "cvss": {"score": 4.0, "vector": "AV:N/AC:H/Au:N/C:P/I:P/A:N"}}, {"lastseen": "2020-06-16T04:24:15", "description": "This plugin examines the chain of X.509 certificates used by this\nservice.", "edition": 18, "published": "2012-01-17T00:00:00", "title": "SSL Certificate Chain Analysis", "type": "nessus", "bulletinFamily": "scanner", "cvelist": [], "modified": "2012-01-17T00:00:00", "cpe": [], "id": "SSL_CERTIFICATE_CHAIN.NASL", "href": "https://www.tenable.com/plugins/nessus/57571", "sourceData": "#TRUSTED 391115c2445d2cef7d86b9f01163db9c51d924fb80a8d0043cab4632f105f89de7de20a820601acf33035c00f32e71bc716b5f1c5dc9139eabcc228e3467de2510c445d94bed8aa7a9add2a714f0b0831769dbf4e0a4538a1e616dc24ecf3fd159f99532b088e443ea51cc151c5dfd8fc1fbabd61e2702b000bd04b711c7edc1d77734dfaedcc3dbc9efac25a928dab6cb51c705c32dcc22967a8404260ce654806dd23538c513a961d7cec3f1c778efffe72d98d96d4822f2d4a669dbfec6079df2f345f2eaec8ccc7352c2373926bd0739b7331460e487ee682964390f9e53e2cffeaf3ea43330b8697e2573ad2f5693956f0a02b660020578573441f899807367c49920e75de2adb9a8f19fcb09ae63dcf66ec6337be7d41c4119cd4fd91ab924998c4da930b535783d58c92e8bdf191db7e7615b3817fe77af77b2d18d99cb36f83d15288a48ddb45fa9d735eb8b7d206e1365fae878cf2ec6ae206a9bd7fcbdc98ace5225a1cd62843e6f52aa4e3faf7dd25c47f231413f08313e5d1b93596324e0b8921c00ea4c60700176bfbced1a145d0190f1f1d162ef70995076fb4c255892ea64a4fb159c44efa0282851219ba2a1972edf797b0f6d9afe4dca924b7487a848ca6cd2450fafb8623380b0d8b9ae42c0151994b3b9d360254fadb3a43ab3f7b569a43bf208930ad829116732c0a18d208a42ae4387f109f9cc8634\n#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude(\"compat.inc\");\n\nif (description)\n{\n script_id(57571);\n script_version(\"1.57\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2020/06/12\");\n\n script_name(english:\"SSL Certificate Chain Analysis\");\n script_summary(english:\"Checks the certificate chain.\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"This plugin sets KB items for use by other plugins.\");\n script_set_attribute(attribute:\"description\", value:\n\"This plugin examines the chain of X.509 certificates used by this\nservice.\");\n script_set_attribute(attribute:\"solution\", value:\"n/a\");\n script_set_attribute(attribute:\"risk_factor\", value:\"None\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2012/01/17\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"General\");\n\n script_copyright(english:\"This script is Copyright (C) 2012-2020 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n\n script_dependencies(\"ssl_cert_expiry.nasl\", \"ssl_ca_setup.nasl\");\n script_require_keys(\"SSL/Supported\");\n\n exit(0);\n}\n\ninclude(\"datetime.inc\");\ninclude(\"ftp_func.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"ldap_func.inc\");\ninclude(\"nntp_func.inc\");\ninclude(\"smtp_func.inc\");\ninclude(\"telnet2_func.inc\");\ninclude(\"x509_func.inc\");\ninclude(\"audit.inc\");\ninclude(\"rsync.inc\");\ninclude(\"http.inc\");\ninclude(\"ocsp.inc\");\ninclude(\"ecc.inc\");\n\n\nglobal_var broken, CAs, CAs_raw, CAs_whitelist, chain, port, unsorted, valid;\nglobal_var src = \"ssl_certificate_chain.nasl\";\n\n######################################################################\n# Certificate Extension : Basic Constraints / Key Usage\n######################################################################\nfunction check_cert_ext_basic_constraints(cert, idx)\n{\n local_var bc, critical, ku;\n ssl_dbg(src:src, msg:'check_cert_ext_basic_constraints()');\n\n # Ignore certificates that aren't X.509v3, since these rules don't\n # apply to them.\n if (cert[\"version\"] != 2)\n return TRUE;\n\n # Extract key usage extension.\n ku = cert_get_ext(id:EXTN_KEY_USAGE, cert:cert);\n\n # Extract basic constraints extension.\n bc = cert_get_ext(id:EXTN_BASIC_CONSTRAINTS, cert:cert);\n\n # Extract basic constraints extension's critical boolean.\n critical = cert_get_ext(id:EXTN_BASIC_CONSTRAINTS, cert:cert, field:\"critical\");\n\n # RFC 5280, Section 4.2.1.9 :\n #\n # If the basic constraints extension is not present in a version 3\n # certificate, or the extension is present but the cA boolean is\n # not asserted, then the certified public key MUST NOT be used to\n # verify certificate signatures.\n if (isnull(bc))\n return\n 'The certificate is missing the basic constraints extension which is\\n' +\n 'required for all X.509v3 certificates that sign others.';\n\n if (!bc[\"ca\"])\n return\n 'The certificate does not have the CA bit asserted in the basic\\n' +\n 'constraints extension, which is required for all certificates that\\n' +\n 'sign others.';\n\n if (!isnull(bc[\"pathlen\"]))\n {\n # Many certificates found in the wild are missing the key usage\n # extension despite, having a pathlen. All examples found had the\n # critical boolean in the basic constraints extension set as\n # false. We'll use that as a heuristic.\n if (critical)\n {\n # RFC 5280, Section 4.2.1.9 :\n #\n # CAs MUST NOT include the pathLenConstraint field unless the cA\n # boolean is asserted and the key usage extension asserts the\n # keyCertSign bit.\n if (isnull(ku))\n return\n 'The certificate is missing the key usage extension which is required\\n' +\n 'for all certificates that have a pathlen value in the basic\\n' +\n 'constraints extension.';\n\n if ((ku & keyCertSign) == 0)\n return\n 'The certificate contains the key usage extension, but does not have\\n' +\n 'the keyCertSign bit asserted, which is required for all certificates\\n' +\n 'that have a pathlen value in the basic constraints extension.';\n }\n\n # RFC 5280, Section 4.2.1.9 :\n #\n # Where it appears, the pathLenConstraint field MUST be greater\n # than or equal to zero.\n if (bc[\"pathlen\"] < 0)\n return 'The certificate has an invalid pathlen : ' + bc[\"pathlen\"] + '.';\n\n # Things that don't seem like they should be valid but are :\n #\n # - A certificate with a pathlen of m signing a certificate\n # with a pathlen of n where n >= m.\n # - A certificate with a pathlen restriction signing a\n # certificate that has no pathlen restriction.\n # - A certificate with a pathlen of zero signing a certificate\n # that has a basic constraints extension, so long as it is\n # the last link in the chain.\n #\n # RFC 5280, Section 4.2.1.9 :\n #\n # [Pathlen] gives the maximum number of non-self-issued\n # intermediate certificates that may follow this certificate in\n # a valid certification path. (Note: The last certificate in the\n # certification path is not an intermediate certificate, and is\n # not included in this limit. Usually, the last certificate is\n # an end entity certificate, but it can be a CA certificate.) A\n # pathLenConstraint of zero indicates that no non-self-issued\n # intermediate CA certificates may follow in a valid\n # certification path.\n #\n # RFC 5280, Section 6.1.4 :\n #\n # If the certificate was not self-issued, verify that\n # max_path_length is greater than zero and decrement\n # max_path_length by 1.\n #\n # If pathLenConstraint is present in the certificate and is less\n # than max_path_length, set max_path_length to the value of\n # pathLenConstraint.\n if (idx > 1 && idx - 1 > bc[\"pathlen\"])\n return\n 'The certificate has a pathlen of ' + bc[\"pathlen\"] + ', but has ' + (idx - 1) + ' intermediate CA\\n' +\n 'certificates below it in the certificate chain.';\n\n if (!isnull(ku))\n {\n # Section 4.2.1.3 states that the key usage extension is\n # required in all signing certs, while Section 6.1.4 contains an\n # algorithm that treats the extension as optional. We'll treat\n # the extension as optional unless there's a pathlen value in\n # the basic constraints extension.\n #\n # RFC 5280, Section 4.2.1.3 :\n #\n # Conforming CAs MUST include this extension in certificates\n # that contain public keys that are used to validate digital\n # signatures on other public key certificates or CRLs.\n #\n # The keyCertSign bit is asserted when the subject public key is\n # used for verifying signatures on public key certificates. If\n # the keyCertSign bit is asserted, then the cA bit in the basic\n # constraints extension (Section 4.2.1.9) MUST also be asserted.\n if ((ku & keyCertSign) == 0)\n return\n 'The certificate contains the key usage extension, but does not have\\n' +\n 'the keyCertSign bit asserted, which is required for all certificates\\n' +\n 'that sign others.';\n }\n }\n\n return TRUE;\n}\n\n######################################################################\n# Root CA - Check if top of chain is self-signed with CA extension\n#\n# Note: This function should always run after check_chain_ca(), so that\n# check_chain_ca() has already had the chance to add a known or custom\n# CA certificate to the top of the chain\n######################################################################\nfunction check_root_ca()\n{\n local_var alg, attr, bc, cert;\n ssl_dbg(src:src, msg:'check_root_ca()');\n\n cert = chain[max_index(chain)-1];\n bc = cert_get_ext(id:EXTN_BASIC_CONSTRAINTS, cert:cert[\"tbsCertificate\"]);\n if(bc[\"ca\"])\n {\n set_kb_item(name:\"SSL/Chain/Top/\"+port+\"/CA\", value:TRUE);\n\n # If the certificate at the top of the chain is a CA certificate and\n # is self-signed, then it is the root CA certificate\n if(is_self_signed(cert))\n {\n # Format the attributes that the plugin that reports this issue will\n # need in its output, to prevent having to re-parse the\n # certificates.\n alg = oid_name[cert[\"signatureAlgorithm\"]];\n if(isnull(alg)) alg = \"Unknown\";\n cert = cert[\"tbsCertificate\"];\n\n attr =\n 'Subject : ' + format_dn(cert[\"subject\"]) + '\\n' +\n 'Issuer : ' + format_dn(cert[\"issuer\"]) + '\\n' +\n 'Valid From : ' + cert[\"validity\"][\"notBefore\"] + '\\n' +\n 'Valid To : ' + cert[\"validity\"][\"notAfter\"] + '\\n' +\n 'Signature Algorithm : ' + alg + '\\n';\n\n set_kb_item(name:\"SSL/Chain/Top/\"+port+\"/Self-Signed\", value:TRUE);\n set_kb_item(name:\"SSL/Chain/Root/\" + port, value:attr);\n }\n\n # If the certificate at the top of the chain is a CA certificate and\n # is not self-signed, then it is an intermediate CA certificate with\n # an unknown issuer\n else\n set_kb_item(name:\"SSL/Chain/Top/\"+port+\"/Self-Signed\", value:FALSE);\n }\n else\n {\n set_kb_item(name:\"SSL/Chain/Top/\"+port+\"/CA\", value:FALSE);\n\n # If the certificate at the top of the chain is not a CA and is\n # self-signed, it is a self-generated server certificate\n if(is_self_signed(cert))\n set_kb_item(name:\"SSL/Chain/Top/\"+port+\"/Self-Signed\", value:TRUE);\n\n # If the certificate at the top of the chain is not a CA and is not\n # self-signed, it is just a server certificate with an unknown issuer\n else\n set_kb_item(name:\"SSL/Chain/Top/\"+port+\"/Self-Signed\", value:FALSE);\n }\n return NULL;\n}\n\nfunction check_distrusted_ca()\n{\n ssl_dbg(src:src, msg:'check_distrusted_ca()');\n var root = is_CA_distrusted(chain:chain, return_cert:TRUE);\n var attr, alg;\n\n if(!isnull(root))\n {\n set_kb_item(name:\"SSL/Chain/Distrusted\", value:port);\n root = root['tbsCertificate'];\n\n alg = oid_name[root[\"signatureAlgorithm\"]];\n\n attr =\n 'Subject : ' + format_dn(root[\"subject\"]) + '\\n' +\n 'Issuer : ' + format_dn(root[\"issuer\"]) + '\\n' +\n 'Valid From : ' + root[\"validity\"][\"notBefore\"] + '\\n' +\n 'Valid To : ' + root[\"validity\"][\"notAfter\"] + '\\n' +\n 'Signature Algorithm : ' + alg + '\\n';\n\n valid = FALSE;\n replace_kb_item(name:\"SSL/Chain/Root/\" + port, value:attr);\n }\n}\n\nfunction check_chain_ext_basic_constraints()\n{\n local_var attr, bit, bits, cert, ext, i, j, key, reason;\n ssl_dbg(src:src, msg:'check_chain_ext_basic_constraints()');\n\n key = \"SSL/Chain/Extension/BasicConstraints\";\n j = 0;\n\n # Verify that each certificate in the chain is issued properly by\n # another one. The top certificate is the only one that can be\n # self-signed, which has special rules in the RFC. As a result, we\n # skip it. The final certificate in the chain is also skipped since\n # the RFC isn't explicit about its handling, so we'll play it safe.\n for (i = max_index(chain) - 2; i >= 1; i--)\n {\n # Extract the certificate from the chain, which we know to be\n # ordered.\n cert = chain[i][\"tbsCertificate\"];\n\n # Skip known certificates.\n if (find_issuer_idx(CA:CAs, cert:cert) >= 0)\n continue;\n\n # Check that the certificate has extensions that follow the RFC.\n reason = check_cert_ext_basic_constraints(idx:i, cert:cert);\n if (reason == TRUE)\n continue;\n\n # Note that since this check won't necessarily cause errors in SSL\n # clients, we don't mark the chain as invalid.\n\n # Extract attributes we want to report on.\n attr =\n 'Subject : ' + format_dn(cert[\"subject\"]) + '\\n' +\n 'Issuer : ' + format_dn(cert[\"issuer\"]) + '\\n' +\n 'Version : ' + (cert[\"version\"] + 1) + '\\n';\n\n # Add basic constraints extension contents.\n ext = cert_get_ext(id:EXTN_BASIC_CONSTRAINTS, cert:cert);\n if (!isnull(ext))\n {\n attr += \"Basic Constraints : \";\n\n attr += \"Critical:\";\n if (cert_get_ext(id:EXTN_BASIC_CONSTRAINTS, field:\"critical\", cert:cert))\n attr += \"TRUE\";\n else\n attr += \"FALSE\";\n\n attr += \", CA:\";\n if (ext[\"ca\"])\n attr += \"TRUE\";\n else\n attr += \"FALSE\";\n\n if (!isnull(ext[\"pathlen\"]))\n attr += \", pathlen:\" + ext[\"pathlen\"];\n\n attr += '\\n';\n }\n\n # Add key usage extension contents.\n ext = cert_get_ext(id:EXTN_KEY_USAGE, cert:cert);\n if (!isnull(ext))\n {\n attr += \"Key Usage : \";\n\n attr += \"Critical:\";\n if (cert_get_ext(id:EXTN_KEY_USAGE, field:\"critical\", cert:cert))\n attr += \"TRUE\";\n else\n attr += \"FALSE\";\n\n bits = make_list();\n foreach bit (keys(key_usage))\n {\n if ((ext & bit) != 0)\n bits = make_list(bits, key_usage[bit]);\n }\n\n if (max_index(bits) > 0)\n attr += \", \" + join(bits, sep:\", \");\n\n attr += '\\n';\n }\n\n # Record this certificate's specific error.\n set_kb_item(name:key + \"/\" + port + \"/Attributes/\" + j, value:attr);\n set_kb_item(name:key + \"/\" + port + \"/Reason/\" + j, value:reason);\n\n j++;\n }\n\n if (j != 0)\n set_kb_item(name:key, value:port);\n\n return NULL;\n}\n\n######################################################################\n# Certificate Expiry Failures\n######################################################################\nfunction check_chain_expired()\n{\n local_var attr, cert, key, offset, subj, time, type, types, when, now,\n date_checks, compare_date, future_warning_days, cert_expired;\n ssl_dbg(src:src, msg:'check_chain_expired()');\n\n types = make_array(\n \"After\", \" \",\n \"Before\", \" \"\n );\n\n foreach cert (chain)\n {\n cert = cert[\"tbsCertificate\"];\n\n # Extract attributes we want to report on.\n when = cert[\"validity\"];\n subj = format_dn(cert[\"subject\"]);\n\n future_warning_days = get_kb_item('SSL/settings/future_warning_days'); # set by ssl_cert_expiry.nasl\n if (future_warning_days <= 0)\n future_warning_days = 60;\n\n # Allow this part of the plugin to be tested without having to fake the system clock\n now = get_kb_item(\"TEST_ssl_certificate_chain_stubbed_unixtime\");\n if (isnull(now))\n now = unixtime();\n\n date_checks = make_array(\"SSL/Chain/Expiry/\", now, # now, should be first in list\n \"SSL/Chain/Future_Expiry/\", now + (60*60*24*future_warning_days));\n\n cert_expired = FALSE;\n foreach key (keys(date_checks))\n {\n compare_date = date_checks[key];\n foreach type (keys(types))\n {\n time = when[\"not\" + type];\n\n # Skip certificates that are within their valid range.\n offset = date_cmp(time, base_date:compare_date);\n if (\n (type == \"After\" && offset <= 0) ||\n (type == \"Before\" && offset >= 0)\n ) continue;\n\n # Mark the chain as having an error.\n if(key == \"SSL/Chain/Expiry/\")\n {\n broken = TRUE;\n valid = FALSE;\n cert_expired = TRUE;\n }\n else if(key == \"SSL/Chain/Future_Expiry/\")\n {\n # don't double report future expiry if certificate is already expired... \n if(cert_expired) continue;\n }\n \n # Format the attributes that the plugin that reports this issue\n # will need in its output, to prevent having to reparse the\n # certificates.\n attr =\n 'Subject ' + types[type] + ' : ' + subj + '\\n' +\n 'Not ' + type + ' : ' + time + '\\n';\n set_kb_item(name:key + type + \"/\" + port, value:attr);\n }\n }\n }\n return NULL;\n}\n\n######################################################################\n# Certificate Signature Failures\n######################################################################\nfunction check_chain_signed()\n{\n local_var alg, attr, cert, e, hash, i, key, n, pki, seq, sig, state, x, y, curve_oid;\n local_var subj, unsigned_cert;\n local_var chain_len;\n local_var issuer;\n local_var pss_hash, pss_mgfhash, saltlen;\n ssl_dbg(src:src, msg:'check_chain_signed()');\n\n key = \"SSL/Chain/Signature/\";\n\n chain_len = max_index(chain);\n for (i = 0; i < chain_len; i++)\n {\n cert = chain[i];\n\n # Extract the signature information from the certificate.\n alg = cert[\"signatureAlgorithm\"];\n sig = cert[\"signatureValue\"];\n\n # Find the issuing certificate, since we need its public key\n # information to extract check the signed hash of the certificate.\n if (i < chain_len - 1)\n {\n # Certificates should always be issued by subsequent\n # certificates due to the sorting done by check_chain_used().\n issuer = chain[i + 1];\n if (!is_signed_by(cert, issuer))\n {\n err_print(format_dn(cert[\"tbsCertificate\"][\"subject\"]) + \" is not signed by the subsequent certificate in the chain.\");\n continue;\n }\n }\n else\n {\n # If the last certificate isn't self-signed, check_chain_ca()\n # will have flagged it.\n if (!is_self_signed(cert))\n continue;\n\n issuer = cert;\n }\n\n # Extract the public key from the certificate.\n pki = issuer[\"tbsCertificate\"][\"subjectPublicKeyInfo\"];\n if (isnull(pki) || isnull(pki[1]))\n {\n state = \"Algorithm/Unknown\";\n }\n else if (oid_name[alg] == \"RSA-PSS Signature Scheme\")\n {\n n = pki[1][0];\n e = pki[1][1];\n\n # Signatures are an ASN.1 BIT STRING for historical reasons.\n # The first byte is the number of unused/padding bits in the BIT STRING.\n # If it's zero, we just remove it.\n # nb: this snip is borrowed from the other RSA code.\n if (ord(sig[0]) == 0)\n sig = substr(sig, 1, strlen(sig) - 1);\n if (ord(n[0]) == 0)\n n = substr(n, 1, strlen(n) - 1);\n\n # Compare the parameters on the CA certificate to the parameters on the leaf certificate.\n # See RFC 4055 sect. 3.3 for these rules.\n # * If the CA certificate is 'rsaEncryption' instead of 'rsaPss', then anything goes\n # * If the CA certificate is 'rsaPss' but has *absent* parameters, anything goes\n # * If the CA certificate is 'rsaPss' and has any parameters, full validation is needed\n # If validation fails (e.g. if the leaf is using a different hash), the whole\n # signature check fails.\n if (oid_name[pki[0]] == \"RSA-PSS Signature Scheme\" && pki[2] != FALSE)\n {\n set_kb_item(name:\"SSL/Chain/RSAPSS/ParameterValidation/\" + port, value:TRUE);\n\n # If we couldn't parse the parameters on the CA or on the leaf\n # The parsing does handle absent parameters and sets them to FALSE, not NULL.\n if (isnull(pki[2]) || isnull(cert.signatureAlgorithmParameters))\n {\n set_kb_item(name:\"SSL/Chain/RSAPSS/CAOrLeafParamsUnparsed/\" + port, value:TRUE);\n state = FALSE;\n }\n\n # Special case. RSAPSS keys may have no parameters, but signatures must have\n # parameters, even if they are \"empty\" (in which case, defaults are taken).\n if (cert.signatureAlgorithmParameters == FALSE)\n {\n set_kb_item(name:\"SSL/Chain/RSAPSS/LeafSignatureMissingParameters/\" + port, value:TRUE);\n state = FALSE;\n }\n\n # If algorithm is not MGF1, we won't be able to validate it\n if (oid_name[cert.signatureAlgorithmParameters[1].value] != \"MGF1\")\n {\n set_kb_item(name:\"SSL/Chain/RSAPSS/UnsupportedMGF/\" + port, value:TRUE);\n state = FALSE;\n }\n\n # If the trailer field isn't '1', we probably can't verify the certificate anyways\n # The RFC specifies '1' as the only legal value.\n if (pki[2][3] != 1)\n {\n set_kb_item(name:\"SSL/Chain/RSAPSS/IllegalTrailerField/\" + port, value:TRUE);\n state = FALSE;\n }\n\n # Make sure parameters are copacetic.\n if (cmp_rsapss_parameters(ca:pki[2], leaf:cert.signatureAlgorithmParameters) == FALSE)\n {\n set_kb_item(name:\"SSL/Chain/RSAPSS/IllegalParameters/\" + port, value:TRUE);\n state = FALSE;\n }\n }\n else\n set_kb_item(name:\"SSL/Chain/RSAPSS/ParameterValidation/\" + port, value:FALSE);\n\n # Pull out the things that might be specially configured.\n # We don't pull out the trailer field or MGF algorithm, because only one of\n # each is standardized.\n pss_hash = alg_pointer[oid_name[cert.signatureAlgorithmParameters[0].value]];\n pss_mgfhash = alg_pointer[oid_name[cert.signatureAlgorithmParameters[1].hash]];\n saltlen = cert.signatureAlgorithmParameters[2].value;\n\n if (typeof(pss_hash) != \"function\" || typeof(pss_mgfhash) != \"function\" || typeof(saltlen) != 'int')\n {\n state = \"Algorithm/Unsupported\";\n }\n\n # Only check the signature if we didn't already fail the validation\n if (isnull(state))\n {\n # Extract the signed portion of the certificate, in DER format.\n seq = der_parse_sequence(seq:cert[\"raw\"], list:TRUE);\n unsigned_cert = seq[1];\n\n # Verify the signature\n state = rsa_pss_emsa_verify(\n em:rsa_pss_decrypt_em(n:n, e:e, sig:sig),\n msg:unsigned_cert,\n embits:num_bits(n:n) - 1,\n hash:pss_hash,\n mgfhash:pss_mgfhash,\n slen:saltlen\n );\n if (state == FALSE)\n set_kb_item(name:\"SSL/Chain/RSAPSS/SignatureCheckFailed/\" + port, value:TRUE);\n }\n }\n else if (\"RSA Encryption\" >< oid_name[alg] || \"RSA Signature\" >< oid_name[alg])\n {\n n = pki[1][0];\n e = pki[1][1];\n\n if (ord(sig[0]) == 0)\n sig = substr(sig, 1, strlen(sig) - 1);\n if (ord(n[0]) == 0)\n n = substr(n, 1, strlen(n) - 1);\n\n # Decrypt the hash using the issuer's public key.\n hash = rsa_public_decrypt(sig:sig, n:n, e:e);\n\n # Extract the signed portion of the certificate, in DER format.\n seq = der_parse_sequence(seq:cert[\"raw\"], list:TRUE);\n unsigned_cert = seq[1];\n\n # Verify that the signed hash from the signature matches the hash\n # we calculate.\n if (oid_name[alg] == \"SHA-256 With RSA Encryption\")\n {\n if (!defined_func(\"SHA256\"))\n state = \"Algorithm/Unsupported\";\n else\n state = (SHA256(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"SHA-384 With RSA Encryption\")\n {\n if (!defined_func(\"SHA384\"))\n state = \"Algorithm/Unsupported\";\n else\n state = (SHA384(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"SHA-512 With RSA Encryption\")\n {\n if (!defined_func(\"SHA512\"))\n state = \"Algorithm/Unsupported\";\n else\n state = (SHA512(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"SHA-224 With RSA Encryption\")\n {\n if (!defined_func(\"SHA224\"))\n state = \"Algorithm/Unsupported\";\n else\n state = (SHA224(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"SHA-1 With RSA Encryption\")\n {\n state = (SHA1(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"MD5 With RSA Encryption\")\n {\n state = (MD5(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"MD4 With RSA Encryption\")\n {\n state = (MD4(unsigned_cert) >< hash);\n }\n else if (oid_name[alg] == \"MD2 With RSA Encryption\")\n {\n state = (MD2(unsigned_cert) >< hash);\n }\n else\n {\n state = \"Algorithm/Unknown\";\n }\n }\n else if (\"ECDSA\" >< oid_name[alg] && ecc_functions_available())\n {\n x = pki[1][0];\n y = pki[1][1];\n curve_oid = pki[2];\n\n # Signatures are an ASN.1 BIT STRING for historical reasons, even\n # though inside the BIT STRING is a DER-encoded SEQUENCE of two\n # INTEGERS (for ECDSA signatures).\n # The first byte is the number of unused/padding bits in the BIT STRING,\n # and will always be zero for ECDSA signatures.\n if (ord(sig[0]) == 0)\n sig = substr(sig, 1);\n\n sig = parse_ecdsa_signaturevalue(sv:sig);\n\n # Extract the signed portion of the certificate, in DER format.\n # This should be the whole length of the raw certificate, not \n # stripping the last byte as previously done\n seq = der_parse_sequence(seq:cert[\"raw\"], list:TRUE);\n unsigned_cert = seq[1];\n\n # Verify that the signature on the certificate matches the signature we compute\n if (isnull(curve_nid.oid[curve_oid]))\n {\n state = \"Curve/Unrecognized\";\n }\n else if (oid_name[alg] == \"ECDSA With SHA-256\")\n {\n state = ecdsa_verify(curve_nid:curve_nid.oid[curve_oid], msg:unsigned_cert, x:x, y:y, r:sig.r, s:sig.s, hash:@SHA256);\n }\n else if (oid_name[alg] == \"ECDSA With SHA-384\")\n {\n state = ecdsa_verify(curve_nid:curve_nid.oid[curve_oid], msg:unsigned_cert, x:x, y:y, r:sig.r, s:sig.s, hash:@SHA384);\n }\n else if (oid_name[alg] == \"ECDSA With SHA-512\")\n {\n state = ecdsa_verify(curve_nid:curve_nid.oid[curve_oid], msg:unsigned_cert, x:x, y:y, r:sig.r, s:sig.s, hash:@SHA512);\n }\n else if (oid_name[alg] == \"ECDSA With SHA-1\")\n {\n state = ecdsa_verify(curve_nid:curve_nid.oid[curve_oid], msg:unsigned_cert, x:x, y:y, r:sig.r, s:sig.s, hash:@SHA1);\n }\n else\n {\n state = \"Algorithm/Unknown\";\n }\n }\n else if (!isnull(oid_name[alg]))\n {\n state = \"Algorithm/Unsupported\";\n }\n else\n {\n state = \"Algorithm/Unknown\";\n }\n\n # If nothing was wrong with this certificate, move on to the next\n # one.\n if (state == TRUE)\n continue;\n\n # Mark the chain as having an error.\n broken = TRUE;\n valid = FALSE;\n\n # Extract attributes we want to report on.\n subj = format_dn(cert[\"tbsCertificate\"][\"subject\"]);\n\n # Format the attributes that the plugin that reports this issue\n # will need in its output, to prevent having to re-parse the\n # certificates.\n if (state == \"Algorithm/Unknown\")\n {\n attr =\n 'Subject : ' + subj + '\\n' +\n 'Algorithm (OID) : ' + alg + '\\n';\n }\n else if (state == \"Algorithm/Unsupported\")\n {\n attr =\n 'Subject : ' + subj + '\\n' +\n 'Algorithm (Name) : ' + oid_name[alg] + '\\n';\n }\n # This may happen if Ed25519 and other certificates become popular\n else if (state == \"Curve/Unrecognized\")\n {\n attr =\n 'Subject : ' + subj + '\\n' +\n 'Algorithm (Name) : ' + oid_name[alg] + '\\n' +\n 'EC Curve (OID) : ' + curve_oid + '\\n';\n }\n else\n {\n state = \"Bad\";\n attr =\n 'Subject : ' + subj + '\\n' +\n 'Hash : ' + hexstr(hash) + '\\n';\n }\n\n set_kb_item(name:key + state + \"/\" + port, value:attr);\n }\n return NULL;\n}\n\n######################################################################\n# Certificate With Weak RSA Keys\n######################################################################\nfunction check_weak_rsa_keys()\n{\n local_var attr, cert, key, len, min, min_list, weak_min_keylens, issued_year,\n issued_month, issued_day, temp, time, when;\n ssl_dbg(src:src, msg:'check_weak_rsa_keys()');\n\n # 1024-bit RSA keys are considered to be the minimum safe length\n # nowadays.\n # keys less than 2048 bits will be considered unsafe by Microsoft\n # in October 2013\n min_list = make_list(1024, 2048);\n\n key = \"SSL/Chain/WeakRSA_Under_\";\n weak_min_keylens = make_list();\n\n foreach cert (chain)\n {\n # Only check RSA keys\n if (\"RSA\" >!< oid_name[cert[\"tbsCertificate\"][\"subjectPublicKeyInfo\"][0]])\n continue;\n\n # Calculate the length of the certificate's public key.\n len = der_bit_length(cert, \"tbsCertificate\", \"subjectPublicKeyInfo\", 1, 0);\n if (isnull(len))\n continue;\n\n # Format the attributes that the plugin that reports this issue\n # will need in its output, to prevent having to re-parse the\n # certificates.\n attr =\n 'Subject : ' + format_dn(cert[\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'RSA Key Length : ' + len + ' bits\\n';\n\n foreach min (min_list)\n {\n # Determine if the key is strong enough.\n if (len == 0 || len >= min)\n continue;\n\n # Exception:\n # A Root CA Certificate issued prior to 31 Dec. 2010 with an RSA key size less than 2048 bits\n # MAY still serve as a trust anchor for Subscriber Certificate\n if (min == 2048 && is_self_signed(cert[\"tbsCertificate\"]))\n {\n when = cert[\"tbsCertificate\"][\"validity\"];\n time = when[\"notBefore\"];\n temp = split(time, sep:\" \", keep:FALSE);\n\n issued_year = int(temp[3]);\n issued_month = month_num_by_name(temp[0], base:1);\n issued_day = int(temp[1]);\n\n if (\n !get_kb_item(\"Settings/PCI_DSS\") &&\n ((issued_year < 2010) ||\n (issued_year == 2010 && issued_month < 12) ||\n (issued_year == 2010 && issued_month == 12 && issued_day < 31))\n ) continue;\n }\n\n weak_min_keylens = make_list(weak_min_keylens, min);\n\n set_kb_item(name:key + min, value: port);\n set_kb_item(name:key + min + \"/\" + port, value: attr);\n }\n }\n return NULL;\n}\n\n######################################################################\n# Certificate With Weak Hash Algorithm\n######################################################################\nfunction check_weak_hashes()\n{\n local_var alg, attr, cert, key, key_ca, known_ca, weak_alg, weak_algs,\n subject,tag, when, issued_time, expire_time, expire_temp,\n expire_year, expire_month, expire_day, hash, sig_algorithm,\n cert_count, issuer_idx;\n ssl_dbg(src:src, msg:'check_weak_hashes()');\n\n weak_algs = make_list(\n \"1.2.840.113549.1.1.2\", # MD2 with RSA Encryption\n \"1.2.840.113549.1.1.3\", # MD4 with RSA Encryption\n \"1.2.840.113549.1.1.4\", # MD5 with RSA Encryption\n \"1.2.840.113549.1.1.5\", # SHA1 with RSA Encryption\n \"1.2.840.10045.4.1\", # ECDSA with SHA1\n \"RSA-PSS Signature Scheme with SHA-1\", # Not written as OIDs, these are handled specially\n \"RSA-PSS Signature Scheme with MD5\",\n \"RSA-PSS Signature Scheme with MD4\"\n );\n\n key = \"SSL/Chain/WeakHash\";\n key_ca = \"SSL/Chain/KnownCA/WeakHash\";\n tag = \"SSL/Chain/SHA-1/JAN-DEC-16\";\n\n cert_count = -1;\n\n foreach cert (chain)\n {\n # Exception:\n # If we flag certificates that are CAs with this check, we are\n # definitely going to get complaints. To avoid this, only flag\n # certificates that are below other certificates in our CA\n # databases to be reported on by ssl_weak_hash.nasl as Medium\n # severity. Flag CAs separately to be reported on by\n # ssl_weak_hash_ca.nasl as informational.\n #\n # Note: We send the subject to find_issuer_idx() because we want\n # to know if the certificate IS a known CA certificate, not if\n # it is ISSUED BY a known CA.\n known_ca = FALSE;\n subject = cert[\"tbsCertificate\"][\"subject\"];\n if (find_issuer_idx(CA:CAs, issuer:subject, ignore_custom:TRUE) >= 0)\n known_ca = TRUE;\n\n cert_count++;\n # Ignore any cert that is both whitelisted and is the root CA.\n if ( cert_count == (max_index(chain)-1))\n {\n issuer_idx = find_issuer_idx(CA:CAs, cert:cert);\n if ( issuer_idx >= 0 && CAs_whitelist[issuer_idx])\n {\n continue;\n }\n }\n\n # Get the hash algorithm used by the certificate.\n alg = cert[\"signatureAlgorithm\"];\n if (isnull(alg))\n continue;\n\n # Special case for RSA-PSS: the hash algorithm is not a part of\n # the AlgorithmIdentifier, so instead we pull it out and construct\n # a fake \"alg\" to use.\n # We consider only the PSS \"hash\" parameter, as it is equivalent\n # to the hash used in other signature algorithms.\n # We do not consider the hash used by MGF-1 (which might be MD5 or\n # SHA-1) because it does not have as strict of requirements.\n if (oid_name[alg] == \"RSA-PSS Signature Scheme\")\n {\n hash = oid_name[cert.signatureAlgorithmParameters[0].value];\n if (isnull(hash))\n continue;\n alg = \"RSA-PSS Signature Scheme with \" + hash;\n sig_algorithm = alg;\n }\n else\n {\n sig_algorithm = oid_name[alg];\n }\n\n foreach weak_alg (weak_algs)\n {\n # Algorithm is in the weak list *and* uses SHA-1.\n # RSA with SHA-1, ECDSA with SHA-1, or RSA-PSS with SHA-1.\n if (alg == weak_alg && (\"1.2.840.113549.1.1.5\" >< weak_alg || \"1.2.840.10045.4.1\" >< weak_alg || \"SHA-1\" >< weak_alg))\n {\n when = cert[\"tbsCertificate\"][\"validity\"];\n issued_time = when[\"notBefore\"];\n expire_time = when[\"notAfter\"];\n\n if (isnull(issued_time) || isnull(expire_time))\n exit(1, \"The SSL certificate does not contain a valid date in the valid to or from fields.\");\n\n expire_temp = split(expire_time, sep:\" \", keep:FALSE);\n\n expire_year = int(expire_temp[3]);\n expire_month = month_num_by_name(expire_temp[0], base:1);\n expire_day = int(expire_temp[1]);\n\n # SHA-1 certificate that expires on or after January 1, 2017 should should be\n # reported in ssl_weak_hash.nasl\n if (\n get_kb_item(\"Settings/PCI_DSS\") ||\n (int(expire_year) >= 2017 &&\n int(expire_month) >= 01 &&\n int(expire_day) >= 01))\n {\n # Format the attributes that the plugin that reports this issue\n # will need in its output, to prevent having to re-parse the\n # certificates.\n attr =\n 'Subject : ' + format_dn(cert[\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'Signature Algorithm : ' + sig_algorithm + '\\n' +\n 'Valid From : ' + issued_time + '\\n' +\n 'Valid To : ' + expire_time + '\\n';\n if(known_ca)\n {\n set_kb_item(name:key_ca, value:port);\n set_kb_item(name:key_ca + \"/\" + port, value:attr);\n }\n else\n {\n set_kb_item(name:key, value:port);\n set_kb_item(name:key + \"/\" + port, value:attr);\n }\n break;\n }\n\n # SHA-1 certificate that expires between January 1, 2016 and December 31, 2016 should\n # be reported in an informational plugin.\n else if (int(expire_year) == 2016 && int(expire_month) <= 12 && int(expire_day) <= 31)\n {\n # Format the attributes that the plugin that reports this issue\n # will need in its output, to prevent having to re-parse the\n # certificates.\n attr =\n 'Subject : ' + format_dn(cert[\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'Signature Algorithm : ' + sig_algorithm + '\\n' +\n 'Valid From : ' + issued_time + '\\n' +\n 'Valid To : ' + expire_time + '\\n';\n set_kb_item(name:tag, value:port);\n set_kb_item(name:tag + \"/\" + port, value:attr);\n break;\n }\n\n # SHA-1 certificate issued before January 1, 2016 should be discarded and ignored and\n # not reported in a plugin.\n else if (int(expire_year) < 2016)\n {\n break;\n }\n }\n\n else if (alg == weak_alg)\n {\n when = cert[\"tbsCertificate\"][\"validity\"];\n issued_time = when[\"notBefore\"];\n expire_time = when[\"notAfter\"];\n\n if (isnull(issued_time) || isnull(expire_time))\n exit(1, \"The SSL certificate does not contain dates in the valid to or from fields.\");\n\n # Format the attributes that the plugin that reports this issue\n # will need in its output, to prevent having to re-parse the\n # certificates. Reporting for MD2, MD4, and MD5\n attr =\n 'Subject : ' + format_dn(cert[\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'Signature Algorithm : ' + sig_algorithm + '\\n' +\n 'Valid From : ' + issued_time + '\\n' +\n 'Valid To : ' + expire_time + '\\n';\n if(known_ca)\n {\n set_kb_item(name:key_ca, value:port);\n set_kb_item(name:key_ca + \"/\" + port, value:attr);\n }\n else\n {\n set_kb_item(name:key, value:port);\n set_kb_item(name:key + \"/\" + port, value:attr);\n }\n break;\n }\n }\n }\n return NULL;\n}\n\n######################################################################\n# Certificate with a Certificate Revocation List URL\n######################################################################\nfunction check_crls()\n{\n local_var cert, crl, ext, host, i, kb;\n ssl_dbg(src:src, msg:'check_crls()');\n\n crl = FALSE;\n host = get_host_name();\n kb = \"SSL/CRL/\" + get_host_name();\n\n for (i = 0; i < max_index(chain); i++)\n {\n cert = chain[i][\"tbsCertificate\"];\n\n # Don't check on the CRLs of CAs, since that'll generate even more\n # traffic.\n if (find_issuer_idx(CA:CAs, issuer:cert[\"subject\"]) >= 0)\n continue;\n\n # Extract key CRL extension.\n ext = cert_get_ext(id:EXTN_CRL_DIST_POINTS, cert:cert);\n if (\n isnull(ext) ||\n isnull(ext[0]) ||\n isnull(ext[0][\"distributionPoint\"]) ||\n isnull(ext[0][\"distributionPoint\"][0]) ||\n isnull(ext[0][\"distributionPoint\"][0][\"uniformResourceIdentifier\"])\n ) continue;\n\n # Store CRL information in the global KB.\n kb = \"SSL/CRL/\" + host + \"/\" + port;\n set_global_kb_item(name:kb, value:i);\n kb += \"/\" + i;\n\n set_global_kb_item(\n name : kb + \"/URL\",\n value : ext[0][\"distributionPoint\"][0][\"uniformResourceIdentifier\"]\n );\n set_global_kb_item(\n name : kb + \"/Subject\",\n value : format_dn(cert[\"subject\"])\n );\n\n crl = TRUE;\n }\n\n if (crl)\n {\n set_global_kb_item(name:\"SSL/CRL/Host\", value:host);\n set_global_kb_item(name:\"SSL/CRL/\" + host, value:port);\n }\n return NULL;\n}\n\n######################################################################\n# Validate the certificate(s) via OCSP\n######################################################################\nfunction check_ocsp()\n{\n local_var key, i, ocsp_result, attr;\n ssl_dbg(src:src, msg:'check_ocsp()');\n\n if (!get_global_kb_item(\"global_settings/enable_crl_checking\"))\n {\n return NULL;\n }\n\n key = \"SSL/Chain/OCSP/\";\n for (i = 0; i < max_index(chain); i++)\n {\n if (has_ocsp(server_der_cert:chain[i][\"raw\"]))\n {\n ocsp_result = do_ocsp(server_der_cert:chain[i][\"raw\"]);\n\n if (!isnull(ocsp_result['ocsp_failure']))\n {\n # This error is generally OCSP responder didn't reply or couldn't download\n # the issuer cert. It could be that the server is down/unreachable for a\n # moment, but I think its better to flag the whole thing as shady.\n broken = true;\n attr =\n 'Subject : ' + format_dn(chain[i][\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'OCSP Status : ' + ocsp_result['ocsp_failure'] + '\\n';\n set_kb_item(name:\"SSL/Chain/OCSP/Status/\" + port, value:attr);\n }\n else\n {\n if (isnull(ocsp_result['revocation_status']))\n {\n # This means we entirely failed parsing somehow. Originally I had this\n # flagging the certificate. However, I don't want to create false positives\n # so I'll just leave this stubbed out.\n }\n else if (ocsp_result['revocation_status'] == \"Revoked\")\n {\n broken = true;\n attr =\n 'Subject : ' + format_dn(chain[i][\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'OCSP Status : Revoked\\n';\n set_kb_item(name:\"SSL/Chain/OCSP/Status/\" + port, value:attr);\n }\n\n if (!isnull(ocsp_result['verify_ocsp_response']) &&\n ocsp_result['verify_ocsp_response'] != \"Valid Signature\" &&\n \"Unhandled Signature Algorithm\" >!< ocsp_result['verify_ocsp_response'])\n {\n # This could be a general failure to decrypt the signature or just a bad signature\n broken = true;\n attr =\n 'Subject : ' + format_dn(chain[i][\"tbsCertificate\"][\"subject\"]) + '\\n' +\n 'OCSP Signature : ' + ocsp_result['verify_ocsp_response'] + '\\n';\n set_kb_item(name:\"SSL/Chain/OCSP/Signature/\" + port, value:attr);\n }\n }\n }\n }\n return NULL;\n}\n\n######################################################################\n# Certificate Authority Failures\n######################################################################\nfunction check_chain_ca()\n{\n local_var attr, cert, copy, i, issuer, key, res;\n ssl_dbg(src:src, msg:'check_chain_ca()');\n\n # Try and complete the certificate chain using the certificate\n # authorities that we know about.\n i = max_index(chain) - 1;\n while (TRUE)\n {\n cert = chain[i][\"tbsCertificate\"];\n\n # A valid chain ends on a self-signed certificate.\n if (is_self_signed(cert))\n break;\n\n # Try to find the certificate that signed the one at the top of\n # the chain.\n issuer = find_issuer_idx(CA:CAs, cert:cert);\n if (issuer < 0)\n break;\n\n # Keep the raw version of the certificate embedded, for verifying\n # signatures.\n copy = CAs[issuer];\n copy[\"raw\"] = CAs_raw[issuer];\n\n # Add the signing certificate to the top of the chain.\n chain[++i] = copy;\n }\n\n # So long as the top certificate in the chain is signed by a known\n # CA, we're okay.\n if (find_issuer_idx(CA:CAs, cert:cert) >= 0)\n return 0;\n\n # Mark the chain as having an error.\n broken = TRUE;\n valid = FALSE;\n\n # Format the attributes that the plugin that reports this issue will\n # need in its output, to prevent having to re-parse the\n # certificates.\n attr =\n 'Subject : ' + format_dn(cert[\"subject\"]) + '\\n' +\n 'Issuer : ' + format_dn(cert[\"issuer\"]) + '\\n';\n set_kb_item(name:\"SSL/Chain/UnknownCA/\" + port, value:attr);\n return NULL;\n}\n\n######################################################################\n# Self-Signed Certificates\n######################################################################\nfunction check_chain_self_signed()\n{\n local_var attr, cert, key;\n ssl_dbg(src:src, msg:'check_chain_self_signed()');\n\n # Get the certificate from the top of the chain.\n cert = chain[max_index(chain) - 1];\n cert = cert[\"tbsCertificate\"];\n\n # Skip certificates that aren't self-signed.\n if (!is_self_signed(cert))\n return 0;\n\n # Known, self-signed certificates will return a non-negative index.\n # We're not interested in those, here.\n if (find_issuer_idx(CA:CAs, cert:cert) >= 0)\n return 0;\n\n # Save the unused certificates to the KB for use by other plugins.\n key = \"SSL/Chain/SelfSigned\";\n set_kb_item(name:key, value:port);\n key += \"/\" + port;\n\n # Format the attributes that the plugin that reports this issue will\n # need in its output, to prevent having to re-parse the\n # certificates.\n attr = 'Subject : ' + format_dn(cert[\"subject\"]) + '\\n';\n set_kb_item(name:key, value:attr);\n return NULL;\n}\n\n######################################################################\n# Unordered Certificates\n######################################################################\nfunction check_chain_sorted()\n{\n local_var attr, cert, i, key, sorted;\n ssl_dbg(src:src, msg:'check_chain_sorted()');\n\n key = \"SSL/Chain/Unordered\";\n\n # If the sorted chain is the same as the unsorted chain, then it was\n # ordered and we're done.\n if (obj_cmp(chain, unsorted))\n return 0;\n\n # Save the fact that the chain was unordered to the KB for use by\n # other plugins.\n set_kb_item(name:key, value:port);\n\n # Format the attributes that the plugin that reports this issue will\n # need in its output, to prevent having to re-parse the\n # certificates.\n i = 0;\n key += \"/\" + port + \"/\";\n foreach cert (unsorted)\n {\n cert = cert[\"tbsCertificate\"];\n attr =\n 'Subject : ' + format_dn(cert[\"subject\"]) + '\\n' +\n 'Issuer : ' + format_dn(cert[\"issuer\"]) + '\\n';\n set_kb_item(name:key + i++, value:attr);\n }\n return NULL;\n}\n\n######################################################################\n# Unused Certificates\n######################################################################\nfunction check_chain_used()\n{\n local_var attr, cert, key, res;\n ssl_dbg(src:src, msg:'check_chain_used()');\n\n # Sort the chain, returning both the used and unused certificates.\n res = sort_cert_chain(unsorted, filter:FALSE, raw:FALSE);\n if (isnull(res) || max_index(res[0]) == 0)\n exit(1, \"Failed to sort certificate chain from port \" + port + \".\");\n\n # Store the ordered version of the chain, so the sort is only done\n # once.\n chain = res[0];\n\n # If there are no unused certificates, we're done.\n if (max_index(res[1]) == 0)\n return 0;\n\n # Save the unused certificates to the KB for use by other plugins.\n key = \"SSL/Chain/Unused\";\n set_kb_item(name:key, value:port);\n key += \"/\" + port;\n\n # Format the attributes that the plugin that reports this issue will\n # need in its output, to prevent having to re-parse the\n # certificates.\n foreach cert (res[1])\n {\n cert = cert[\"tbsCertificate\"];\n attr = add_rdn_seq_nl(seq:cert[\"subject\"]);\n set_kb_item(name:key, value:attr);\n }\n return NULL;\n}\n\n######################################################################\n# Main Body\n######################################################################\nget_kb_item_or_exit(\"SSL/Supported\");\n\n# Load up the certs of CAs we're aware of.\nCAs = load_CA();\nif (isnull(CAs) || isnull(CAs[0]) || max_index(CAs[0]) == 0)\n exit(1, \"Could not load the list of SSL certificates.\");\nCAs_whitelist = CAs[2];\nCAs_raw = CAs[1];\nCAs = CAs[0];\n\n# Get list of ports that use SSL or StartTLS.\nport = get_ssl_ports(fork:TRUE);\nif (isnull(port))\n exit(1, \"The host does not appear to have any SSL-based services.\");\n\n# Only consider open ports.\nif (!get_port_state(port))\n exit(0, \"Port \" + port + \" is not open.\");\n\n# Allow the plugin to be tested with just certificates in a KB with -k,\n# instead of having to have an SSL server somewhere.\nif (!get_kb_item(\"TEST_ssl_certificate_chain_do_not_open_socket\"))\n{\n ssl_dbg(src:src, msg:'Opening SSL socket on port '+port+'.');\n # Open socket, sending StartTLS commands if necessary.\n soc = open_sock_ssl(port);\n if (!soc)\n exit(1, \"Failed to connect to port \" + port + \".\");\n}\n\n# Retrieve the certificate chain the server is using for this port.\nssl_dbg(src:src, msg:'Getting certificates on port '+port+' socket '+\n soc+'.');\nunsorted = get_server_cert(\n socket : soc,\n port : port,\n encoding : \"der\",\n getchain : TRUE,\n sort : FALSE,\n securerenegotiation:TRUE\n);\nssl_dbg(src:src, msg:'Closing socket '+soc+'.');\nif (soc) close(soc);\nif (isnull(unsorted) || max_index(unsorted) == 0)\n exit(1, \"Failed to retrieve the certificate chain from port \" + port + \".\");\n\n# Parse the chain so that we only deal with parsed certificates in\n# this plugin.\nssl_dbg(src:src, msg:'Parsing certificate chain from port '+port+'.');\nunsorted = parse_cert_chain(unsorted);\nif (isnull(unsorted))\n exit(1, \"Failed to parse certificate in chain on port \" + port + \".\");\n\n# Run each check that we have on the certificate chain. The order of\n# the checks is significant, since the chain starts unordered for the\n# early checks, and is reordered for later checks.\nbroken = FALSE;\nvalid = TRUE;\ncheck_chain_used();\ncheck_chain_sorted();\ncheck_chain_self_signed();\ncheck_chain_ca();\ncheck_crls();\ncheck_ocsp();\ncheck_weak_hashes();\ncheck_weak_rsa_keys();\ncheck_chain_signed();\ncheck_chain_expired();\ncheck_chain_ext_basic_constraints();\ncheck_root_ca();\ncheck_distrusted_ca();\n\n# Record whether the chain has any errors.\nssl_dbg(src:src, msg:'Setting SSL/ValidCAChain/'+port+'='+valid);\nset_kb_item(name:\"SSL/ValidCAChain/\" + port, value:valid);\nif (broken)\n{\n ssl_dbg(src:src, msg:'Setting SSL/BrokenCAChain='+port);\n set_kb_item(name:\"SSL/BrokenCAChain\", value:port);\n}\n", "cvss": {"score": 0.0, "vector": "NONE"}}, {"lastseen": "2021-01-01T05:49:59", "description": "The SSL certificate for the remote SSL-enabled service is not yet\nvalid.", "edition": 19, "published": "2009-12-02T00:00:00", "title": "SSL Certificate Expiry - Future Validity", "type": "nessus", "bulletinFamily": "scanner", "cvelist": [], "modified": "2021-01-02T00:00:00", "cpe": [], "id": "SSL_CERT_FUTURE_VALIDITY.NASL", "href": "https://www.tenable.com/plugins/nessus/42980", "sourceData": "#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude(\"compat.inc\");\n\nif(description)\n{\n script_id(42980);\n script_version (\"$Revision: 1.8 $\");\n script_cvs_date(\"$Date: 2012/04/02 16:34:10 $\");\n\n script_name(english:\"SSL Certificate Expiry - Future Validity\");\n script_summary(english:\"Checks SSL certificate expiry\");\n\n script_set_attribute(\n attribute:'synopsis',\n value:\n\"There is a problem with the SSL certificate associated with the\nremote service.\"\n );\n script_set_attribute(\n attribute:'description',\n value:\n\"The SSL certificate for the remote SSL-enabled service is not yet\nvalid.\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\n\"Make sure that system clock on the Nessus Server host is not out of\nsync. If it's not, then purchase or generate a new SSL certificate to\nreplace the existing one.\"\n );\n script_set_attribute(attribute:\"risk_factor\", value:\"None\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2009/12/02\");\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_copyright(english:\"This script is Copyright (C) 2009-2012 Tenable Network Security, Inc.\");\n script_family(english:\"General\");\n\n script_dependencies(\"ssl_cert_expiry.nasl\");\n script_require_keys(\"SSL/Supported\");\n\n exit(0);\n}\n\ninclude(\"byte_func.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"misc_func.inc\");\ninclude(\"ssl_funcs.inc\");\n\nget_kb_item_or_exit(\"SSL/Supported\");\n\n# Get list of ports that use SSL or StartTLS.\nports = get_ssl_ports();\nif (isnull(ports) || max_index(ports) == 0)\n exit(1, \"The host does not appear to have any SSL-based services.\");\n\nforeach port (ports)\n{\n if (!get_port_state(port)) continue; \n\n future_valid_date = get_kb_item('Transport/SSL/'+port+'/future_validity_date');\n\n if (!isnull(future_valid_date))\n {\n if (report_verbosity > 0)\n {\n issuer = get_kb_item('Transport/SSL/'+port+'/issuer');\n subject = get_kb_item('Transport/SSL/'+port+'/subject');\n\n valid_start_alt = future_valid_date;\n valid_start_end = get_kb_item('Transport/SSL/'+port+'/valid_start_end');\n\n report = \n '\\n' + 'The SSL certificate is not valid before ' + future_valid_date + ' :' +\n '\\n' + \n '\\n Subject : ' + subject +\n '\\n Issuer : ' + issuer +\n '\\n Not valid before : ' + valid_start_alt +\n '\\n Not valid after : ' + valid_end_alt + '\\n';\n security_note(port:port, extra:report);\n }\n else security_note(port);\n }\n}\n", "cvss": {"score": 0.0, "vector": "NONE"}}, {"lastseen": "2020-09-09T05:04:39", "description": "The SSL certificate associated with the remote service will expire\nsoon.", "edition": 16, "published": "2009-12-02T00:00:00", "title": "SSL Certificate Expiry - Future Expiry", "type": "nessus", "bulletinFamily": "scanner", "cvelist": [], "modified": "2009-12-02T00:00:00", "cpe": [], "id": "SSL_CERT_FUTURE_EXPIRY.NASL", "href": "https://www.tenable.com/plugins/nessus/42981", "sourceData": "#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude(\"compat.inc\");\n\nif(description)\n{\n script_id(42981);\n script_version (\"1.9\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2020/09/04\");\n\n script_name(english:\"SSL Certificate Expiry - Future Expiry\");\n script_summary(english:\"Checks SSL certificate expiry\");\n\n script_set_attribute(\n attribute:'synopsis',\n value:\n\"The SSL certificate associated with the remote service will expire\nsoon.\"\n );\n script_set_attribute(\n attribute:'description',\n value:\n\"The SSL certificate associated with the remote service will expire\nsoon.\"\n );\n script_set_attribute(\n attribute:\"solution\", \n value:\n\"Purchase or generate a new SSL certificate in the near future to\nreplace the existing one.\"\n );\n script_set_attribute(attribute:\"risk_factor\", value:\"None\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2009/12/02\");\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n\n script_copyright(english:\"This script is Copyright (C) 2009-2020 Tenable Network Security, Inc.\");\n script_family(english:\"General\");\n\n script_dependencies(\"ssl_cert_expiry.nasl\");\n script_require_keys(\"SSL/Supported\");\n \n exit(0);\n}\n\ninclude(\"byte_func.inc\");\ninclude(\"ssl_funcs.inc\");\n\nget_kb_item_or_exit(\"SSL/Supported\");\n\n# Get list of ports that use SSL or StartTLS.\nports = get_ssl_ports();\nif (isnull(ports) || max_index(ports) == 0)\n exit(1, \"The host does not appear to have any SSL-based services.\");\n\nreport = '';\n\nforeach port (ports)\n{\n if (!get_port_state(port)) continue;\n\n if (get_kb_item('Transport/SSL/'+port+'/expired_cert')) continue;\n\n days_left = get_kb_item('Transport/SSL/'+port+'/days_to_expire');\n valid_end = get_kb_item('Transport/SSL/'+port+'/future_expiry_date');\n\n if (!isnull(days_left) && !isnull(valid_end))\n {\n issuer = get_kb_item('Transport/SSL/'+port+'/issuer');\n subject = get_kb_item('Transport/SSL/'+port+'/subject');\n valid_start = get_kb_item('Transport/SSL/'+port+'/valid_start');\n report = \n '\\n' + 'The SSL certificate will expire within ' + days_left + ' days, at' + \n '\\n' + valid_end + ' :' +\n '\\n' + \n '\\n Subject : ' + subject +\n '\\n Issuer : ' + issuer +\n '\\n Not valid before : ' + valid_start + \n '\\n Not valid after : ' + valid_end + '\\n';\n security_report_v4(port:port, extra:report, severity:SECURITY_NOTE);\n }\n}\n\nif (report == '') exit(0, \"No SSL certificates set to expire in identified range.\");\n", "cvss": {"score": 0.0, "vector": "NONE"}}]}