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 + ("" + "%s" + "%s", + tls_certificate_source_iterator_uuid (&sources), + tls_certificate_source_iterator_timestamp (&sources), + tls_certificate_source_iterator_tls_versions (&sources) + ? tls_certificate_source_iterator_tls_versions (&sources) + : ""); + + if (tls_certificate_source_iterator_location_uuid (&sources)) + { + SENDF_TO_CLIENT_OR_FAIL + ("" + "%s" + "%s" + "", + tls_certificate_source_iterator_location_uuid + (&sources), + tls_certificate_source_iterator_location_host_ip + (&sources), + tls_certificate_source_iterator_location_port + (&sources)); + } + + if (tls_certificate_source_iterator_origin_uuid (&sources)) + { + SENDF_TO_CLIENT_OR_FAIL + ("" + "%s" + "%s" + "%s" + "", + tls_certificate_source_iterator_origin_uuid (&sources), + tls_certificate_source_iterator_origin_type (&sources), + tls_certificate_source_iterator_origin_id (&sources), + tls_certificate_source_iterator_origin_data (&sources)); + } + + SEND_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_fingerprint text @@ -22774,6 +22786,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. boolean Whether 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_use permissions certificate + sha256_fingerprint md5_fingerprint trust activation_time expiration_time subject_dn issuer_dn + serial + last_collected + sources owner @@ -22910,6 +22938,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. The MD5 fingerprint of the certificate text + + sha256_fingerprint + The SHA256 fingerprint of the certificate + text + trust Whether 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 issuer text + + 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. copy name trust - certificate comment @@ -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