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