diff --git a/CHANGELOG.md b/CHANGELOG.md
index e66a23cf5..69563e535 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
+- Added TLS certificates as a new resource type [#585](https://github.com/greenbone/gvmd/pull/585) [#663](https://github.com/greenbone/gvmd/pull/663)
- Update NVTs via OSP [#392](https://github.com/greenbone/gvmd/pull/392) [#609](https://github.com/greenbone/gvmd/pull/609) [#626](https://github.com/greenbone/gvmd/pull/626)
- Handle addition of ID to NVT preferences. [#413](https://github.com/greenbone/gvmd/pull/413)
- Add setting 'OMP Slave Check Period' [#491](https://github.com/greenbone/gvmd/pull/491)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 78833bf7d..6900bacbf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -113,7 +113,7 @@ include (CPack)
## Variables
-set (GVMD_DATABASE_VERSION 212)
+set (GVMD_DATABASE_VERSION 214)
set (GVMD_SCAP_DATABASE_VERSION 15)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 98616fa04..3a9e6c339 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -87,6 +87,7 @@ add_executable (manage-utils-test
manage_sql.c manage_sql_nvts.c manage_sql_secinfo.c
manage_sql_configs.c
manage_sql_tickets.c manage_sql_tls_certificates.c
+ manage_tls_certificates.c
manage_migrators.c scanner.c
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c comm.c
@@ -110,6 +111,7 @@ add_executable (manage-test
manage_sql.c manage_sql_nvts.c manage_sql_secinfo.c
manage_sql_configs.c
manage_sql_tickets.c manage_sql_tls_certificates.c
+ manage_tls_certificates.c
manage_migrators.c scanner.c
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c comm.c
@@ -133,6 +135,7 @@ add_executable (gmp-tickets-test
manage_sql.c manage_sql_nvts.c manage_sql_secinfo.c
manage_sql_configs.c
manage_sql_tickets.c manage_sql_tls_certificates.c
+ manage_tls_certificates.c
manage_migrators.c scanner.c
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c comm.c
@@ -156,6 +159,7 @@ add_executable (gvmd
manage_sql.c manage_sql_nvts.c manage_sql_secinfo.c
manage_sql_configs.c
manage_sql_tickets.c manage_sql_tls_certificates.c
+ manage_tls_certificates.c
manage_migrators.c scanner.c
sql_pg.c manage_pg.c
lsc_user.c lsc_crypt.c utils.c comm.c
diff --git a/src/gmp.c b/src/gmp.c
index ebbdfacd1..0c3b35a99 100644
--- a/src/gmp.c
+++ b/src/gmp.c
@@ -13249,10 +13249,19 @@ handle_get_credentials (gmp_parser_t *gmp_parser, GError **error)
/* get certificate info */
time_t activation_time, expiration_time;
gchar *activation_time_str, *expiration_time_str;
- gchar *fingerprint, *issuer;
- get_certificate_info (cert, -1,
- &activation_time, &expiration_time,
- &fingerprint, NULL, &issuer, NULL);
+ gchar *md5_fingerprint, *issuer;
+
+ get_certificate_info (cert,
+ -1,
+ &activation_time,
+ &expiration_time,
+ &md5_fingerprint,
+ NULL, /* sha256_fingerprint */
+ NULL, /* subject */
+ &issuer,
+ NULL, /* serial */
+ NULL); /* certificate_format */
+
activation_time_str = certificate_iso_time (activation_time);
expiration_time_str = certificate_iso_time (expiration_time);
SENDF_TO_CLIENT_OR_FAIL
@@ -13266,11 +13275,11 @@ handle_get_credentials (gmp_parser_t *gmp_parser, GError **error)
certificate_time_status (activation_time, expiration_time),
activation_time_str,
expiration_time_str,
- fingerprint ? fingerprint : "",
+ md5_fingerprint ? md5_fingerprint : "",
issuer ? issuer : "");
g_free (activation_time_str);
g_free (expiration_time_str);
- g_free (fingerprint);
+ g_free (md5_fingerprint);
g_free (issuer);
}
@@ -16512,10 +16521,19 @@ handle_get_scanners (gmp_parser_t *gmp_parser, GError **error)
if (scanner_iterator_ca_pub (&scanners))
{
/* CA Certificate */
- gchar *fingerprint, *issuer;
- get_certificate_info (scanner_iterator_ca_pub (&scanners), -1,
- &activation_time, &expiration_time,
- &fingerprint, NULL, &issuer, NULL);
+ gchar *md5_fingerprint, *issuer;
+
+ get_certificate_info (scanner_iterator_ca_pub (&scanners),
+ -1,
+ &activation_time,
+ &expiration_time,
+ &md5_fingerprint,
+ NULL, /* sha256_fingerprint */
+ NULL, /* subject */
+ &issuer,
+ NULL, /* serial */
+ NULL); /* certificate_format */
+
activation_time_str = certificate_iso_time (activation_time);
expiration_time_str = certificate_iso_time (expiration_time);
SENDF_TO_CLIENT_OR_FAIL
@@ -16529,11 +16547,11 @@ handle_get_scanners (gmp_parser_t *gmp_parser, GError **error)
certificate_time_status (activation_time, expiration_time),
activation_time_str,
expiration_time_str,
- fingerprint,
+ md5_fingerprint,
issuer);
g_free (activation_time_str);
g_free (expiration_time_str);
- g_free (fingerprint);
+ g_free (md5_fingerprint);
g_free (issuer);
}
}
@@ -16557,10 +16575,19 @@ handle_get_scanners (gmp_parser_t *gmp_parser, GError **error)
if (scanner_iterator_key_pub (&scanners))
{
/* Certificate */
- gchar *fingerprint, *issuer;
- get_certificate_info (scanner_iterator_key_pub (&scanners), -1,
- &activation_time, &expiration_time,
- &fingerprint, NULL, &issuer, NULL);
+ gchar *md5_fingerprint, *issuer;
+
+ get_certificate_info (scanner_iterator_key_pub (&scanners),
+ -1,
+ &activation_time,
+ &expiration_time,
+ &md5_fingerprint,
+ NULL, /* sha256_fingerprint */
+ NULL, /* subject */
+ &issuer,
+ NULL, /* serial */
+ NULL); /* certificate_format */
+
activation_time_str = certificate_iso_time (activation_time);
expiration_time_str = certificate_iso_time (expiration_time);
SENDF_TO_CLIENT_OR_FAIL
@@ -16574,11 +16601,11 @@ handle_get_scanners (gmp_parser_t *gmp_parser, GError **error)
certificate_time_status (activation_time, expiration_time),
activation_time_str,
expiration_time_str,
- fingerprint,
+ md5_fingerprint,
issuer);
g_free (activation_time_str);
g_free (expiration_time_str);
- g_free (fingerprint);
+ g_free (md5_fingerprint);
g_free (issuer);
}
}
@@ -17433,13 +17460,20 @@ handle_get_settings (gmp_parser_t *gmp_parser, GError **error)
&& strlen (setting_iterator_value (&settings)))
{
time_t activation_time, expiration_time;
- gchar *activation_time_str, *expiration_time_str, *fingerprint;
+ gchar *activation_time_str, *expiration_time_str, *md5_fingerprint;
gchar *issuer;
- get_certificate_info (setting_iterator_value (&settings), -1,
+ get_certificate_info (setting_iterator_value (&settings),
+ -1,
&activation_time,
- &expiration_time, &fingerprint,
- NULL, &issuer, NULL);
+ &expiration_time,
+ &md5_fingerprint,
+ NULL, /* sha256_fingerprint */
+ NULL, /* subject */
+ &issuer,
+ NULL, /* serial */
+ NULL); /* certificate_format */
+
activation_time_str = certificate_iso_time (activation_time);
expiration_time_str = certificate_iso_time (expiration_time);
SENDF_TO_CLIENT_OR_FAIL
@@ -17453,11 +17487,11 @@ handle_get_settings (gmp_parser_t *gmp_parser, GError **error)
certificate_time_status (activation_time, expiration_time),
activation_time_str,
expiration_time_str,
- fingerprint,
+ md5_fingerprint,
issuer);
g_free (activation_time_str);
g_free (expiration_time_str);
- g_free (fingerprint);
+ g_free (md5_fingerprint);
g_free (issuer);
}
@@ -20216,7 +20250,7 @@ gmp_xml_handle_end_element (/* unused */ GMarkupParseContext* context,
{
time_t activation_time, expiration_time;
gchar *activation_time_str, *expiration_time_str;
- gchar *fingerprint, *issuer;
+ gchar *md5_fingerprint, *issuer;
SENDF_TO_CLIENT_OR_FAIL
(""
@@ -20224,9 +20258,17 @@ gmp_xml_handle_end_element (/* unused */ GMarkupParseContext* context,
"%s",
ldap_cacert);
- get_certificate_info (ldap_cacert, -1, &activation_time,
- &expiration_time, &fingerprint,
- NULL, &issuer, NULL);
+ get_certificate_info (ldap_cacert,
+ -1,
+ &activation_time,
+ &expiration_time,
+ &md5_fingerprint,
+ NULL, /* sha256_fingerprint */
+ NULL, /* subject */
+ &issuer,
+ NULL, /* serial */
+ NULL); /* certificate_format */
+
activation_time_str = certificate_iso_time (activation_time);
expiration_time_str = certificate_iso_time (expiration_time);
SENDF_TO_CLIENT_OR_FAIL
@@ -20240,11 +20282,11 @@ gmp_xml_handle_end_element (/* unused */ GMarkupParseContext* context,
certificate_time_status (activation_time, expiration_time),
activation_time_str,
expiration_time_str,
- fingerprint,
+ md5_fingerprint,
issuer);
g_free (activation_time_str);
g_free (expiration_time_str);
- g_free (fingerprint);
+ g_free (md5_fingerprint);
g_free (issuer);
SEND_TO_CLIENT_OR_FAIL ("");
diff --git a/src/gmp_get.h b/src/gmp_get.h
index cf232e744..4e941c1e7 100644
--- a/src/gmp_get.h
+++ b/src/gmp_get.h
@@ -117,6 +117,30 @@ send_get_common (const char *, get_data_t *, iterator_t *,
} \
while (0)
+/**
+ * @brief Send common part of GET response to client, returning on fail.
+ *
+ * This will work for types not using the trashcan.
+ *
+ * @param[in] type Type of resource.
+ * @param[in] get GET data.
+ * @param[in] iterator Iterator.
+ */
+#define SEND_GET_COMMON_NO_TRASH(type, get, iterator) \
+ do \
+ { \
+ if (send_get_common (G_STRINGIFY (type), get, iterator, \
+ gmp_parser->client_writer, \
+ gmp_parser->client_writer_data, \
+ type##_writable (get_iterator_resource (iterator)), \
+ type##_in_use (get_iterator_resource (iterator)))) \
+ { \
+ error_send_to_client (error); \
+ return; \
+ } \
+ } \
+ while (0)
+
int
buffer_get_filter_xml (GString *, const char *, const get_data_t *,
const char *, const char *);
diff --git a/src/gmp_tls_certificates.c b/src/gmp_tls_certificates.c
index 875104f23..a55bf8d64 100644
--- a/src/gmp_tls_certificates.c
+++ b/src/gmp_tls_certificates.c
@@ -122,6 +122,14 @@ get_tls_certificates_run (gmp_parser_t *gmp_parser, GError **error)
return;
}
+ if (get_tls_certificates_data.get.trash)
+ {
+ SEND_TO_CLIENT_OR_FAIL
+ (XML_ERROR_SYNTAX ("get_tls_certificates",
+ "TLS Certificates do not use the trashcan"));
+ return;
+ }
+
/* Setup the iterator. */
ret = init_tls_certificate_iterator (&tls_certificates,
@@ -178,12 +186,14 @@ get_tls_certificates_run (gmp_parser_t *gmp_parser, GError **error)
/* Send generic GET command elements. */
- SEND_GET_COMMON (tls_certificate, &get_tls_certificates_data.get,
- &tls_certificates);
+ SEND_GET_COMMON_NO_TRASH (tls_certificate,
+ &get_tls_certificates_data.get,
+ &tls_certificates);
/* Send tls_certificate info. */
- SENDF_TO_CLIENT_OR_FAIL
+ SENDF_TO_CLIENT_OR_FAIL
("%s"
+ "%s"
"%s"
"%d"
"%d"
@@ -191,7 +201,8 @@ get_tls_certificates_run (gmp_parser_t *gmp_parser, GError **error)
"%s"
"%s"
"%s"
- "",
+ "%s"
+ "%s",
tls_certificate_iterator_certificate_format (&tls_certificates)
? tls_certificate_iterator_certificate_format (&tls_certificates)
: "unknown",
@@ -199,12 +210,75 @@ get_tls_certificates_run (gmp_parser_t *gmp_parser, GError **error)
? tls_certificate_iterator_certificate (&tls_certificates)
: "",
tls_certificate_iterator_md5_fingerprint (&tls_certificates),
+ tls_certificate_iterator_sha256_fingerprint (&tls_certificates),
tls_certificate_iterator_trust (&tls_certificates),
tls_certificate_iterator_valid (&tls_certificates),
tls_certificate_iterator_activation_time (&tls_certificates),
tls_certificate_iterator_expiration_time (&tls_certificates),
tls_certificate_iterator_subject_dn (&tls_certificates),
- tls_certificate_iterator_issuer_dn (&tls_certificates));
+ tls_certificate_iterator_issuer_dn (&tls_certificates),
+ tls_certificate_iterator_serial (&tls_certificates),
+ tls_certificate_iterator_last_collected (&tls_certificates));
+
+ if (get_tls_certificates_data.get.details)
+ {
+ iterator_t sources;
+ SEND_TO_CLIENT_OR_FAIL ("");
+
+ init_tls_certificate_source_iterator
+ (&sources,
+ get_iterator_resource (&tls_certificates));
+
+ while (next (&sources))
+ {
+ SENDF_TO_CLIENT_OR_FAIL
+ ("");
+ }
+
+ cleanup_iterator (&sources);
+
+ SEND_TO_CLIENT_OR_FAIL ("");
+ }
+
+ SENDF_TO_CLIENT_OR_FAIL ("");
count++;
}
cleanup_iterator (&tls_certificates);
@@ -434,7 +508,16 @@ create_tls_certificate_run (gmp_parser_t *gmp_parser, GError **error)
"TLS Certificate",
NULL,
"created");
- return;
+ break;
+ }
+ case 3:
+ {
+ SEND_TO_CLIENT_OR_FAIL
+ (XML_ERROR_SYNTAX ("create_tls_certificate",
+ "TLS Certificate exists already"));
+ log_event_fail ("tls_certificate", "TLS Certificate", NULL,
+ "created");
+ break;
}
case 99:
SEND_TO_CLIENT_OR_FAIL
@@ -570,7 +653,7 @@ modify_tls_certificate_element_start (gmp_parser_t *gmp_parser,
void
modify_tls_certificate_run (gmp_parser_t *gmp_parser, GError **error)
{
- entity_t entity, comment, name, certificate, trust;
+ entity_t entity, comment, name, trust;
const char *tls_certificate_id;
int trust_int;
@@ -582,22 +665,8 @@ modify_tls_certificate_run (gmp_parser_t *gmp_parser, GError **error)
comment = entity_child (entity, "comment");
name = entity_child (entity, "name");
- certificate = entity_child (entity, "certificate");
trust = entity_child (entity, "trust");
- if (certificate
- && strcmp (entity_text (certificate), "") == 0)
- {
- SEND_TO_CLIENT_OR_FAIL
- (XML_ERROR_SYNTAX ("modify_tls_certificate",
- "New CERTIFICATE must not be empty if given."));
- log_event_fail ("tls_certificate",
- "TLS Certificate",
- NULL,
- "modified");
- return;
- }
-
trust_int = -1;
if (trust)
{
@@ -619,7 +688,6 @@ modify_tls_certificate_run (gmp_parser_t *gmp_parser, GError **error)
(tls_certificate_id,
comment ? entity_text (comment) : NULL,
name ? entity_text (name) : NULL,
- certificate ? entity_text (certificate) : NULL,
trust_int))
{
case 0:
diff --git a/src/manage.c b/src/manage.c
index 044b186a1..b699f8156 100644
--- a/src/manage.c
+++ b/src/manage.c
@@ -304,9 +304,12 @@ truncate_private_key (const gchar* private_key)
* @param[in] certificate_len Length of certificate, -1: null-terminated
* @param[out] activation_time Pointer to write activation time to.
* @param[out] expiration_time Pointer to write expiration time to.
- * @param[out] fingerprint Pointer for newly allocated fingerprint.
+ * @param[out] md5_fingerprint Pointer for newly allocated MD5 fingerprint.
+ * @param[out] sha256_fingerprint Pointer for newly allocated SHA-256
+ * fingerprint.
* @param[out] subject Pointer for newly allocated subject DN.
* @param[out] issuer Pointer for newly allocated issuer DN.
+ * @param[out] serial Pointer for newly allocated serial.
* @param[out] certificate_format Pointer to certificate format.
*
* @return 0 success, -1 error.
@@ -314,7 +317,8 @@ truncate_private_key (const gchar* private_key)
int
get_certificate_info (const gchar* certificate, gssize certificate_len,
time_t* activation_time, time_t* expiration_time,
- gchar** fingerprint, gchar **subject, gchar** issuer,
+ gchar** md5_fingerprint, gchar **sha256_fingerprint,
+ gchar **subject, gchar** issuer, gchar **serial,
gnutls_x509_crt_fmt_t *certificate_format)
{
gchar *cert_truncated;
@@ -325,14 +329,18 @@ get_certificate_info (const gchar* certificate, gssize certificate_len,
*activation_time = -1;
if (expiration_time)
*expiration_time = -1;
- if (fingerprint)
- *fingerprint = NULL;
+ if (md5_fingerprint)
+ *md5_fingerprint = NULL;
+ if (sha256_fingerprint)
+ *sha256_fingerprint = NULL;
if (subject)
*subject = NULL;
if (issuer)
*issuer = NULL;
+ if (serial)
+ *serial = NULL;
if (certificate_format)
- *certificate_format = 0;
+ *certificate_format = GNUTLS_X509_FMT_DER;
if (certificate)
{
@@ -394,7 +402,7 @@ get_certificate_info (const gchar* certificate, gssize certificate_len,
= gnutls_x509_crt_get_expiration_time (gnutls_cert);
}
- if (fingerprint)
+ if (md5_fingerprint)
{
int i;
size_t buffer_size = 16;
@@ -415,13 +423,34 @@ get_certificate_info (const gchar* certificate, gssize certificate_len,
g_string_append_printf (string, "%02x", buffer[i]);
}
- *fingerprint = string->str;
+ *md5_fingerprint = string->str;
+ g_string_free (string, FALSE);
+ }
+
+ if (sha256_fingerprint)
+ {
+ int i;
+ size_t buffer_size = 32;
+ unsigned char buffer[buffer_size];
+ GString *string;
+
+ string = g_string_new ("");
+
+ gnutls_x509_crt_get_fingerprint (gnutls_cert, GNUTLS_DIG_SHA256,
+ buffer, &buffer_size);
+
+ for (i = 0; i < buffer_size; i++)
+ {
+ g_string_append_printf (string, "%02X", buffer[i]);
+ }
+
+ *sha256_fingerprint = string->str;
g_string_free (string, FALSE);
}
if (subject)
{
- size_t buffer_size;
+ size_t buffer_size = 0;
gchar *buffer;
gnutls_x509_crt_get_dn (gnutls_cert, NULL, &buffer_size);
buffer = g_malloc (buffer_size);
@@ -432,7 +461,7 @@ get_certificate_info (const gchar* certificate, gssize certificate_len,
if (issuer)
{
- size_t buffer_size;
+ size_t buffer_size = 0;
gchar *buffer;
gnutls_x509_crt_get_issuer_dn (gnutls_cert, NULL, &buffer_size);
buffer = g_malloc (buffer_size);
@@ -441,6 +470,28 @@ get_certificate_info (const gchar* certificate, gssize certificate_len,
*issuer = buffer;
}
+ if (serial)
+ {
+ int i;
+ size_t buffer_size = 0;
+ gchar* buffer;
+ GString *string;
+
+ string = g_string_new ("");
+
+ gnutls_x509_crt_get_serial (gnutls_cert, NULL, &buffer_size);
+ buffer = g_malloc (buffer_size);
+ gnutls_x509_crt_get_serial (gnutls_cert, buffer, &buffer_size);
+
+ for (i = 0; i < buffer_size; i++)
+ {
+ g_string_append_printf (string, "%02X", buffer[i]);
+ }
+
+ *serial = string->str;
+ g_string_free (string, FALSE);
+ }
+
gnutls_x509_crt_deinit (gnutls_cert);
g_free (cert_truncated);
}
@@ -1820,7 +1871,7 @@ update_end_times (entity_t report)
entities = next_entities (entities);
}
- /* Add host details and set the host end times. */
+ /* Add host details, create assets and set the host end times. */
entities = report->entities;
while ((end = first_entity (entities)))
@@ -1850,6 +1901,9 @@ update_end_times (entity_t report)
entity_text (ip),
end))
return -1;
+ if (add_assets_from_host_in_report (global_current_report,
+ entity_text (ip)))
+ return -1;
}
}
diff --git a/src/manage.h b/src/manage.h
index b1ea08791..4086e209f 100644
--- a/src/manage.h
+++ b/src/manage.h
@@ -165,6 +165,8 @@ get_certificate_info (const gchar *,
gchar **,
gchar **,
gchar **,
+ gchar **,
+ gchar **,
gnutls_x509_crt_fmt_t *);
gchar *
@@ -173,6 +175,12 @@ certificate_iso_time (time_t);
const gchar *
certificate_time_status (time_t, time_t);
+void
+parse_ssldetails (const char *, time_t *, time_t *, gchar **, gchar **);
+
+const char*
+tls_certificate_format_str (gnutls_x509_crt_fmt_t certificate_format);
+
/* Credentials. */
@@ -2461,6 +2469,9 @@ create_asset_report (const char *, const char *);
int
create_asset_host (const char *, const char *, resource_t* );
+int
+add_assets_from_host_in_report (report_t report, const char *host);
+
/* Notes. */
diff --git a/src/manage_migrators.c b/src/manage_migrators.c
index 94b8acfb4..7630de396 100644
--- a/src/manage_migrators.c
+++ b/src/manage_migrators.c
@@ -553,6 +553,610 @@ migrate_211_to_212 ()
return 0;
}
+/**
+ * @brief Gets or creates a tls_certificate_location in the version 213 format.
+ *
+ * If a location with matching host_ip and port exists its id is returned,
+ * otherwise a new one is created and its id is returned.
+ *
+ * @param[in] host_ip IP address of the location
+ * @param[in] port Port number of the location
+ *
+ * @return Row id of the tls_certificate_location
+ */
+resource_t
+tls_certificate_get_location_213 (const char *host_ip,
+ const char *port)
+{
+ resource_t location = 0;
+ char *quoted_host_ip, *quoted_port;
+ quoted_host_ip = host_ip ? sql_quote (host_ip) : g_strdup ("");
+ quoted_port = port ? sql_quote (port) : g_strdup ("");
+
+ sql_int64 (&location,
+ "SELECT id"
+ " FROM tls_certificate_locations"
+ " WHERE host_ip = '%s'"
+ " AND port = '%s'",
+ quoted_host_ip,
+ quoted_port);
+
+ if (location)
+ {
+ g_free (quoted_host_ip);
+ g_free (quoted_port);
+ return location;
+ }
+
+ sql ("INSERT INTO tls_certificate_locations"
+ " (uuid, host_ip, port)"
+ " VALUES (make_uuid (), '%s', '%s')",
+ quoted_host_ip,
+ quoted_port);
+
+ location = sql_last_insert_id ();
+
+ g_free (quoted_host_ip);
+ g_free (quoted_port);
+
+ return location;
+}
+
+/**
+ * @brief Gets or creates a tls_certificate_origin in the version 213 format.
+ *
+ * If an origin with matching type, id and data exists its id is returned,
+ * otherwise a new one is created and its id is returned.
+ *
+ * @param[in] origin_type Origin type, e.g. "GMP" or "Report"
+ * @param[in] origin_id Origin resource id, e.g. a report UUID.
+ * @param[in] origin_data Origin extra data, e.g. OID of generating NVT.
+ *
+ * @return Row id of the tls_certificate_origin
+ */
+resource_t
+tls_certificate_get_origin_213 (const char *origin_type,
+ const char *origin_id,
+ const char *origin_data)
+{
+ resource_t origin = 0;
+ char *quoted_origin_type, *quoted_origin_id, *quoted_origin_data;
+ quoted_origin_type = origin_type ? sql_quote (origin_type) : g_strdup ("");
+ quoted_origin_id = origin_id ? sql_quote (origin_id) : g_strdup ("");
+ quoted_origin_data = origin_data ? sql_quote (origin_data) : g_strdup ("");
+
+ sql_int64 (&origin,
+ "SELECT id"
+ " FROM tls_certificate_origins"
+ " WHERE origin_type = '%s'"
+ " AND origin_id = '%s'"
+ " AND origin_data = '%s'",
+ quoted_origin_type,
+ quoted_origin_id,
+ quoted_origin_data);
+
+ if (origin)
+ {
+ g_free (quoted_origin_type);
+ g_free (quoted_origin_id);
+ g_free (quoted_origin_data);
+ return origin;
+ }
+
+ sql ("INSERT INTO tls_certificate_origins"
+ " (uuid, origin_type, origin_id, origin_data)"
+ " VALUES (make_uuid (), '%s', '%s', '%s')",
+ quoted_origin_type,
+ quoted_origin_id,
+ quoted_origin_data);
+
+ origin = sql_last_insert_id ();
+
+ g_free (quoted_origin_type);
+ g_free (quoted_origin_id);
+ g_free (quoted_origin_data);
+
+ return origin;
+}
+
+/**
+ * @brief Migrate the database from version 212 to version 213.
+ *
+ * @return 0 success, -1 error.
+ */
+int
+migrate_212_to_213 ()
+{
+ iterator_t tls_certs;
+ resource_t import_origin;
+
+ gchar *sha256_fingerprint, *serial;
+
+ sha256_fingerprint = NULL;
+ serial = NULL;
+
+ sql_begin_immediate ();
+
+ /* Ensure that the database is currently version 212. */
+
+ if (manage_db_version () != 212)
+ {
+ sql_rollback ();
+ return -1;
+ }
+
+ /* Update the database. */
+
+ /* Add columns to tls_certificates */
+ sql ("ALTER TABLE tls_certificates"
+ " ADD COLUMN sha256_fingerprint text;");
+ sql ("ALTER TABLE tls_certificates"
+ " ADD COLUMN serial text;");
+
+ /* Change type of timestamp columns because some expiration times
+ * may exceed the limits of 32 bit integers
+ */
+ sql ("ALTER TABLE tls_certificates"
+ " ALTER COLUMN activation_time TYPE bigint");
+ sql ("ALTER TABLE tls_certificates"
+ " ALTER COLUMN expiration_time TYPE bigint");
+ sql ("ALTER TABLE tls_certificates"
+ " ALTER COLUMN creation_time TYPE bigint");
+ sql ("ALTER TABLE tls_certificates"
+ " ALTER COLUMN modification_time TYPE bigint");
+
+ /* Create new tables */
+ sql ("CREATE TABLE tls_certificate_locations"
+ " (id SERIAL PRIMARY KEY,"
+ " uuid text UNIQUE NOT NULL,"
+ " host_ip text,"
+ " port text);");
+
+ sql ("CREATE INDEX tls_certificate_locations_by_host_ip"
+ " ON tls_certificate_locations (host_ip)");
+
+ sql ("CREATE TABLE tls_certificate_origins"
+ " (id SERIAL PRIMARY KEY,"
+ " uuid text UNIQUE NOT NULL,"
+ " origin_type text,"
+ " origin_id text,"
+ " origin_data text);");
+
+ sql ("CREATE INDEX tls_certificate_origins_by_origin_id_and_type"
+ " ON tls_certificate_origins (origin_id, origin_type)");
+
+ sql ("CREATE TABLE tls_certificate_sources"
+ " (id SERIAL PRIMARY KEY,"
+ " uuid text UNIQUE NOT NULL,"
+ " tls_certificate integer REFERENCES tls_certificates (id),"
+ " location integer REFERENCES tls_certificate_locations (id),"
+ " origin integer REFERENCES tls_certificate_origins (id),"
+ " timestamp bigint,"
+ " tls_versions text);");
+
+ /* Remove now unused tls_certificates_trash table */
+ sql ("DROP TABLE IF EXISTS tls_certificates_trash;");
+
+ /* Add origin and source for manual GMP import */
+ sql ("INSERT INTO tls_certificate_origins"
+ " (uuid, origin_type, origin_id, origin_data)"
+ " VALUES (make_uuid(), 'Import', '', '')");
+ import_origin = sql_last_insert_id ();
+
+ /* Set the sha256_fingerprint and serial for existing tls_certificates */
+ init_iterator (&tls_certs,
+ "SELECT id, certificate, creation_time"
+ " FROM tls_certificates");
+ while (next (&tls_certs))
+ {
+ tls_certificate_t tls_certificate;
+ const char *certificate_64;
+ gsize certificate_size;
+ unsigned char *certificate;
+ time_t creation_time;
+
+ tls_certificate = iterator_int64 (&tls_certs, 0);
+ certificate_64 = iterator_string (&tls_certs, 1);
+ certificate = g_base64_decode (certificate_64, &certificate_size);
+ creation_time = iterator_int64 (&tls_certs, 2);
+
+ get_certificate_info ((gchar*)certificate,
+ certificate_size,
+ NULL, /* activation_time */
+ NULL, /* expiration_time */
+ NULL, /* md5_fingerprint */
+ &sha256_fingerprint,
+ NULL, /* subject */
+ NULL, /* issuer */
+ &serial,
+ NULL); /* certificate_format */
+
+ sql ("UPDATE tls_certificates"
+ " SET sha256_fingerprint = '%s', serial = '%s'"
+ " WHERE id = %llu",
+ sha256_fingerprint,
+ serial,
+ tls_certificate);
+
+ sql ("INSERT INTO tls_certificate_sources"
+ " (uuid, tls_certificate, origin, location, timestamp)"
+ " VALUES (make_uuid(), %llu, %llu, NULL, %ld);",
+ tls_certificate,
+ import_origin,
+ creation_time);
+
+ g_free (sha256_fingerprint);
+ }
+ cleanup_iterator (&tls_certs);
+
+ /* Set the database version to 213 */
+
+ set_db_version (213);
+
+ sql_commit ();
+
+ return 0;
+}
+
+/**
+ * @brief Create a TLS certificate in the version 214 format.
+ *
+ * @param[in] owner Owner of the new tls_certificate.
+ * @param[in] certificate_b64 The Base64 encoded certificate.
+ * @param[in] subject_dn The subject DN of the certificate.
+ * @param[in] issuer_dn The issuer DN of the certificate.
+ * @param[in] activation_time Time before which the certificate is invalid.
+ * @param[in] expiration_time Time after which the certificate is expired.
+ * @param[in] md5_fingerprint MD5 fingerprint of the certificate.
+ * @param[in] sha256_fingerprint SHA-256 fingerprint of the certificate.
+ * @param[in] serial Serial of the certificate.
+ * @param[in] certificate_format Certificate format (DER or PEM).
+ *
+ * @return The new TLS certificate.
+ */
+static tls_certificate_t
+make_tls_certificate_214 (user_t owner,
+ const char *certificate_b64,
+ const char *subject_dn,
+ const char *issuer_dn,
+ time_t activation_time,
+ time_t expiration_time,
+ const char *md5_fingerprint,
+ const char *sha256_fingerprint,
+ const char *serial,
+ gnutls_x509_crt_fmt_t certificate_format)
+{
+ gchar *quoted_certificate_b64, *quoted_subject_dn, *quoted_issuer_dn;
+ gchar *quoted_md5_fingerprint, *quoted_sha256_fingerprint, *quoted_serial;
+ tls_certificate_t ret;
+
+ quoted_certificate_b64
+ = certificate_b64 ? sql_quote (certificate_b64) : NULL;
+ quoted_subject_dn
+ = subject_dn ? sql_quote (subject_dn) : NULL;
+ quoted_issuer_dn
+ = issuer_dn ? sql_quote (issuer_dn) : NULL;
+ quoted_md5_fingerprint
+ = md5_fingerprint ? sql_quote (md5_fingerprint) : NULL;
+ quoted_sha256_fingerprint
+ = sha256_fingerprint ? sql_quote (sha256_fingerprint) : NULL;
+ quoted_serial
+ = serial ? sql_quote (serial) : NULL;
+
+ sql ("INSERT INTO tls_certificates"
+ " (uuid, owner,"
+ " name, comment, creation_time, modification_time,"
+ " certificate, subject_dn, issuer_dn, trust,"
+ " activation_time, expiration_time,"
+ " md5_fingerprint, sha256_fingerprint, serial, certificate_format)"
+ " SELECT make_uuid(), %llu,"
+ " '%s', '%s', m_now(), m_now(),"
+ " '%s', '%s', '%s', %d,"
+ " %ld, %ld,"
+ " '%s', '%s', '%s', '%s';",
+ owner,
+ sha256_fingerprint ? quoted_sha256_fingerprint : "",
+ "", /* comment */
+ certificate_b64 ? quoted_certificate_b64 : "",
+ subject_dn ? quoted_subject_dn : "",
+ issuer_dn ? quoted_issuer_dn : "",
+ 0, /* trust */
+ activation_time,
+ expiration_time,
+ md5_fingerprint ? quoted_md5_fingerprint : "",
+ sha256_fingerprint ? quoted_sha256_fingerprint : "",
+ serial ? quoted_serial : "",
+ tls_certificate_format_str (certificate_format));
+
+ ret = sql_last_insert_id ();
+
+ g_free (quoted_certificate_b64);
+ g_free (quoted_subject_dn);
+ g_free (quoted_issuer_dn);
+ g_free (quoted_md5_fingerprint);
+ g_free (quoted_sha256_fingerprint);
+ g_free (quoted_serial);
+
+ return ret;
+}
+
+/**
+ * @brief Migrate the database from version 213 to version 214.
+ *
+ * @return 0 success, -1 error.
+ */
+int
+migrate_213_to_214 ()
+{
+ iterator_t tls_certs;
+ char *previous_fpr;
+ user_t previous_owner;
+ tls_certificate_t current_tls_certificate;
+
+ time_t activation_time, expiration_time;
+ gchar *md5_fingerprint, *sha256_fingerprint, *subject, *issuer, *serial;
+ gnutls_x509_crt_fmt_t certificate_format;
+
+ previous_fpr = NULL;
+ previous_owner = 0;
+ current_tls_certificate = 0;
+
+ activation_time = -1;
+ expiration_time = -1;
+ md5_fingerprint = NULL;
+ sha256_fingerprint = NULL;
+ subject = NULL;
+ issuer = NULL;
+ serial = NULL;
+ certificate_format = 0;
+
+ sql_begin_immediate ();
+
+ /* Ensure that the database is currently version 213. */
+
+ if (manage_db_version () != 213)
+ {
+ sql_rollback ();
+ return -1;
+ }
+
+ /* Update the database. */
+
+ /* Collect TLS certificates from host details
+ *
+ * The outer loop collects the details containing the
+ * Base64 encoded certificates and their SHA-256 fingerprints
+ * in an order that reduces how often the data has to extracted or
+ * queried from other host details:
+ *
+ * - The detail name containing the fingerprint is first, to reduce the
+ * number of times the certificate info must be fetched.
+ * - The owner is second so each certificate is created only once per user
+ * without checking if it was already created in different report or not.
+ * - The report id is last so tls_certificate_sources are created in the
+ * same order as the reports.
+ */
+ init_iterator (&tls_certs,
+ "SELECT rhd.value, rhd.name, reports.owner, rhd.report_host,"
+ " report_hosts.host, reports.uuid, rhd.source_name,"
+ " coalesce (report_hosts.start_time, reports.date)"
+ " FROM report_host_details AS rhd"
+ " JOIN report_hosts ON rhd.report_host = report_hosts.id"
+ " JOIN reports ON report_hosts.report = reports.id"
+ " WHERE source_description = 'SSL/TLS Certificate'"
+ " OR source_description = 'SSL Certificate'"
+ " ORDER BY rhd.name, reports.owner, reports.id");
+
+ 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;
+ user_t owner;
+ resource_t report_host;
+ const char *host_ip, *report_id, *source_name;
+ time_t timestamp;
+
+ iterator_t ports;
+ gboolean has_ports;
+ gchar *quoted_source_name;
+
+ 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);
+
+ owner = iterator_int64 (&tls_certs, 2);
+ report_host = iterator_int64 (&tls_certs, 3);
+ host_ip = iterator_string (&tls_certs, 4);
+ report_id = iterator_string (&tls_certs, 5);
+ source_name = iterator_string (&tls_certs, 6);
+ timestamp = iterator_int64 (&tls_certs, 7);
+
+ quoted_source_name = sql_quote (source_name);
+
+ // Get certificate data only once per fingerprint
+ if (previous_fpr == NULL
+ || strcmp (previous_fpr, quoted_scanner_fpr))
+ {
+ char *ssldetails;
+
+ activation_time = -1;
+ expiration_time = -1;
+ g_free (md5_fingerprint);
+ md5_fingerprint = NULL;
+ g_free (sha256_fingerprint);
+ sha256_fingerprint = NULL;
+ g_free (subject);
+ subject = NULL;
+ g_free (issuer);
+ issuer = NULL;
+ g_free (serial);
+ serial = NULL;
+ certificate_format = 0;
+
+ /* Try extracting the data directly from the certificate */
+ get_certificate_info ((gchar*)certificate,
+ certificate_size,
+ &activation_time,
+ &expiration_time,
+ &md5_fingerprint,
+ &sha256_fingerprint,
+ &subject,
+ &issuer,
+ &serial,
+ &certificate_format);
+
+ /* Use fingerprint from host detail
+ * in case get_certificate_info fails */
+ if (sha256_fingerprint == NULL)
+ sha256_fingerprint = g_strdup (scanner_fpr);
+
+ /* Also use SSLDetails in case get_certificate_info fails
+ * or to ensure consistency with the host details */
+ ssldetails
+ = sql_string ("SELECT rhd.value"
+ " FROM report_host_details AS rhd"
+ " JOIN report_hosts"
+ " ON report_hosts.id = rhd.report_host"
+ " WHERE name = 'SSLDetails:%s'"
+ " ORDER BY report_hosts.start_time DESC"
+ " LIMIT 1;",
+ quoted_scanner_fpr);
+
+ parse_ssldetails (ssldetails,
+ &activation_time,
+ &expiration_time,
+ &issuer,
+ &serial);
+
+ free (ssldetails);
+ }
+
+ /* Ordering should ensure the certificate is unique for each owner */
+ if (owner != previous_owner
+ || previous_fpr == NULL
+ || strcmp (previous_fpr, quoted_scanner_fpr))
+ {
+ current_tls_certificate = 0;
+ sql_int64 (¤t_tls_certificate,
+ "SELECT id FROM tls_certificates"
+ " WHERE sha256_fingerprint = '%s'"
+ " AND owner = %llu",
+ quoted_scanner_fpr, owner);
+
+ if (current_tls_certificate == 0)
+ {
+ current_tls_certificate
+ = make_tls_certificate_214 (owner,
+ certificate_b64,
+ subject,
+ issuer,
+ activation_time,
+ expiration_time,
+ md5_fingerprint,
+ sha256_fingerprint,
+ serial,
+ certificate_format);
+ }
+ }
+
+ /* Collect ports for each unique certificate and owner */
+ 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);
+
+ has_ports = FALSE;
+ while (next (&ports))
+ {
+ const char *value;
+ gchar *port, *quoted_port;
+ GString *versions;
+ iterator_t versions_iter;
+ resource_t cert_location, cert_origin;
+
+ value = iterator_string (&ports, 0);
+ port = g_strndup (value, g_strrstr (value, ":") - value - 1);
+ quoted_port = sql_quote (port);
+
+ has_ports = TRUE;
+
+ /* Collect TLS versions for each port */
+ versions = g_string_new ("");
+ init_iterator (&versions_iter,
+ "SELECT value FROM report_host_details"
+ " WHERE report_host = %llu"
+ " AND name = 'TLS/%s'",
+ report_host,
+ quoted_port);
+ while (next (&versions_iter))
+ {
+ gchar *quoted_version;
+ quoted_version = sql_quote (iterator_string (&versions_iter, 0));
+
+ if (versions->len)
+ g_string_append (versions, ", ");
+ g_string_append (versions, quoted_version);
+ }
+ cleanup_iterator (&versions_iter);
+
+ cert_location
+ = tls_certificate_get_location_213 (host_ip, port);
+ cert_origin
+ = tls_certificate_get_origin_213 ("Report",
+ report_id,
+ quoted_source_name);
+
+ sql ("INSERT INTO tls_certificate_sources"
+ " (uuid, tls_certificate, location, origin,"
+ " timestamp, tls_versions)"
+ " VALUES (make_uuid (), %llu, %llu, %llu,"
+ " %ld, '%s')",
+ current_tls_certificate,
+ cert_location,
+ cert_origin,
+ timestamp,
+ versions->str);
+
+ g_free (port);
+ g_free (quoted_port);
+ g_string_free (versions, TRUE);
+ }
+
+ if (has_ports == FALSE)
+ g_warning ("Certificate without ports: %s report:%s host:%s",
+ quoted_scanner_fpr, report_id, host_ip);
+
+ cleanup_iterator (&ports);
+
+ g_free (quoted_source_name);
+
+ g_free (previous_fpr);
+ previous_fpr = quoted_scanner_fpr;
+ previous_owner = owner;
+ }
+ cleanup_iterator (&tls_certs);
+
+ /* Set the database version to 214 */
+
+ set_db_version (214);
+
+ sql_commit ();
+
+ return 0;
+}
+
#undef UPDATE_DASHBOARD_SETTINGS
/**
@@ -571,6 +1175,8 @@ static migrator_t database_migrators[] = {
{210, migrate_209_to_210},
{211, migrate_210_to_211},
{212, migrate_211_to_212},
+ {213, migrate_212_to_213},
+ {214, migrate_213_to_214},
/* End marker. */
{-1, NULL}};
diff --git a/src/manage_pg.c b/src/manage_pg.c
index 0b7745238..abacb3dad 100644
--- a/src/manage_pg.c
+++ b/src/manage_pg.c
@@ -948,7 +948,9 @@ manage_create_sql_functions ()
"$$ LANGUAGE plpgsql"
" IMMUTABLE;");
- sql ("CREATE OR REPLACE FUNCTION iso_time (seconds integer)"
+ sql ("DROP FUNCTION IF EXISTS iso_time (seconds integer);");
+
+ sql ("CREATE OR REPLACE FUNCTION iso_time (seconds bigint)"
" RETURNS text AS $$"
" DECLARE"
" user_zone text;"
@@ -991,7 +993,9 @@ manage_create_sql_functions ()
" END;"
"$$ LANGUAGE plpgsql;");
- sql ("CREATE OR REPLACE FUNCTION certificate_iso_time (integer)"
+ sql ("DROP FUNCTION IF EXISTS iso_time (integer);");
+
+ sql ("CREATE OR REPLACE FUNCTION certificate_iso_time (bigint)"
" RETURNS text AS $$"
" BEGIN"
" RETURN CASE"
@@ -1002,7 +1006,9 @@ manage_create_sql_functions ()
" END;"
"$$ LANGUAGE plpgsql;");
- sql ("CREATE OR REPLACE FUNCTION days_from_now (seconds integer)"
+ sql ("DROP FUNCTION IF EXISTS days_from_now (seconds integer);");
+
+ sql ("CREATE OR REPLACE FUNCTION days_from_now (seconds bigint)"
" RETURNS integer AS $$"
" DECLARE"
" diff interval;"
@@ -2522,33 +2528,40 @@ create_tables ()
" owner integer REFERENCES users (id) ON DELETE RESTRICT,"
" name text,"
" comment text,"
- " creation_time integer,"
- " modification_time integer,"
+ " creation_time bigint,"
+ " modification_time bigint,"
" certificate text,"
" subject_dn text,"
" issuer_dn text,"
- " activation_time integer,"
- " expiration_time integer,"
+ " activation_time bigint,"
+ " expiration_time bigint,"
" md5_fingerprint text,"
" trust integer,"
- " certificate_format text);");
+ " certificate_format text,"
+ " sha256_fingerprint text,"
+ " serial text);");
- sql ("CREATE TABLE IF NOT EXISTS tls_certificates_trash"
+ sql ("CREATE TABLE IF NOT EXISTS tls_certificate_locations"
" (id SERIAL PRIMARY KEY,"
" uuid text UNIQUE NOT NULL,"
- " owner integer REFERENCES users (id) ON DELETE RESTRICT,"
- " name text,"
- " comment text,"
- " creation_time integer,"
- " modification_time integer,"
- " certificate text,"
- " subject_dn text,"
- " issuer_dn text,"
- " activation_time integer,"
- " expiration_time integer,"
- " md5_fingerprint text,"
- " trust integer,"
- " certificate_format text);");
+ " host_ip text,"
+ " port text);");
+
+ sql ("CREATE TABLE IF NOT EXISTS tls_certificate_origins"
+ " (id SERIAL PRIMARY KEY,"
+ " uuid text UNIQUE NOT NULL,"
+ " origin_type text,"
+ " origin_id text,"
+ " origin_data text);");
+
+ sql ("CREATE TABLE IF NOT EXISTS tls_certificate_sources"
+ " (id SERIAL PRIMARY KEY,"
+ " uuid text UNIQUE NOT NULL,"
+ " tls_certificate integer REFERENCES tls_certificates (id),"
+ " location integer REFERENCES tls_certificate_locations (id),"
+ " origin integer REFERENCES tls_certificate_origins (id),"
+ " timestamp bigint,"
+ " tls_versions text);");
sql ("CREATE TABLE IF NOT EXISTS scanners"
" (id SERIAL PRIMARY KEY,"
@@ -3285,6 +3298,13 @@ create_tables ()
sql ("SELECT create_index ('tag_resources_trash_by_tag',"
" 'tag_resources_trash', 'tag');");
+ sql ("SELECT create_index ('tls_certificate_locations_by_host_ip',"
+ " 'tls_certificate_locations', 'host_ip')");
+
+ sql ("SELECT create_index ('tls_certificate_origins_by_origin_id_and_type',"
+ " 'tls_certificate_origins',"
+ " 'origin_id, origin_type')");
+
sql ("SELECT create_index ('vt_refs_by_vt_oid',"
" 'vt_refs', 'vt_oid');");
diff --git a/src/manage_sql.c b/src/manage_sql.c
index 5c96588a5..f6f469f82 100644
--- a/src/manage_sql.c
+++ b/src/manage_sql.c
@@ -4480,7 +4480,8 @@ type_has_trash (const char *type)
&& type_is_info_subtype (type) == 0
&& strcasecmp (type, "allinfo")
&& strcasecmp (type, "vuln")
- && strcasecmp (type, "user"));
+ && strcasecmp (type, "user")
+ && strcasecmp (type, "tls_certificate"));
}
/**
@@ -4797,6 +4798,11 @@ copy_resource_lock (const char *type, const char *name, const char *comment,
if (named && name && *name && resource_with_name_exists (name, type, 0))
return 1;
+
+ if ((strcmp (type, "tls_certificate") == 0)
+ && user_has_tls_certificate (resource, owner))
+ return 1;
+
if (name && *name)
quoted_name = sql_quote (name);
else
@@ -22434,6 +22440,20 @@ create_report (array_t *results, const char *task_id, const char *in_assets,
insert_count++;
}
+ sql_commit ();
+
+ index = 0;
+ sql_begin_immediate ();
+ while ((end = (create_report_result_t*) g_ptr_array_index (host_ends,
+ index++)))
+ if (end->host)
+ {
+ sql_commit ();
+ gvm_usleep (CREATE_REPORT_CHUNK_SLEEP);
+ add_assets_from_host_in_report (report, end->host);
+ sql_begin_immediate ();
+ }
+
if (first == 0)
sql (insert->str);
@@ -31408,6 +31428,7 @@ parse_osp_report (task_t task, report_t report, const char *report_xml)
else if (host && nvt_id && desc && (strcmp (nvt_id, "HOST_END") == 0))
{
set_scan_host_end_time_otp (report, host, desc);
+ add_assets_from_host_in_report (report, host);
}
else
{
@@ -54395,11 +54416,6 @@ manage_restore (const char *id)
if (ret != 2)
return ret;
- /* TLS Certificate. */
- ret = restore_tls_certificate (id);
- if (ret != 2)
- return ret;
-
/* Agent. */
if (find_trash ("agent", id, &resource))
@@ -55601,7 +55617,6 @@ manage_empty_trashcan ()
current_credentials.uuid);
sql ("DELETE FROM configs_trash" WHERE_OWNER);
empty_trashcan_tickets ();
- empty_trashcan_tls_certificates();
sql ("DELETE FROM permissions"
" WHERE subject_type = 'group'"
" AND subject IN (SELECT id from groups_trash"
@@ -57907,6 +57922,60 @@ delete_asset (const char *asset_id, const char *report_id, int dummy)
return 2;
}
+/**
+ * @brief Generates and adds assets from report host details
+ *
+ * @param[in] report The report to get host details from.
+ * @param[in] host_ip IP address of the host to get details from.
+ *
+ * @return 0 success, -1 error.
+ */
+int
+add_assets_from_host_in_report (report_t report, const char *host_ip)
+{
+ int ret;
+ gchar *quoted_host;
+ char *report_id;
+ report_host_t report_host = 0;
+
+ /* Get report UUID */
+ report_id = report_uuid (report);
+ if (report_id == NULL)
+ {
+ g_warning ("%s: report %llu not found.",
+ __FUNCTION__, report);
+ return -1;
+ }
+
+ /* Find report_host */
+ quoted_host = sql_quote (host_ip);
+ sql_int64 (&report_host,
+ "SELECT id FROM report_hosts"
+ " WHERE host = '%s' AND report = %llu",
+ quoted_host,
+ report);
+ g_free (quoted_host);
+ if (report_host == 0)
+ {
+ g_warning ("%s: report_host for host '%s' and report '%s' not found.",
+ __FUNCTION__, host_ip, report_id);
+ free (report_id);
+ return -1;
+ }
+
+ /* Create assets */
+ ret = add_tls_certificates_from_report_host (report_host,
+ report_id,
+ host_ip);
+ if (ret)
+ {
+ free (report_id);
+ return ret;
+ }
+
+ return 0;
+}
+
/* Settings. */
diff --git a/src/manage_sql_tls_certificates.c b/src/manage_sql_tls_certificates.c
index 74ab63b21..d599b484f 100644
--- a/src/manage_sql_tls_certificates.c
+++ b/src/manage_sql_tls_certificates.c
@@ -39,12 +39,23 @@
*/
#define G_LOG_DOMAIN "md manage"
+// Static function prototypes
+
+static tls_certificate_t
+user_tls_certificate_match_internal (tls_certificate_t,
+ user_t,
+ const char *,
+ const char *);
+
+// Iterator for GMP get_tls_certificates
+
/**
* @brief Filter columns for tls_certificate iterator.
*/
#define TLS_CERTIFICATE_ITERATOR_FILTER_COLUMNS \
{ GET_ITERATOR_FILTER_COLUMNS, "subject_dn", "issuer_dn", "md5_fingerprint", \
- "activates", "expires", "valid", "certificate_format", NULL }
+ "activates", "expires", "valid", "certificate_format", "last_collected", \
+ "sha256_fingerprint", "serial", NULL }
/**
* @brief TLS Certificate iterator columns.
@@ -100,79 +111,35 @@
KEYWORD_TYPE_STRING \
}, \
{ \
- "activation_time", \
- "activates", \
- KEYWORD_TYPE_INTEGER \
- }, \
- { \
- "expiration_time", \
- "expires", \
- KEYWORD_TYPE_INTEGER \
- }, \
- { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
- }
-
-/**
- * @brief TLS Certificate iterator columns for trash case.
- */
-#define TLS_CERTIFICATE_ITERATOR_TRASH_COLUMNS \
- { \
- GET_ITERATOR_COLUMNS (tls_certificates_trash), \
- { \
- "certificate", \
+ "sha256_fingerprint", \
NULL, \
KEYWORD_TYPE_STRING \
}, \
{ \
- "subject_dn", \
+ "serial", \
NULL, \
KEYWORD_TYPE_STRING \
}, \
{ \
- "issuer_dn", \
+ "(SELECT iso_time(max(timestamp)) FROM tls_certificate_sources" \
+ " WHERE tls_certificate = tls_certificates.id)", \
NULL, \
KEYWORD_TYPE_STRING \
}, \
{ \
- "trust", \
- NULL, \
- KEYWORD_TYPE_INTEGER \
- }, \
- { \
- "md5_fingerprint", \
- NULL, \
- KEYWORD_TYPE_STRING \
- }, \
- { \
- "iso_time (activation_time)", \
"activation_time", \
+ "activates", \
KEYWORD_TYPE_INTEGER \
}, \
{ \
- "iso_time (expiration_time)", \
"expiration_time", \
+ "expires", \
KEYWORD_TYPE_INTEGER \
}, \
{ \
- "(CASE WHEN (expiration_time >= m_now() OR expiration_time = -1)" \
- " AND (activation_time <= m_now() OR activation_time = -1)" \
- " THEN 1 ELSE 0 END)", \
- "valid", \
- KEYWORD_TYPE_INTEGER \
- }, \
- { \
- "certificate_format", \
- NULL, \
- KEYWORD_TYPE_STRING \
- }, \
- { \
- "activation_time", \
- "activates", \
- KEYWORD_TYPE_INTEGER \
- }, \
- { \
- "expiration_time", \
- "expires", \
+ "(SELECT max(timestamp) FROM tls_certificate_sources" \
+ " WHERE tls_certificate = tls_certificates.id)", \
+ "last_collected", \
KEYWORD_TYPE_INTEGER \
}, \
{ NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
@@ -190,9 +157,8 @@ tls_certificate_count (const get_data_t *get)
{
static const char *extra_columns[] = TLS_CERTIFICATE_ITERATOR_FILTER_COLUMNS;
static column_t columns[] = TLS_CERTIFICATE_ITERATOR_COLUMNS;
- static column_t trash_columns[] = TLS_CERTIFICATE_ITERATOR_TRASH_COLUMNS;
- return count ("tls_certificate", get, columns, trash_columns, extra_columns,
+ return count ("tls_certificate", get, columns, NULL, extra_columns,
0, 0, 0, TRUE);
}
@@ -210,13 +176,12 @@ init_tls_certificate_iterator (iterator_t *iterator, const get_data_t *get)
{
static const char *filter_columns[] = TLS_CERTIFICATE_ITERATOR_FILTER_COLUMNS;
static column_t columns[] = TLS_CERTIFICATE_ITERATOR_COLUMNS;
- static column_t trash_columns[] = TLS_CERTIFICATE_ITERATOR_TRASH_COLUMNS;
return init_get_iterator (iterator,
"tls_certificate",
get,
columns,
- trash_columns,
+ NULL,
filter_columns,
0,
NULL,
@@ -326,27 +291,45 @@ DEF_ACCESS (tls_certificate_iterator_certificate_format,
GET_ITERATOR_COLUMN_COUNT + 8);
/**
- * @brief Return whether a tls_certificate is in use.
+ * @brief Get a column value from a tls_certificate iterator.
*
- * @param[in] tls_certificate TLS Certificate.
+ * @param[in] iterator Iterator.
*
- * @return 1 if in use, else 0.
+ * @return Value of the column or NULL if iteration is complete.
*/
-int
-tls_certificate_in_use (tls_certificate_t tls_certificate)
-{
- return 0;
-}
+DEF_ACCESS (tls_certificate_iterator_sha256_fingerprint,
+ GET_ITERATOR_COLUMN_COUNT + 9);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_iterator_serial,
+ GET_ITERATOR_COLUMN_COUNT + 10);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_iterator_last_collected,
+ GET_ITERATOR_COLUMN_COUNT + 11);
+
/**
- * @brief Return whether a trashcan tls_certificate is in use.
+ * @brief Return whether a tls_certificate is in use.
*
* @param[in] tls_certificate TLS Certificate.
*
* @return 1 if in use, else 0.
*/
int
-trash_tls_certificate_in_use (tls_certificate_t tls_certificate)
+tls_certificate_in_use (tls_certificate_t tls_certificate)
{
return 0;
}
@@ -365,62 +348,212 @@ tls_certificate_writable (tls_certificate_t tls_certificate)
}
/**
- * @brief Return whether a trashcan tls_certificate is writable.
+ * @brief Create or update a TLS certificate from collected data
*
- * @param[in] tls_certificate TLS Certificate.
+ * @param[in] name Optional name for the certificate.
+ * @param[in] comment Optional comment for the certificate.
+ * @param[in] certificate_b64 Base64 encoded certificate.
+ * @param[in] activation_time Activation time of the certificate.
+ * @param[in] expiration_time Expiration time of the certificate
+ * @param[in] md5_fingerprint MD5 fingerprint of the certificate.
+ * @param[in] sha256_fingerprint SHA-256 fingerprint of the certificate.
+ * @param[in] subject_dn Subject DN of the certificate.
+ * @param[in] issuer_dn Issuer DN of the certificate.
+ * @param[in] serial Serial of the certificate.
+ * @param[in] certificate_format Certificate format (0 = DER, 1 = PEM).
+ * @param[in] trust Whether to trust the certificate.
+ * @param[in] update Whether/how to update if certificate exists.
+ * 0: reject, 1: update missing.
+ * @param[out] tls_certificate Created TLS certificate.
*
- * @return 1 if writable, else 0.
+ * @return 0 success, -1 error, 3 certificate already exists.
*/
-int
-trash_tls_certificate_writable (tls_certificate_t tls_certificate)
+static int
+make_tls_certificate (const char *name,
+ const char *comment,
+ const char *certificate_b64,
+ time_t activation_time,
+ time_t expiration_time,
+ const char *md5_fingerprint,
+ const char *sha256_fingerprint,
+ const char *subject_dn,
+ const char *issuer_dn,
+ const char *serial,
+ gnutls_x509_crt_fmt_t certificate_format,
+ int trust,
+ int update,
+ tls_certificate_t *tls_certificate)
{
- return trash_tls_certificate_in_use (tls_certificate) == 0;
-}
+ gchar *quoted_name, *quoted_comment, *quoted_certificate_b64;
+ gchar *quoted_md5_fingerprint, *quoted_sha256_fingerprint;
+ gchar *quoted_subject_dn, *quoted_issuer_dn, *quoted_serial;
-/**
- * @brief Get a string representation of a certificate format.
- *
- * @param[in] certificate_format The format as gnutls_x509_crt_fmt_t.
- *
- * @return A string representation of the format (e.g. "PEM" or "DER").
- */
-static const char*
-tls_certificate_format_str (gnutls_x509_crt_fmt_t certificate_format)
-{
- switch (certificate_format)
+ user_t current_user = 0;
+ tls_certificate_t old_tls_certificate, new_tls_certificate;
+
+ if (sha256_fingerprint == NULL || strcmp (sha256_fingerprint, "") == 0)
+ {
+ g_warning ("%s: Missing/empty sha256_fingerprint", __FUNCTION__);
+ return -1;
+ }
+
+ sql_int64 (¤t_user,
+ "SELECT id FROM users WHERE uuid = '%s'",
+ current_credentials.uuid);
+
+ old_tls_certificate
+ = user_tls_certificate_match_internal (0,
+ current_user,
+ sha256_fingerprint,
+ md5_fingerprint);
+
+ if (old_tls_certificate && update != 1)
+ {
+ return 3;
+ }
+
+ if (name && strcmp (name, ""))
+ quoted_name = sql_quote (name);
+ else
+ quoted_name = sql_quote (sha256_fingerprint);
+ quoted_comment
+ = sql_quote (comment ? comment : "");
+ quoted_certificate_b64
+ = sql_quote (certificate_b64 ? certificate_b64 : "");
+ quoted_md5_fingerprint
+ = sql_quote (md5_fingerprint ? md5_fingerprint : "");
+ quoted_sha256_fingerprint
+ = sql_quote (sha256_fingerprint ? sha256_fingerprint : "");
+ quoted_subject_dn
+ = sql_quote (subject_dn ? subject_dn : "");
+ quoted_issuer_dn
+ = sql_quote (issuer_dn ? issuer_dn : "");
+ quoted_serial
+ = sql_quote (serial ? serial : "");
+
+ if (old_tls_certificate)
+ {
+ if (update == 1)
+ {
+ /*
+ * Update any columns that are NULL or empty.
+ *
+ * (activation_time and expiration_time are updated if unknown (-1),
+ * certificate_format is updated if certificate is updated)
+ */
+ sql ("UPDATE tls_certificates SET"
+ " certificate"
+ " = coalesce (nullif (certificate, ''), '%s'),"
+ " activation_time"
+ " = coalesce (nullif (activation_time, -1), %ld),"
+ " expiration_time"
+ " = coalesce (nullif (expiration_time, -1), %ld),"
+ " md5_fingerprint"
+ " = coalesce (nullif (md5_fingerprint, ''), '%s'),"
+ " sha256_fingerprint"
+ " = coalesce (nullif (sha256_fingerprint, ''), '%s'),"
+ " subject_dn"
+ " = coalesce (nullif (subject_dn, ''), '%s'),"
+ " issuer_dn"
+ " = coalesce (nullif (issuer_dn, ''), '%s'),"
+ " serial"
+ " = coalesce (nullif (serial, ''), '%s'),"
+ " certificate_format"
+ " = (CASE"
+ " WHEN (certificate IS NULL) OR (certificate = '')"
+ " THEN '%s'"
+ " ELSE certificate_format"
+ " END),"
+ " modification_time = m_now ()"
+ " WHERE id = %llu",
+ quoted_certificate_b64,
+ activation_time,
+ expiration_time,
+ quoted_md5_fingerprint,
+ quoted_sha256_fingerprint,
+ quoted_subject_dn,
+ quoted_issuer_dn,
+ quoted_serial,
+ tls_certificate_format_str (certificate_format),
+ old_tls_certificate);
+
+ new_tls_certificate = old_tls_certificate;
+ }
+ }
+ else
{
- case GNUTLS_X509_FMT_DER:
- return "DER";
- case GNUTLS_X509_FMT_PEM:
- return "PEM";
- default:
- return "unknown";
+ sql ("INSERT INTO tls_certificates"
+ " (uuid, owner, name, comment, creation_time, modification_time,"
+ " certificate, subject_dn, issuer_dn, trust,"
+ " activation_time, expiration_time,"
+ " md5_fingerprint, sha256_fingerprint, serial, certificate_format)"
+ " SELECT make_uuid(),"
+ " (SELECT id FROM users WHERE users.uuid = '%s'),"
+ " '%s', '%s', m_now(), m_now(), '%s', '%s', '%s', %d,"
+ " %ld, %ld,"
+ " '%s', '%s', '%s', '%s';",
+ current_credentials.uuid,
+ quoted_name,
+ quoted_comment,
+ quoted_certificate_b64,
+ quoted_subject_dn,
+ quoted_issuer_dn,
+ trust,
+ activation_time,
+ expiration_time,
+ quoted_md5_fingerprint,
+ quoted_sha256_fingerprint,
+ quoted_serial,
+ tls_certificate_format_str (certificate_format));
+
+ new_tls_certificate = sql_last_insert_id ();
}
+
+ g_free (quoted_name);
+ g_free (quoted_comment);
+ g_free (quoted_certificate_b64);
+ g_free (quoted_subject_dn);
+ g_free (quoted_issuer_dn);
+ g_free (quoted_md5_fingerprint);
+ g_free (quoted_sha256_fingerprint);
+ g_free (quoted_serial);
+
+ if (tls_certificate)
+ *tls_certificate = new_tls_certificate;
+
+ return 0;
}
/**
- * @brief Create a TLS certificate.
+ * @brief Create or update a TLS certificate from Base64 encoded file content.
*
- * @param[in] name Name of new TLS certificate.
- * @param[in] comment Comment of TLS certificate.
- * @param[in] certificate_b64 Base64 certificate file content.
- * @param[in] trust Whether to trust the certificate.
+ * @param[in] name Name of new TLS certificate.
+ * @param[in] comment Comment of TLS certificate.
+ * @param[in] certificate_b64 Base64 certificate file content.
+ * @param[in] fallback_fpr Fallback fingerprint if getting data fails.
+ * @param[in] trust Whether to trust the certificate.
+ * @param[in] allow_failed_info Whether to use if get_certificate_info fails.
+ * @param[in] update Whether/how to update if certificate exists.
+ * 0: reject, 1: update missing.
* @param[out] tls_certificate Created TLS certificate.
*
* @return 0 success, 1 invalid certificate content, 2 certificate not Base64,
- * 99 permission denied, -1 error.
+ * 3 certificate already exists, 99 permission denied, -1 error.
*/
int
-create_tls_certificate (const char *name,
- const char *comment,
- const char *certificate_b64,
- int trust,
- tls_certificate_t *tls_certificate)
+make_tls_certificate_from_base64 (const char *name,
+ const char *comment,
+ const char *certificate_b64,
+ const char *fallback_fpr,
+ int trust,
+ int allow_failed_info,
+ int update,
+ tls_certificate_t *tls_certificate)
{
int ret;
gchar *certificate_decoded;
gsize certificate_len;
- char *md5_fingerprint, *subject_dn, *issuer_dn;
+ char *md5_fingerprint, *sha256_fingerprint, *subject_dn, *issuer_dn, *serial;
time_t activation_time, expiration_time;
gnutls_x509_crt_fmt_t certificate_format;
@@ -435,35 +568,90 @@ create_tls_certificate (const char *name,
&activation_time,
&expiration_time,
&md5_fingerprint,
+ &sha256_fingerprint,
&subject_dn,
&issuer_dn,
+ &serial,
&certificate_format);
+ if (ret && (allow_failed_info == 0 || fallback_fpr == NULL))
+ {
+ g_free (certificate_decoded);
+ return 1;
+ }
+ else
+ {
+ sha256_fingerprint = g_strdup (fallback_fpr);
+ }
+
+ ret = make_tls_certificate (name,
+ comment,
+ certificate_b64,
+ activation_time,
+ expiration_time,
+ md5_fingerprint,
+ sha256_fingerprint,
+ subject_dn,
+ issuer_dn,
+ serial,
+ certificate_format,
+ trust,
+ update,
+ tls_certificate);
+
+ g_free (certificate_decoded);
+ g_free (md5_fingerprint);
+ g_free (sha256_fingerprint);
+ g_free (subject_dn);
+ g_free (issuer_dn);
+ g_free (serial);
+
+ return ret;
+}
+
+/**
+ * @brief Create a TLS certificate.
+ *
+ * @param[in] name Name of new TLS certificate.
+ * @param[in] comment Comment of TLS certificate.
+ * @param[in] certificate_b64 Base64 certificate file content.
+ * @param[in] trust Whether to trust the certificate.
+ * @param[out] tls_certificate Created TLS certificate.
+ *
+ * @return 0 success, 1 invalid certificate content, 2 certificate not Base64,
+ * 3 certificate already exists, 99 permission denied, -1 error.
+ */
+int
+create_tls_certificate (const char *name,
+ const char *comment,
+ const char *certificate_b64,
+ int trust,
+ tls_certificate_t *tls_certificate)
+{
+ int ret;
+ tls_certificate_t new_tls_certificate;
+
+ ret = make_tls_certificate_from_base64 (name,
+ comment,
+ certificate_b64,
+ NULL, /* fallback_fpr */
+ trust,
+ 0, /* allow_failed_info */
+ 0, /* update */
+ &new_tls_certificate);
+
if (ret)
- return 1;
-
- sql ("INSERT INTO tls_certificates"
- " (uuid, owner, name, comment, creation_time, modification_time,"
- " certificate, subject_dn, issuer_dn, trust,"
- " activation_time, expiration_time, md5_fingerprint,"
- " certificate_format)"
- " SELECT make_uuid(), (SELECT id FROM users WHERE users.uuid = '%s'),"
- " '%s', '%s', m_now(), m_now(), '%s', '%s', '%s', %d,"
- " %ld, %ld, '%s', '%s';",
- current_credentials.uuid,
- name ? name : md5_fingerprint,
- comment ? comment : "",
- certificate_b64 ? certificate_b64 : "",
- subject_dn ? subject_dn : "",
- issuer_dn ? issuer_dn : "",
- trust,
- activation_time,
- expiration_time,
- md5_fingerprint,
- tls_certificate_format_str (certificate_format));
+ return ret;
+
+ get_or_make_tls_certificate_source (new_tls_certificate,
+ NULL, /* host_ip */
+ NULL, /* port */
+ "Import",
+ NULL, /* origin_id */
+ NULL); /* origin_data */
if (tls_certificate)
- *tls_certificate = sql_last_insert_id ();
+ *tls_certificate = new_tls_certificate;
return 0;
}
@@ -496,7 +684,7 @@ copy_tls_certificate (const char *name,
ret = copy_resource ("tls_certificate", name, comment, tls_certificate_id,
"certificate, subject_dn, issuer_dn, trust,"
"activation_time, expiration_time, md5_fingerprint,"
- "certificate_format",
+ "certificate_format, sha256_fingerprint, serial",
0, new_tls_certificate, &old_tls_certificate);
if (ret)
return ret;
@@ -507,8 +695,11 @@ copy_tls_certificate (const char *name,
/**
* @brief Delete a tls_certificate.
*
+ * TLS certificates do not use the trashcan, so the "ultimate" param is ignored
+ * and the resource is always removed completely.
+ *
* @param[in] tls_certificate_id UUID of tls_certificate.
- * @param[in] ultimate Whether to remove entirely, or to trashcan.
+ * @param[in] ultimate Dummy for consistency with other delete commands.
*
* @return 0 success, 1 fail because tls_certificate is in use,
* 2 failed to find tls_certificate,
@@ -541,92 +732,35 @@ delete_tls_certificate (const char *tls_certificate_id, int ultimate)
if (tls_certificate == 0)
{
- /* No such tls_certificate, check the trashcan. */
-
- if (find_trash ("tls_certificate",
- tls_certificate_id,
- &tls_certificate))
- {
- sql_rollback ();
- return -1;
- }
- if (tls_certificate == 0)
- {
- sql_rollback ();
- return 2;
- }
- if (ultimate == 0)
- {
- /* It's already in the trashcan. */
- sql_commit ();
- return 0;
- }
-
- sql ("DELETE FROM permissions"
- " WHERE resource_type = 'tls_certificate'"
- " AND resource_location = %i"
- " AND resource = %llu;",
- LOCATION_TRASH,
- tls_certificate);
-
- tags_remove_resource ("tls_certificate",
- tls_certificate,
- LOCATION_TRASH);
-
- sql ("DELETE FROM tls_certificates_trash WHERE id = %llu;",
- tls_certificate);
-
- sql_commit ();
- return 0;
+ /* No such tls_certificate */
+ sql_rollback ();
+ return 2;
}
- /* TLS certificate was found in regular table. */
-
- if (ultimate == 0)
- {
- tls_certificate_t trash_tls_certificate;
-
- /* Move to trash. */
-
- sql ("INSERT INTO tls_certificates_trash"
- " (uuid, owner, name, comment, creation_time, modification_time,"
- " certificate, subject_dn, issuer_dn, trust,"
- " activation_time, expiration_time, md5_fingerprint,"
- " certificate_format)"
- " SELECT"
- " uuid, owner, name, comment, creation_time, modification_time,"
- " certificate, subject_dn, issuer_dn, trust,"
- " activation_time, expiration_time, md5_fingerprint,"
- " certificate_format"
- " FROM tls_certificates WHERE id = %llu;",
- tls_certificate);
-
- trash_tls_certificate = sql_last_insert_id ();
-
- permissions_set_locations ("tls_certificate",
- tls_certificate,
- trash_tls_certificate,
- LOCATION_TRASH);
- tags_set_locations ("tls_certificate",
- tls_certificate,
- trash_tls_certificate,
- LOCATION_TRASH);
- }
- else
- {
- /* Delete entirely. */
+ sql ("DELETE FROM permissions"
+ " WHERE resource_type = 'tls_certificate'"
+ " AND resource_location = %i"
+ " AND resource = %llu;",
+ LOCATION_TABLE,
+ tls_certificate);
+
+ tags_remove_resource ("tls_certificate",
+ tls_certificate,
+ LOCATION_TABLE);
+
+ sql ("DELETE FROM tls_certificate_sources"
+ " WHERE tls_certificate = %llu",
+ tls_certificate);
- sql ("DELETE FROM permissions"
- " WHERE resource_type = 'tls_certificate'"
- " AND resource_location = %i"
- " AND resource = %llu;",
- LOCATION_TABLE,
- tls_certificate);
+ sql ("DELETE FROM tls_certificate_locations"
+ " WHERE NOT EXISTS"
+ " (SELECT * FROM tls_certificate_sources"
+ " WHERE location = tls_certificate_locations.id);");
- tags_remove_resource ("tls_certificate",
- tls_certificate,
- LOCATION_TABLE);
- }
+ sql ("DELETE FROM tls_certificate_origins"
+ " WHERE NOT EXISTS"
+ " (SELECT * FROM tls_certificate_sources"
+ " WHERE origin = tls_certificate_origins.id);");
sql ("DELETE FROM tls_certificates WHERE id = %llu;",
tls_certificate);
@@ -635,89 +769,6 @@ delete_tls_certificate (const char *tls_certificate_id, int ultimate)
return 0;
}
-/**
- * @brief Try restore a tls_certificate.
- *
- * If success, ends transaction for caller before exiting.
- *
- * @param[in] tls_certificate_id UUID of resource.
- *
- * @return 0 success, 1 fail because tls_certificate is in use,
- * 2 failed to find tls_certificate, -1 error.
- */
-int
-restore_tls_certificate (const char *tls_certificate_id)
-{
- tls_certificate_t trash_tls_certificate, tls_certificate;
-
- if (find_trash ("tls_certificate",
- tls_certificate_id,
- &trash_tls_certificate))
- {
- sql_rollback ();
- return -1;
- }
-
- if (trash_tls_certificate == 0)
- return 2;
-
- /* Move the tls_certificate back to the regular table. */
-
- sql ("INSERT INTO tls_certificates"
- " (uuid, owner, name, comment, creation_time, modification_time,"
- " certificate, subject_dn, issuer_dn, trust,"
- " activation_time, expiration_time, md5_fingerprint,"
- " certificate_format)"
- " SELECT"
- " uuid, owner, name, comment, creation_time, modification_time,"
- " certificate, subject_dn, issuer_dn, trust,"
- " activation_time, expiration_time, md5_fingerprint,"
- " certificate_format"
- " FROM tls_certificates_trash WHERE id = %llu;",
- trash_tls_certificate);
-
- tls_certificate = sql_last_insert_id ();
-
- /* Adjust references to the tls_certificate. */
-
- permissions_set_locations ("tls_certificate",
- trash_tls_certificate,
- tls_certificate,
- LOCATION_TABLE);
- tags_set_locations ("tls_certificate",
- trash_tls_certificate,
- tls_certificate,
- LOCATION_TABLE);
-
- /* Clear out the trashcan tls_certificate. */
-
- sql ("DELETE FROM tls_certificates_trash WHERE id = %llu;",
- trash_tls_certificate);
-
- sql_commit ();
- return 0;
-}
-
-/**
- * @brief Empty TLS certificate trashcans.
- */
-void
-empty_trashcan_tls_certificates ()
-{
- sql ("DELETE FROM permissions"
- " WHERE resource_type = 'tls_certificate'"
- " AND resource_location = %i"
- " AND resource IN (SELECT id FROM tls_certificates_trash"
- " WHERE owner = (SELECT id FROM users"
- " WHERE uuid = '%s'));",
- LOCATION_TRASH,
- current_credentials.uuid);
-
- sql ("DELETE FROM tls_certifcates_trash"
- " WHERE owner = (SELECT id FROM users WHERE uuid = '%s');",
- current_credentials.uuid);
-}
-
/**
* @brief Delete all TLS certificate owned by a user.
*
@@ -765,7 +816,6 @@ inherit_tls_certificates (user_t user, user_t inheritor)
* @param[in] tls_certificate_id UUID of TLS certificate.
* @param[in] comment New comment on TLS certificate.
* @param[in] name New name of TLS certificate.
- * @param[in] certificate_b64 New Base64 certificate file content.
* @param[in] trust New trust value or -1 to keep old value.
*
* @return 0 success, 1 TLS certificate exists already,
@@ -777,7 +827,6 @@ int
modify_tls_certificate (const gchar *tls_certificate_id,
const gchar *comment,
const gchar *name,
- const gchar *certificate_b64,
int trust)
{
tls_certificate_t tls_certificate;
@@ -812,62 +861,6 @@ modify_tls_certificate (const gchar *tls_certificate_id,
return 2;
}
- /* Update certificate if requested. */
-
- if (certificate_b64)
- {
- gchar *quoted_certificate;
- int ret;
- char *md5_fingerprint, *subject_dn, *issuer_dn;
- time_t activation_time, expiration_time;
- gnutls_x509_crt_fmt_t certificate_format;
-
- gchar *certificate_decoded;
- gsize certificate_len;
-
- certificate_decoded
- = (gchar*) g_base64_decode (certificate_b64, &certificate_len);
-
- if (certificate_decoded == NULL || certificate_len == 0)
- {
- sql_rollback ();
- return 4;
- }
-
- ret = get_certificate_info (certificate_decoded,
- certificate_len,
- &activation_time,
- &expiration_time,
- &md5_fingerprint,
- &subject_dn,
- &issuer_dn,
- &certificate_format);
-
- if (ret)
- return 3;
-
- quoted_certificate = sql_quote (certificate_b64);
- sql ("UPDATE tls_certificates SET"
- " certificate = '%s',"
- " activation_time = %llu,"
- " expiration_time = %llu,"
- " md5_fingerprint = '%s',"
- " subject_dn = '%s',"
- " issuer_dn = '%s',"
- " modification_time = m_now (),"
- " certificate_format = '%s'"
- " WHERE id = %llu;",
- quoted_certificate,
- activation_time,
- expiration_time,
- md5_fingerprint,
- subject_dn,
- issuer_dn,
- tls_certificate_format_str (certificate_format),
- tls_certificate);
- g_free (quoted_certificate);
- }
-
/* Update comment if requested. */
if (comment)
@@ -930,3 +923,600 @@ tls_certificate_uuid (tls_certificate_t tls_certificate)
return sql_string ("SELECT uuid FROM tls_certificates WHERE id = %llu;",
tls_certificate);
}
+
+/**
+ * @brief Initialise an iterator of TLS certificate sources
+ *
+ * @param[in] iterator Iterator to initialise.
+ * @param[in] tls_certificate TLS certificate to get sources for.
+ *
+ * @return 0 success, -1 error.
+ */
+int
+init_tls_certificate_source_iterator (iterator_t *iterator,
+ tls_certificate_t tls_certificate)
+{
+ init_iterator (iterator,
+ "SELECT tls_certificate_sources.uuid,"
+ " iso_time(timestamp) AS iso_timestamp,"
+ " tls_versions,"
+ " tls_certificate_locations.uuid,"
+ " host_ip, port,"
+ " tls_certificate_origins.uuid,"
+ " origin_type, origin_id, origin_data"
+ " FROM tls_certificate_sources"
+ " LEFT OUTER JOIN tls_certificate_origins"
+ " ON tls_certificate_origins.id = origin"
+ " LEFT OUTER JOIN tls_certificate_locations"
+ " ON tls_certificate_locations.id = location"
+ " WHERE tls_certificate = %llu"
+ " ORDER BY timestamp DESC",
+ tls_certificate);
+
+ return 0;
+}
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_uuid, 0);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_timestamp, 1);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_tls_versions, 2);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_location_uuid, 3);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_location_host_ip, 4);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_location_port, 5);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_origin_uuid, 6);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_origin_type, 7);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_origin_id, 8);
+
+/**
+ * @brief Get a column value from a tls_certificate iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Value of the column or NULL if iteration is complete.
+ */
+DEF_ACCESS (tls_certificate_source_iterator_origin_data, 9);
+
+/**
+ * @brief Gets or creates a tls_certificate_location.
+ *
+ * If a location with matching host_ip and port exists its id is returned,
+ * otherwise a new one is created and its id is returned.
+ *
+ * @param[in] host_ip IP address of the location
+ * @param[in] port Port number of the location
+ *
+ * @return Row id of the tls_certificate_location
+ */
+resource_t
+get_or_make_tls_certificate_location (const char *host_ip,
+ const char *port)
+{
+ resource_t location = 0;
+ char *quoted_host_ip, *quoted_port;
+ quoted_host_ip = host_ip ? sql_quote (host_ip) : g_strdup ("");
+ quoted_port = port ? sql_quote (port) : g_strdup ("");
+
+ sql_int64 (&location,
+ "SELECT id"
+ " FROM tls_certificate_locations"
+ " WHERE host_ip = '%s'"
+ " AND port = '%s'",
+ quoted_host_ip,
+ quoted_port);
+
+ if (location)
+ {
+ g_free (quoted_host_ip);
+ g_free (quoted_port);
+ return location;
+ }
+
+ sql ("INSERT INTO tls_certificate_locations"
+ " (uuid, host_ip, port)"
+ " VALUES (make_uuid (), '%s', '%s')",
+ quoted_host_ip,
+ quoted_port);
+
+ location = sql_last_insert_id ();
+
+ g_free (quoted_host_ip);
+ g_free (quoted_port);
+
+ return location;
+}
+
+/**
+ * @brief Gets or creates a tls_certificate_origin.
+ *
+ * If an origin with matching type, id and data exists its id is returned,
+ * otherwise a new one is created and its id is returned.
+ *
+ * @param[in] origin_type Origin type, e.g. "GMP" or "Report"
+ * @param[in] origin_id Origin resource id, e.g. a report UUID.
+ * @param[in] origin_data Origin extra data, e.g. OID of generating NVT.
+ *
+ * @return Row id of the tls_certificate_origin
+ */
+resource_t
+get_or_make_tls_certificate_origin (const char *origin_type,
+ const char *origin_id,
+ const char *origin_data)
+{
+ resource_t origin = 0;
+ char *quoted_origin_type, *quoted_origin_id, *quoted_origin_data;
+ quoted_origin_type = origin_type ? sql_quote (origin_type) : g_strdup ("");
+ quoted_origin_id = origin_id ? sql_quote (origin_id) : g_strdup ("");
+ quoted_origin_data = origin_data ? sql_quote (origin_data) : g_strdup ("");
+
+ sql_int64 (&origin,
+ "SELECT id"
+ " FROM tls_certificate_origins"
+ " WHERE origin_type = '%s'"
+ " AND origin_id = '%s'"
+ " AND origin_data = '%s'",
+ quoted_origin_type,
+ quoted_origin_id,
+ quoted_origin_data);
+
+ if (origin)
+ {
+ g_free (quoted_origin_type);
+ g_free (quoted_origin_id);
+ g_free (quoted_origin_data);
+ return origin;
+ }
+
+ sql ("INSERT INTO tls_certificate_origins"
+ " (uuid, origin_type, origin_id, origin_data)"
+ " VALUES (make_uuid (), '%s', '%s', '%s')",
+ quoted_origin_type,
+ quoted_origin_id,
+ quoted_origin_data);
+
+ origin = sql_last_insert_id ();
+
+ g_free (quoted_origin_type);
+ g_free (quoted_origin_id);
+ g_free (quoted_origin_data);
+
+ return origin;
+}
+
+/**
+ * @brief Gets or creates a tls_certificate_source.
+ *
+ * If a source with matching location and origin data exists its id is
+ * returned, otherwise a new one is created and its id is returned.
+ *
+ * If all the location data is NULL a NULL location is fetched / created.
+ *
+ * @param[in] tls_certificate The TLS certificate of the source
+ * @param[in] host_ip IP address of the location
+ * @param[in] port Port number of the location
+ * @param[in] origin_type Origin type, e.g. "GMP" or "Report"
+ * @param[in] origin_id Origin resource id, e.g. a report UUID.
+ * @param[in] origin_data Origin extra data, e.g. OID of generating NVT.
+ *
+ * @return Row id of the tls_certificate_origin
+ */
+resource_t
+get_or_make_tls_certificate_source (tls_certificate_t tls_certificate,
+ const char *host_ip,
+ const char *port,
+ const char *origin_type,
+ const char *origin_id,
+ const char *origin_data)
+{
+ resource_t location, origin, source;
+
+ if (tls_certificate == 0)
+ {
+ g_warning ("%s: No TLS certificate given", __FUNCTION__);
+ return 0;
+ }
+
+ if (host_ip || port)
+ location = get_or_make_tls_certificate_location (host_ip, port);
+ else
+ location = 0;
+
+ origin = get_or_make_tls_certificate_origin (origin_type,
+ origin_id,
+ origin_data);
+
+ source = 0;
+ if (location)
+ {
+ sql_int64 (&source,
+ "SELECT id FROM tls_certificate_sources"
+ " WHERE tls_certificate = %llu"
+ " AND location = %llu"
+ " AND origin = %llu",
+ tls_certificate,
+ location,
+ origin);
+ }
+ else
+ {
+ sql_int64 (&source,
+ "SELECT id FROM tls_certificate_sources"
+ " WHERE tls_certificate = %llu"
+ " AND location IS NULL"
+ " AND origin = %llu",
+ tls_certificate,
+ origin);
+ }
+
+ if (source == 0)
+ {
+ sql ("INSERT INTO tls_certificate_sources"
+ " (uuid, tls_certificate, location, origin, timestamp)"
+ " VALUES"
+ " (make_uuid(), %llu, nullif(%llu, 0), %llu, m_now());",
+ tls_certificate,
+ location,
+ origin);
+ source = sql_last_insert_id ();
+ }
+
+ return source;
+}
+
+/**
+ * @brief Tries to find a matching certificate for a given user
+ *
+ * @param[in] tls_certificate The certificate to check
+ * @param[in] user The user to check
+ * @param[in] sha256_fingerprint The SHA256 fingerprint to match
+ * @param[in] md5_fingerprint The MD5 fingerprint to match
+ *
+ * @return The matching certificate or 0 if none is found.
+ */
+static tls_certificate_t
+user_tls_certificate_match_internal (tls_certificate_t tls_certificate,
+ user_t user,
+ const char *sha256_fingerprint,
+ const char *md5_fingerprint)
+{
+ gchar *quoted_sha256_fingerprint, *quoted_md5_fingerprint;
+ tls_certificate_t ret_tls_certificate = 0;
+
+ quoted_sha256_fingerprint
+ = sql_quote (sha256_fingerprint ? sha256_fingerprint : "");
+ quoted_md5_fingerprint
+ = sql_quote (md5_fingerprint ? md5_fingerprint : "");
+
+ sql_int64 (&ret_tls_certificate,
+ "SELECT id FROM tls_certificates"
+ " WHERE (id = %llu"
+ " OR sha256_fingerprint = '%s'"
+ " OR md5_fingerprint = '%s')"
+ " AND owner = %llu",
+ tls_certificate,
+ quoted_sha256_fingerprint,
+ quoted_md5_fingerprint,
+ user);
+
+ g_free (quoted_sha256_fingerprint);
+ g_free (quoted_md5_fingerprint);
+
+ return ret_tls_certificate;
+}
+
+/**
+ * @brief Checks if user owns a certificate or one with the same fingerprints.
+ *
+ * @param[in] tls_certificate The certificate to check
+ * @param[in] user The user to check
+ *
+ * @return 1 matching certificate found, 0 no matching certificate
+ */
+int
+user_has_tls_certificate (tls_certificate_t tls_certificate,
+ user_t user)
+{
+ gchar *sha256_fingerprint, *md5_fingerprint;
+
+ sql_int64 (&user,
+ "SELECT id FROM users WHERE uuid = '%s'",
+ current_credentials.uuid);
+
+ sha256_fingerprint
+ = sql_string ("SELECT sha256_fingerprint FROM tls_certificates"
+ " WHERE id = %llu",
+ tls_certificate);
+ md5_fingerprint
+ = sql_string ("SELECT md5_fingerprint FROM tls_certificates"
+ " WHERE id = %llu",
+ tls_certificate);
+
+ if (user_tls_certificate_match_internal (tls_certificate,
+ user,
+ sha256_fingerprint,
+ md5_fingerprint))
+ {
+ g_free (sha256_fingerprint);
+ g_free (md5_fingerprint);
+ return 1;
+ }
+
+ g_free (sha256_fingerprint);
+ g_free (md5_fingerprint);
+
+ return 0;
+}
+
+/**
+ * @brief Collects and add TLS certificates from the details of a report host.
+ *
+ * @param[in] report_host The report host to get certificates from.
+ * @param[in] report_id UUID of the report
+ * @param[in] host_ip The IP address of the report host.
+ *
+ * @return 0: success, -1: error
+ */
+int
+add_tls_certificates_from_report_host (report_host_t report_host,
+ const char *report_id,
+ const char *host_ip)
+{
+ 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;
+
+ /* host_ip and report_id are expected to avoid possibly redundant
+ * SQL queries to get them */
+ if (report_host == 0
+ || host_ip == NULL
+ || report_id == NULL
+ || strcmp (host_ip, "") == 0
+ || strcmp (report_id, "") == 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;
+ const char *source_name;
+ char *ssldetails;
+ tls_certificate_t tls_certificate;
+
+ iterator_t ports;
+ gboolean has_ports;
+
+ 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);
+
+ source_name = iterator_string (&tls_certs, 2);
+
+ g_debug ("%s: Handling certificate %s on %s in report %s",
+ __FUNCTION__, scanner_fpr, host_ip, report_id);
+
+ tls_certificate = 0;
+ 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);
+
+ parse_ssldetails (ssldetails,
+ &activation_time,
+ &expiration_time,
+ &issuer,
+ &serial);
+
+ free (ssldetails);
+
+ if (make_tls_certificate (sha256_fingerprint, /* name */
+ "", /* comment */
+ certificate_b64,
+ activation_time,
+ expiration_time,
+ md5_fingerprint,
+ sha256_fingerprint,
+ subject,
+ issuer,
+ serial,
+ certificate_format,
+ 0,
+ 1,
+ &tls_certificate)
+ || tls_certificate == 0)
+ {
+ g_warning ("%s: Could not create TLS certificate"
+ " or get existing one for fingerprint '%s'.",
+ __FUNCTION__, scanner_fpr);
+
+ g_free (certificate);
+ g_free (md5_fingerprint);
+ g_free (sha256_fingerprint);
+ g_free (subject);
+ g_free (issuer);
+ g_free (serial);
+ continue;
+ }
+
+ 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);
+
+ has_ports = FALSE;
+ while (next (&ports))
+ {
+ const char *value;
+ gchar *port, *quoted_port;
+ GString *versions;
+ iterator_t versions_iter;
+
+ value = iterator_string (&ports, 0);
+ port = g_strndup (value, g_strrstr (value, ":") - value - 1);
+ quoted_port = sql_quote (port);
+
+ has_ports = TRUE;
+
+ versions = g_string_new ("");
+ init_iterator (&versions_iter,
+ "SELECT value FROM report_host_details"
+ " WHERE report_host = %llu"
+ " AND name = 'TLS/%s'",
+ report_host,
+ quoted_port);
+ while (next (&versions_iter))
+ {
+ gchar *quoted_version;
+ quoted_version = sql_quote (iterator_string (&versions_iter, 0));
+
+ if (versions->len)
+ g_string_append (versions, ", ");
+ g_string_append (versions, quoted_version);
+ }
+ cleanup_iterator (&versions_iter);
+
+ get_or_make_tls_certificate_source (tls_certificate,
+ host_ip,
+ port,
+ "Report",
+ report_id,
+ source_name);
+
+ g_free (port);
+ g_free (quoted_port);
+ g_string_free (versions, TRUE);
+ }
+
+ if (has_ports == FALSE)
+ g_warning ("Certificate without ports: %s report:%s host:%s",
+ quoted_scanner_fpr, report_id, host_ip);
+
+ cleanup_iterator (&ports);
+
+ g_free (certificate);
+ g_free (md5_fingerprint);
+ g_free (sha256_fingerprint);
+ g_free (subject);
+ g_free (issuer);
+ g_free (serial);
+ }
+ cleanup_iterator (&tls_certs);
+
+ return 0;
+}
diff --git a/src/manage_sql_tls_certificates.h b/src/manage_sql_tls_certificates.h
index b51be75ed..2ceb7dc15 100644
--- a/src/manage_sql_tls_certificates.h
+++ b/src/manage_sql_tls_certificates.h
@@ -30,16 +30,18 @@
int
delete_tls_certificate (const char *, int);
-int
-restore_tls_certificate (const char *);
-
-void
-empty_trashcan_tls_certificates ();
-
void
delete_tls_certificates_user (user_t);
void
inherit_tls_certificates (user_t, user_t);
+int
+user_has_tls_certificate (tls_certificate_t, user_t);
+
+int
+add_tls_certificates_from_report_host (report_host_t,
+ const char*,
+ const char*);
+
#endif /* not _GVMD_MANAGE_SQL_TLS_CERTIFICATES_H */
diff --git a/src/manage_tls_certificates.c b/src/manage_tls_certificates.c
new file mode 100644
index 000000000..d2c0624b0
--- /dev/null
+++ b/src/manage_tls_certificates.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 2019 Greenbone Networks GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/**
+ * @file manage_tls_certificates.c
+ * @brief GVM management layer: TLS Certificates
+ *
+ * The TLS Certificates helper functions for the GVM management layer.
+ */
+
+/**
+ * @brief Enable extra functions.
+ *
+ * time.h in glibc2 needs this for strptime.
+ */
+#define _XOPEN_SOURCE
+
+#include "manage_tls_certificates.h"
+
+#include
+
+/**
+ * @brief Extract data from a SSLDetails:[...] host detail value
+ *
+ * This will try to free existing strings at the output pointers with g_free,
+ * so the caller must ensure it is safe to do so.
+ *
+ * @param[in] ssldetails The host detail value.
+ * @param[out] activation_time Pointer to return the activation time.
+ * @param[out] expiration_time Pointer to return the expiration time.
+ * @param[out] issuer Pointer to return the issuer.
+ * @param[out] serial Pointer to return the serial.
+ */
+void
+parse_ssldetails (const char *ssldetails,
+ time_t *activation_time,
+ time_t *expiration_time,
+ gchar **issuer,
+ gchar **serial)
+{
+ gchar **ssldetails_split, **ssldetails_point;
+
+ ssldetails_split = g_strsplit (ssldetails, "|", -1);
+ ssldetails_point = ssldetails_split;
+ while (*ssldetails_point)
+ {
+ gchar **detail_split;
+ detail_split = g_strsplit (*ssldetails_point, ":", 2);
+
+ if (detail_split[0] && detail_split[1])
+ {
+ if (strcmp (detail_split[0], "notBefore") == 0)
+ {
+ if (strcmp (detail_split[1], ""))
+ {
+ // Time is given as UTC time and uses special format
+ struct tm tm;
+ memset (&tm, 0, sizeof (struct tm));
+ tm.tm_isdst = -1;
+
+ if (strptime (detail_split[1], "%Y%m%dT%H%M%S", &tm)[0] == 0)
+ *activation_time = mktime (&tm);
+ else
+ *activation_time = -1;
+ }
+ else
+ *activation_time = 0;
+ }
+ else if (strcmp (detail_split[0], "notAfter") == 0)
+ {
+ if (strcmp (detail_split[1], ""))
+ {
+ // Time is given as UTC time and uses special format
+ struct tm tm;
+ memset (&tm, 0, sizeof (struct tm));
+ tm.tm_isdst = -1;
+
+ if (strptime (detail_split[1], "%Y%m%dT%H%M%S", &tm)[0] == 0)
+ *expiration_time = mktime (&tm);
+ else
+ *expiration_time = -1;
+ }
+ else
+ *expiration_time = 0;
+ }
+ else if (strcmp (detail_split[0], "issuer") == 0
+ && strcmp (detail_split[1], ""))
+ {
+ g_free (*issuer);
+ *issuer = g_strdup (detail_split[1]);
+ }
+ else if (strcmp (detail_split[0], "serial") == 0
+ && strcmp (detail_split[1], ""))
+ {
+ g_free (*serial);
+ *serial = g_strdup (detail_split[1]);
+ }
+ }
+ g_strfreev (detail_split);
+ ssldetails_point ++;
+ }
+ g_strfreev (ssldetails_split);
+}
+
+/**
+ * @brief Get a string representation of a certificate format.
+ *
+ * @param[in] certificate_format The format as gnutls_x509_crt_fmt_t.
+ *
+ * @return A string representation of the format (e.g. "PEM" or "DER").
+ */
+const char*
+tls_certificate_format_str (gnutls_x509_crt_fmt_t certificate_format)
+{
+ switch (certificate_format)
+ {
+ case GNUTLS_X509_FMT_DER:
+ return "DER";
+ case GNUTLS_X509_FMT_PEM:
+ return "PEM";
+ default:
+ return "unknown";
+ }
+}
diff --git a/src/manage_tls_certificates.h b/src/manage_tls_certificates.h
index 5272431f5..a39ca2a25 100644
--- a/src/manage_tls_certificates.h
+++ b/src/manage_tls_certificates.h
@@ -63,17 +63,20 @@ tls_certificate_iterator_valid (iterator_t *);
const char*
tls_certificate_iterator_certificate_format (iterator_t*);
-int
-tls_certificate_in_use (tls_certificate_t);
+const char*
+tls_certificate_iterator_sha256_fingerprint (iterator_t*);
-int
-trash_tls_certificate_in_use (tls_certificate_t);
+const char*
+tls_certificate_iterator_serial (iterator_t*);
+
+const char*
+tls_certificate_iterator_last_collected (iterator_t*);
int
-tls_certificate_writable (tls_certificate_t);
+tls_certificate_in_use (tls_certificate_t);
int
-trash_tls_certificate_writable (tls_certificate_t);
+tls_certificate_writable (tls_certificate_t);
int
create_tls_certificate (const char *, const char *, const char *, int,
@@ -84,10 +87,56 @@ copy_tls_certificate (const char*, const char*, const char*,
tls_certificate_t*);
int
-modify_tls_certificate (const gchar *, const gchar *, const gchar *,
- const gchar *, int);
+modify_tls_certificate (const gchar *, const gchar *, const gchar *, int);
char*
tls_certificate_uuid (tls_certificate_t);
+int
+init_tls_certificate_source_iterator (iterator_t *, tls_certificate_t);
+
+const char *
+tls_certificate_source_iterator_uuid (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_timestamp (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_tls_versions (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_location_uuid (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_location_host_ip (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_location_port (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_origin_uuid (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_origin_type (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_origin_id (iterator_t *);
+
+const char *
+tls_certificate_source_iterator_origin_data (iterator_t *);
+
+resource_t
+get_or_make_tls_certificate_location (const char *, const char *);
+
+resource_t
+get_or_make_tls_certificate_origin (const char *, const char *, const char *);
+
+resource_t
+get_or_make_tls_certificate_source (tls_certificate_t,
+ const char *,
+ const char *,
+ const char *,
+ const char *,
+ const char *);
+
#endif /* not _GVMD_MANAGE_TLS_CERTIFICATES_H */
diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in
index ec828b6f9..80a129189 100644
--- a/src/schema_formats/XML/GMP.xml.in
+++ b/src/schema_formats/XML/GMP.xml.in
@@ -6074,6 +6074,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
The client uses the create_tls_certificate command to create a new
TLS certificate.
+
+ TLS certificates owned by the current user must have unique
+ fingerprints, so copying will only work with fingerprints owned
+ by another user.
+
comment
@@ -22752,6 +22757,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Distinguished name (DN) of the certificate issuer
+
+ sha256_fingerprint
+ text
+
+ SHA256 fingerprint of the certificate
+
+ md5_fingerprinttext
@@ -22774,6 +22786,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
booleanWhether the certificate is currently valid
+
+ serial
+ text
+
+ Hexadecimal serial number of the certificate
+
+
+
+ last_collected
+ iso_time
+ Time the certificate was last collected
+
@@ -22818,12 +22842,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
in_usepermissionscertificate
+ sha256_fingerprintmd5_fingerprinttrustactivation_timeexpiration_timesubject_dnissuer_dn
+ serial
+ last_collected
+ sourcesowner
@@ -22910,6 +22938,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
The MD5 fingerprint of the certificatetext
+
+ sha256_fingerprint
+ The SHA256 fingerprint of the certificate
+ text
+ trustWhether the certificate is trusted
@@ -22940,6 +22973,110 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Distinguished name (DN) of the certificate issuertext
+
+ serial
+ Hexadecimal serial number of the certificate
+ text
+
+
+ last_collected
+ Most recent time the TLS certificate was imported or found in a scan
+ iso_time
+
+
+ sources
+ List of sources
+
+ source
+
+
+ source
+ A certificate source
+
+
+ id
+ UUID of the source
+ uuid
+ 1
+
+ timestamp
+ tls_versions
+ location
+ origin
+
+
+ timestamp
+ Time the certificate was found or imported
+ iso_time
+
+
+ tls_versions
+ SSL and TLS versions of the service using the certificate, separated with ", "
+ text
+
+
+ location
+ A location where the certificate was found
+
+
+ id
+ UUID of the location
+ uuid
+ 1
+
+ host
+ port
+
+
+ host
+ Host where the certificate was found
+
+ ip
+
+
+ ip
+ IP address of the host
+ text
+
+
+
+ port
+ Port where the certificate was found
+ integer
+
+
+
+ origin
+ Origin of the certificate data, e.g. a scan report
+
+
+ id
+ UUID of the location
+ uuid
+ 1
+
+ origin_type
+ origin_id
+ origin_data
+
+
+ origin_type
+ Type of origin, e.g. "Import" or "Report"
+ text
+
+
+ origin_id
+ Identifier of origin, e.g. a report UUID
+ text
+
+
+ origin_data
+ Extra origin data, e.g. OID of the detection NVT
+ text
+
+
+
+ filters
@@ -26123,7 +26260,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
copynametrust
- certificatecomment
@@ -26155,13 +26291,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
boolean
-
- certificate
- The Base64 encoded certificate data (x.509 DER or PEM)
-
- text
-
-
@@ -26178,14 +26307,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- Modify the name and certificate content of a TLS certificate
+ Modify the name of a TLS certificate
- Updated Example Certificate
- LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVrVENDQ[...]
-
+ Renamed Example Certificate