diff --git a/src/manage_sql.c b/src/manage_sql.c index d1c50dd078..a3cda06156 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -26944,6 +26944,194 @@ print_report_host_details_xml (report_host_t report_host, FILE *stream, return 0; } +/** + * @brief Print the XML for a report host's TLS certificates to a file stream. + * @param[in] report_host The report host to get certificates from. + * @param[in] host_ip The IP address of the report host. + * @param[in] stream File stream to write to. + * + * @return 0 on success, -1 error. + */ +static int +print_report_host_tls_certificates_xml (report_host_t report_host, + const char *host_ip, + FILE *stream) +{ + + iterator_t tls_certs; + time_t activation_time, expiration_time; + gchar *md5_fingerprint, *sha256_fingerprint, *subject, *issuer, *serial; + gnutls_x509_crt_fmt_t certificate_format; + + if (report_host == 0 + || strcmp (host_ip, "") == 0) + return -1; + + init_iterator (&tls_certs, + "SELECT rhd.value, rhd.name, rhd.source_name" + " FROM report_host_details AS rhd" + " WHERE rhd.report_host = %llu" + " AND (source_description = 'SSL/TLS Certificate'" + " OR source_description = 'SSL Certificate')", + report_host); + + while (next (&tls_certs)) + { + const char *certificate_prefixed, *certificate_b64; + gsize certificate_size; + unsigned char *certificate; + const char *scanner_fpr_prefixed, *scanner_fpr; + gchar *quoted_scanner_fpr; + char *ssldetails; + iterator_t ports; + gboolean valid; + time_t now; + + certificate_prefixed = iterator_string (&tls_certs, 0); + certificate_b64 = g_strrstr (certificate_prefixed, ":") + 1; + + certificate = g_base64_decode (certificate_b64, &certificate_size); + + scanner_fpr_prefixed = iterator_string (&tls_certs, 1); + scanner_fpr = g_strrstr (scanner_fpr_prefixed, ":") + 1; + + quoted_scanner_fpr = sql_quote (scanner_fpr); + + activation_time = -1; + expiration_time = -1; + md5_fingerprint = NULL; + sha256_fingerprint = NULL; + subject = NULL; + issuer = NULL; + serial = NULL; + certificate_format = 0; + + get_certificate_info ((gchar*)certificate, + certificate_size, + &activation_time, + &expiration_time, + &md5_fingerprint, + &sha256_fingerprint, + &subject, + &issuer, + &serial, + &certificate_format); + + if (sha256_fingerprint == NULL) + sha256_fingerprint = g_strdup (scanner_fpr); + + ssldetails + = sql_string ("SELECT rhd.value" + " FROM report_host_details AS rhd" + " WHERE report_host = %llu" + " AND name = 'SSLDetails:%s'" + " LIMIT 1;", + report_host, + quoted_scanner_fpr); + + if (ssldetails) + parse_ssldetails (ssldetails, + &activation_time, + &expiration_time, + &issuer, + &serial); + else + g_warning ("%s: No SSLDetails found for fingerprint %s", + __func__, + scanner_fpr); + + free (ssldetails); + + now = time (NULL); + + if((expiration_time >= now || expiration_time == -1) + && (activation_time <= now || activation_time == -1)) + { + valid = TRUE; + } + else + { + valid = FALSE; + } + char *hostname = sql_string ("SELECT value FROM report_host_details" + " WHERE report_host = %llu" + " AND name = 'hostname'", + report_host); + + PRINT (stream, + "" + "%s" + "%s" + "%s" + "%s" + "%d" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s%s", + scanner_fpr, + tls_certificate_format_str (certificate_format), + certificate_b64, + sha256_fingerprint, + md5_fingerprint, + valid, + certificate_iso_time (activation_time), + certificate_iso_time (expiration_time), + subject, + issuer, + serial, + host_ip, + hostname ? hostname : ""); + + + g_free (certificate); + g_free (md5_fingerprint); + g_free (sha256_fingerprint); + g_free (subject); + g_free (issuer); + g_free (serial); + + free (hostname); + + init_iterator (&ports, + "SELECT value FROM report_host_details" + " WHERE report_host = %llu" + " AND name = 'SSLInfo'" + " AND value LIKE '%%:%%:%s'", + report_host, + quoted_scanner_fpr); + + PRINT (stream, ""); + + while (next (&ports)) + { + const char *value; + gchar *port; + + value = iterator_string (&ports, 0); + port = g_strndup (value, g_strrstr (value, ":") - value - 1); + + PRINT (stream, "%s", port); + + g_free (port); + } + + PRINT (stream, ""); + + PRINT (stream, ""); + + g_free (quoted_scanner_fpr); + cleanup_iterator (&ports); + + } + cleanup_iterator (&tls_certs); + + return 0; +} + + /** * @brief Write report error message to file stream. * @@ -29574,7 +29762,6 @@ print_report_xml_start (report_t report, report_t delta, task_t task, } cleanup_iterator (&hosts); } - array_free (result_hosts); } else if (get->details) { @@ -29679,6 +29866,66 @@ print_report_xml_start (report_t report, report_t delta, task_t task, g_hash_table_destroy (f_host_logs); g_hash_table_destroy (f_host_false_positives); + + /* Print TLS certificates */ + + if (get->details && result_hosts_only) + { + gchar *result_host; + int index = 0; + PRINT (out, ""); + while ((result_host = g_ptr_array_index (result_hosts, index++))) + { + gboolean present; + iterator_t hosts; + init_report_host_iterator (&hosts, report, result_host, 0); + present = next (&hosts); + if (present) + { + report_host_t report_host = host_iterator_report_host(&hosts); + + if (print_report_host_tls_certificates_xml(report_host, + result_host, + out)) + { + fclose (out); + cleanup_iterator (&hosts); + tz_revert (zone, tz, old_tz_override); + return -1; + } + } + cleanup_iterator (&hosts); + } + PRINT (out, ""); + array_free (result_hosts); + } + else if (get->details) + { + const char *host; + iterator_t hosts; + init_report_host_iterator (&hosts, report, NULL, 0); + + PRINT (out, ""); + + while (next (&hosts)) + { + report_host_t report_host = host_iterator_report_host(&hosts); + host = host_iterator_host (&hosts); + + if (print_report_host_tls_certificates_xml(report_host, + host, + out)) + { + fclose (out); + cleanup_iterator (&hosts); + tz_revert (zone, tz, old_tz_override); + return -1; + } + } + cleanup_iterator (&hosts); + PRINT (out, ""); + } + end_time = scan_end_time (report); PRINT (out, "%s", diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in index fb90935526..d36ebdd6ad 100644 --- a/src/schema_formats/XML/GMP.xml.in +++ b/src/schema_formats/XML/GMP.xml.in @@ -1946,6 +1946,7 @@ along with this program. If not, see . apps ssl_certs host + tls_certificates timestamp scan_start scan_end @@ -2814,6 +2815,124 @@ along with this program. If not, see . + + tls_certificates + List of TLS certificates found with the scan + + tls_certificate + + + tls_certificate + TLS certificate found with the scan + + name + certificate + sha256_fingerprint + md5_fingerprint + valid + activation_time + expiration_time + subject_dn + issuer_dn + serial + host + ports + + + name + The name of the TLS certificate + text + + + certificate + The Base64 encoded certificate data + + + format + The format of the certificate + + + DER + PEM + unknown + + + 1 + + + + + sha256_fingerprint + The SHA256 fingerprint of the certificate + text + + + md5_fingerprint + The MD5 fingerprint of the certificate + text + + + valid + Whether the certificate is currently valid + boolean + + + activation_time + Time before which the certificate is not valid + iso_time + + + expiration_time + Time after which the certificate is not valid + iso_time + + + subject_dn + Distinguished name (DN) of the certificate subject + text + + + issuer_dn + Distinguished name (DN) of the certificate issuer + text + + + serial + Hexadecimal serial number of the certificate + text + + + host + Host where the certificate was found + + ip + hostname + + + ip + IP address of the host + text + + + hostname + If available, the hostname from host details + text + + + + ports + List of ports where the certificate was found + + port + + + port + Port where the certificate was found + integer + + + + timestamp The time the scan was requested