Blame SOURCES/1014-combine-secret-key-and-machine-rh1642023.patch

f86c11
From 861d9f8e1593c573bb04572b1f89f83500df85df Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 07:23:51 +0100
f86c11
Subject: [PATCH 01/10] shared: add nm_utils_error_is_notfound() helper
f86c11
f86c11
Inspired by bolt's bolt_err_notfound() in "bolt-error.c".
f86c11
f86c11
(cherry picked from commit b7fc328a66dd66f3f9d9f702e8b4a6d505ea3560)
f86c11
(cherry picked from commit d0f516a2bda68b22c456ef945e1c1fe8e36986ba)
f86c11
---
f86c11
 shared/nm-utils/nm-shared-utils.c | 23 ++++++++++++++++++-----
f86c11
 shared/nm-utils/nm-shared-utils.h |  2 ++
f86c11
 2 files changed, 20 insertions(+), 5 deletions(-)
f86c11
f86c11
diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c
f86c11
index 022c06528..0d4696cda 100644
f86c11
--- a/shared/nm-utils/nm-shared-utils.c
f86c11
+++ b/shared/nm-utils/nm-shared-utils.c
f86c11
@@ -1037,11 +1037,24 @@ nm_utils_error_is_cancelled (GError *error,
f86c11
                              gboolean consider_is_disposing)
f86c11
 {
f86c11
 	if (error) {
f86c11
-		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
f86c11
-			return TRUE;
f86c11
-		if (   consider_is_disposing
f86c11
-		    && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING))
f86c11
-			return TRUE;
f86c11
+		if (error->domain == G_IO_ERROR)
f86c11
+			return NM_IN_SET (error->code, G_IO_ERROR_CANCELLED);
f86c11
+		if (consider_is_disposing) {
f86c11
+			if (error->domain == NM_UTILS_ERROR)
f86c11
+				return NM_IN_SET (error->code, NM_UTILS_ERROR_CANCELLED_DISPOSING);
f86c11
+		}
f86c11
+	}
f86c11
+	return FALSE;
f86c11
+}
f86c11
+
f86c11
+gboolean
f86c11
+nm_utils_error_is_notfound (GError *error)
f86c11
+{
f86c11
+	if (error) {
f86c11
+		if (error->domain == G_IO_ERROR)
f86c11
+			return NM_IN_SET (error->code, G_IO_ERROR_NOT_FOUND);
f86c11
+		if (error->domain == G_FILE_ERROR)
f86c11
+			return NM_IN_SET (error->code, G_FILE_ERROR_NOENT);
f86c11
 	}
f86c11
 	return FALSE;
f86c11
 }
f86c11
diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
f86c11
index f1ff71e3b..20311d08a 100644
f86c11
--- a/shared/nm-utils/nm-shared-utils.h
f86c11
+++ b/shared/nm-utils/nm-shared-utils.h
f86c11
@@ -586,6 +586,8 @@ void nm_utils_error_set_cancelled (GError **error,
f86c11
 gboolean nm_utils_error_is_cancelled (GError *error,
f86c11
                                       gboolean consider_is_disposing);
f86c11
 
f86c11
+gboolean nm_utils_error_is_notfound (GError *error);
f86c11
+
f86c11
 static inline void
f86c11
 nm_utils_error_set_literal (GError **error, int error_code, const char *literal)
f86c11
 {
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From cbc815117511279cbd976658313f59c43debf97a Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 07:29:38 +0100
f86c11
Subject: [PATCH 02/10] core: fix printing error for failure reading secret-key
f86c11
f86c11
g_file_get_contents() fails with G_FILE_ERROR, G_FILE_ERROR_NOENT when the
f86c11
file does not exist.
f86c11
f86c11
That wasn't obvious to me, nm_utils_error_is_notfound() to the rescue.
f86c11
f86c11
Fixes: dbcb1d6d97c609d53dac4a86dc45d0e2595d8857
f86c11
(cherry picked from commit 7b9cd2e3d7206cc895fc2e27df3b7bd987da6ef5)
f86c11
(cherry picked from commit cfc0c6d5146513fba856894506542facde9fc914)
f86c11
---
f86c11
 src/nm-core-utils.c | 2 +-
f86c11
 1 file changed, 1 insertion(+), 1 deletion(-)
f86c11
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index f0efee461..44f0549e6 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2735,7 +2735,7 @@ _secret_key_read (guint8 **out_secret_key,
f86c11
 		nm_log_warn (LOGD_CORE, "secret-key: too short secret key in \"%s\" (generate new key)", NMSTATEDIR "/secret_key");
f86c11
 		nm_clear_g_free (&secret_key);
f86c11
 	} else {
f86c11
-		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
f86c11
+		if (!nm_utils_error_is_notfound (error)) {
f86c11
 			nm_log_warn (LOGD_CORE, "secret-key: failure reading secret key in \"%s\": %s (generate new key)",
f86c11
 			             NMSTATEDIR "/secret_key", error->message);
f86c11
 		}
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From 3484e98ce766858a2cb9c33b91e955140b93e54a Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 07:34:34 +0100
f86c11
Subject: [PATCH 03/10] core: use define for secret_key filename
f86c11
f86c11
(cherry picked from commit 2c7c333297a57d55efb2bd5a447391ea77861423)
f86c11
(cherry picked from commit 0b451b4c879c3c8178b235a5d9b2b669f4696f81)
f86c11
---
f86c11
 src/nm-core-utils.c | 14 ++++++++------
f86c11
 1 file changed, 8 insertions(+), 6 deletions(-)
f86c11
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index 44f0549e6..ab433b292 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2716,6 +2716,8 @@ nm_utils_machine_id_is_fake (void)
f86c11
 
f86c11
 /*****************************************************************************/
f86c11
 
f86c11
+#define SECRET_KEY_FILE      NMSTATEDIR"/secret_key"
f86c11
+
f86c11
 static gboolean
f86c11
 _secret_key_read (guint8 **out_secret_key,
f86c11
                   gsize *out_key_len)
f86c11
@@ -2726,18 +2728,18 @@ _secret_key_read (guint8 **out_secret_key,
f86c11
 	gs_free_error GError *error = NULL;
f86c11
 
f86c11
 	/* Let's try to load a saved secret key first. */
f86c11
-	if (g_file_get_contents (NMSTATEDIR "/secret_key", (char **) &secret_key, &key_len, &error)) {
f86c11
+	if (g_file_get_contents (SECRET_KEY_FILE, (char **) &secret_key, &key_len, &error)) {
f86c11
 		if (key_len >= 16)
f86c11
 			goto out;
f86c11
 
f86c11
 		/* the secret key is borked. Log a warning, but proceed below to generate
f86c11
 		 * a new one. */
f86c11
-		nm_log_warn (LOGD_CORE, "secret-key: too short secret key in \"%s\" (generate new key)", NMSTATEDIR "/secret_key");
f86c11
+		nm_log_warn (LOGD_CORE, "secret-key: too short secret key in \"%s\" (generate new key)", SECRET_KEY_FILE);
f86c11
 		nm_clear_g_free (&secret_key);
f86c11
 	} else {
f86c11
 		if (!nm_utils_error_is_notfound (error)) {
f86c11
 			nm_log_warn (LOGD_CORE, "secret-key: failure reading secret key in \"%s\": %s (generate new key)",
f86c11
-			             NMSTATEDIR "/secret_key", error->message);
f86c11
+			             SECRET_KEY_FILE, error->message);
f86c11
 		}
f86c11
 		g_clear_error (&error);
f86c11
 	}
f86c11
@@ -2763,9 +2765,9 @@ _secret_key_read (guint8 **out_secret_key,
f86c11
 		goto out;
f86c11
 	}
f86c11
 
f86c11
-	if (!nm_utils_file_set_contents (NMSTATEDIR "/secret_key", (char *) secret_key, key_len, 0077, &error)) {
f86c11
+	if (!nm_utils_file_set_contents (SECRET_KEY_FILE, (char *) secret_key, key_len, 0077, &error)) {
f86c11
 		nm_log_warn (LOGD_CORE, "secret-key: failure to persist secret key in \"%s\" (%s) (use non-persistent key)",
f86c11
-		             NMSTATEDIR "/secret_key", error->message);
f86c11
+		             SECRET_KEY_FILE, error->message);
f86c11
 		success = FALSE;
f86c11
 		goto out;
f86c11
 	}
f86c11
@@ -2827,7 +2829,7 @@ nm_utils_secret_key_get_timestamp (void)
f86c11
 	if (!nm_utils_secret_key_get (&key, &key_len))
f86c11
 		return 0;
f86c11
 
f86c11
-	if (stat (NMSTATEDIR "/secret_key", &stat_buf) != 0)
f86c11
+	if (stat (SECRET_KEY_FILE, &stat_buf) != 0)
f86c11
 		return 0;
f86c11
 
f86c11
 	return stat_buf.st_mtim.tv_sec;
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From 4ac908e32ac7c79a2ff7781e702d5d0f688bbcb3 Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 5 Dec 2018 13:42:33 +0100
f86c11
Subject: [PATCH 04/10] core: combine secret-key with /etc/machine-id
f86c11
f86c11
NetworkManager loads (and generates) a secret key as
f86c11
"/var/lib/NetworkManager/secret_key".
f86c11
f86c11
The secret key is used for seeding a per-host component when generating
f86c11
hashed, stable data. For example, it contributes to "ipv4.dhcp-client-id=duid"
f86c11
"ipv6.addr-gen-mode=stable-privacy", "ethernet.cloned-mac-address=stable", etc.
f86c11
As such, it corresponds to the identity of the host.
f86c11
f86c11
Also "/etc/machine-id" is the host's identity. When cloning a virtual machine,
f86c11
it may be a good idea to generate a new "/etc/machine-id", at least in those
f86c11
cases where the VM's identity shall be different. Systemd provides various
f86c11
mechanisms for doing that, like accepting a new machine-id via kernel command line.
f86c11
For the same reason, the user should also regenerate a new NetworkManager's
f86c11
secrey key when the host's identity shall change. However, that is less obvious,
f86c11
less understood and less documented.
f86c11
f86c11
Support and use a new variant of secret key. This secret key is combined
f86c11
with "/etc/machine-id" by sha256 hashing it together. That means, when the
f86c11
user generates a new machine-id, NetworkManager's per-host key also changes.
f86c11
f86c11
Since we don't want to change behavior for existing installations, we
f86c11
only do this when generating a new secret key file. For that, we encode
f86c11
a version tag inside the "/var/lib/NetworkManager/secret_key" file.
f86c11
f86c11
Note that this is all abstracted by nm_utils_secret_key_get(). For
f86c11
version 2 secret-keys, it internally combines the secret_key file with
f86c11
machine-id (via sha256). The advantage is that callers don't care that
f86c11
the secret-key now also contains the machine-id. Also, since we want to
f86c11
stick to the previous behavior if we have an old secret-key, this is
f86c11
nicely abstracted. Otherwise, the caller would not only need to handle
f86c11
two per-host parts, but it would also need to check the version to
f86c11
determine whether the machine-id should be explicitly included.
f86c11
At this point, nm_utils_secret_key_get() should be renamed to
f86c11
nm_utils_host_key_get().
f86c11
f86c11
(cherry picked from commit deb19abf22eca93bdb57f52d162b5d81f1a85fc1)
f86c11
(cherry picked from commit 7b68a574e9b4e242062db50ca36a8e77822cd646)
f86c11
---
f86c11
 src/nm-core-utils.c | 185 +++++++++++++++++++++++++++++++++-----------
f86c11
 1 file changed, 138 insertions(+), 47 deletions(-)
f86c11
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index ab433b292..a379e405f 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -41,6 +41,7 @@
f86c11
 #include "nm-utils/nm-random-utils.h"
f86c11
 #include "nm-utils/nm-io-utils.h"
f86c11
 #include "nm-utils/unaligned.h"
f86c11
+#include "nm-utils/nm-secret-utils.h"
f86c11
 #include "nm-utils.h"
f86c11
 #include "nm-core-internal.h"
f86c11
 #include "nm-setting-connection.h"
f86c11
@@ -2608,7 +2609,7 @@ _uuid_data_init (UuidData *uuid_data,
f86c11
 /*****************************************************************************/
f86c11
 
f86c11
 static const UuidData *
f86c11
-_machine_id_get (void)
f86c11
+_machine_id_get (gboolean allow_fake)
f86c11
 {
f86c11
 	static const UuidData *volatile p_uuid_data;
f86c11
 	const UuidData *d;
f86c11
@@ -2650,6 +2651,12 @@ again:
f86c11
 			const char *hash_seed;
f86c11
 			gsize seed_len;
f86c11
 
f86c11
+			if (!allow_fake) {
f86c11
+				/* we don't allow generating (and memoizing) a fake key.
f86c11
+				 * Signal that no valid machine-id exists. */
f86c11
+				return NULL;
f86c11
+			}
f86c11
+
f86c11
 			if (nm_utils_secret_key_get (&seed_bin, &seed_len)) {
f86c11
 				/* we have no valid machine-id. Generate a fake one by hashing
f86c11
 				 * the secret-key. This key is commonly persisted, so it should be
f86c11
@@ -2699,84 +2706,168 @@ again:
f86c11
 const char *
f86c11
 nm_utils_machine_id_str (void)
f86c11
 {
f86c11
-	return _machine_id_get ()->str;
f86c11
+	return _machine_id_get (TRUE)->str;
f86c11
 }
f86c11
 
f86c11
 const NMUuid *
f86c11
 nm_utils_machine_id_bin (void)
f86c11
 {
f86c11
-	return &_machine_id_get ()->bin;
f86c11
+	return &_machine_id_get (TRUE)->bin;
f86c11
 }
f86c11
 
f86c11
 gboolean
f86c11
 nm_utils_machine_id_is_fake (void)
f86c11
 {
f86c11
-	return _machine_id_get ()->is_fake;
f86c11
+	return _machine_id_get (TRUE)->is_fake;
f86c11
 }
f86c11
 
f86c11
 /*****************************************************************************/
f86c11
 
f86c11
+/* prefix for version2 secret key. The secret key is hashed with /etc/machine-id. */
f86c11
+#define SECRET_KEY_V2_PREFIX "nm-v2:"
f86c11
 #define SECRET_KEY_FILE      NMSTATEDIR"/secret_key"
f86c11
 
f86c11
-static gboolean
f86c11
-_secret_key_read (guint8 **out_secret_key,
f86c11
-                  gsize *out_key_len)
f86c11
+static const guint8 *
f86c11
+_secret_key_hash_v2 (const guint8 *seed_arr,
f86c11
+                     gsize seed_len,
f86c11
+                     guint8 *out_digest /* 32 bytes (NM_UTILS_CHECKSUM_LENGTH_SHA256) */)
f86c11
 {
f86c11
-	guint8 *secret_key;
f86c11
-	gboolean success = TRUE;
f86c11
-	gsize key_len;
f86c11
-	gs_free_error GError *error = NULL;
f86c11
+	nm_auto_free_checksum GChecksum *sum = g_checksum_new (G_CHECKSUM_SHA256);
f86c11
+	const UuidData *machine_id_data;
f86c11
+	char slen[100];
f86c11
 
f86c11
-	/* Let's try to load a saved secret key first. */
f86c11
-	if (g_file_get_contents (SECRET_KEY_FILE, (char **) &secret_key, &key_len, &error)) {
f86c11
-		if (key_len >= 16)
f86c11
-			goto out;
f86c11
+	/*
f86c11
+	    (stat -c '%s' /var/lib/NetworkManager/secret_key;
f86c11
+	     echo -n ' ';
f86c11
+	     cat /var/lib/NetworkManager/secret_key;
f86c11
+	     cat /etc/machine-id | tr -d '\n' | sed -n 's/[a-f0-9-]/\0/pg') | sha256sum
f86c11
+	*/
f86c11
 
f86c11
-		/* the secret key is borked. Log a warning, but proceed below to generate
f86c11
-		 * a new one. */
f86c11
-		nm_log_warn (LOGD_CORE, "secret-key: too short secret key in \"%s\" (generate new key)", SECRET_KEY_FILE);
f86c11
-		nm_clear_g_free (&secret_key);
f86c11
-	} else {
f86c11
+	nm_sprintf_buf (slen, "%"G_GSIZE_FORMAT" ", seed_len);
f86c11
+	g_checksum_update (sum, (const guchar *) slen, strlen (slen));
f86c11
+
f86c11
+	g_checksum_update (sum, (const guchar *) seed_arr, seed_len);
f86c11
+
f86c11
+	machine_id_data = _machine_id_get (FALSE);
f86c11
+	if (   machine_id_data
f86c11
+	    && !machine_id_data->is_fake)
f86c11
+		g_checksum_update (sum, (const guchar *) machine_id_data->str, strlen (machine_id_data->str));
f86c11
+
f86c11
+	nm_utils_checksum_get_digest_len (sum, out_digest, NM_UTILS_CHECKSUM_LENGTH_SHA256);
f86c11
+	return out_digest;
f86c11
+}
f86c11
+
f86c11
+static gboolean
f86c11
+_secret_key_read (guint8 **out_key,
f86c11
+                  gsize *out_key_len)
f86c11
+{
f86c11
+#define SECRET_KEY_LEN 32u
f86c11
+	guint8 sha256_digest[NM_UTILS_CHECKSUM_LENGTH_SHA256];
f86c11
+	nm_auto_clear_secret_ptr NMSecretPtr file_content = { 0 };
f86c11
+	const guint8 *secret_arr;
f86c11
+	gsize secret_len;
f86c11
+	GError *error = NULL;
f86c11
+	gboolean success;
f86c11
+
f86c11
+	if (nm_utils_file_get_contents (-1,
f86c11
+	                                SECRET_KEY_FILE,
f86c11
+	                                10*1024,
f86c11
+	                                NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET,
f86c11
+	                                (char **) &file_content.str,
f86c11
+	                                &file_content.len,
f86c11
+	                                &error) < 0) {
f86c11
 		if (!nm_utils_error_is_notfound (error)) {
f86c11
 			nm_log_warn (LOGD_CORE, "secret-key: failure reading secret key in \"%s\": %s (generate new key)",
f86c11
 			             SECRET_KEY_FILE, error->message);
f86c11
 		}
f86c11
 		g_clear_error (&error);
f86c11
-	}
f86c11
-
f86c11
-	/* RFC7217 mandates the key SHOULD be at least 128 bits.
f86c11
-	 * Let's use twice as much. */
f86c11
-	key_len = 32;
f86c11
-	secret_key = g_malloc (key_len + 1);
f86c11
-
f86c11
-	/* the secret-key is binary. Still, ensure that it's NULL terminated, just like
f86c11
-	 * g_file_set_contents() does. */
f86c11
-	secret_key[32] = '\0';
f86c11
+	} else if (   file_content.len >= NM_STRLEN (SECRET_KEY_V2_PREFIX) + SECRET_KEY_LEN
f86c11
+	           && memcmp (file_content.bin, SECRET_KEY_V2_PREFIX, NM_STRLEN (SECRET_KEY_V2_PREFIX)) == 0) {
f86c11
+		/* for this type of secret key, we require a prefix followed at least SECRET_KEY_LEN (32) bytes. We
f86c11
+		 * (also) do that, because older versions of NetworkManager wrote exactly 32 bytes without
f86c11
+		 * prefix, so we won't wrongly interpret such legacy keys as v2 (if they accidentally have
f86c11
+		 * a SECRET_KEY_V2_PREFIX prefix, they'll still have the wrong size).
f86c11
+		 *
f86c11
+		 * Note that below we generate the random seed in base64 encoding. But that is only done
f86c11
+		 * to write an ASCII file. There is no base64 decoding and the ASCII is hashed as-is.
f86c11
+		 * We would accept any binary data just as well (provided a suitable prefix and at least
f86c11
+		 * 32 bytes).
f86c11
+		 *
f86c11
+		 * Note that when hashing the v2 content, we also hash the prefix. There is no strong reason,
f86c11
+		 * except that it seems simpler not to distinguish between the v2 prefix and the content.
f86c11
+		 * It's all just part of the seed. */
f86c11
 
f86c11
-	if (!nm_utils_random_bytes (secret_key, key_len)) {
f86c11
-		nm_log_warn (LOGD_CORE, "secret-key: failure to generate good random data for secret-key (use non-persistent key)");
f86c11
-		success = FALSE;
f86c11
+		secret_arr = _secret_key_hash_v2 (file_content.bin, file_content.len, sha256_digest);
f86c11
+		secret_len = NM_UTILS_CHECKSUM_LENGTH_SHA256;
f86c11
+		success = TRUE;
f86c11
 		goto out;
f86c11
-	}
f86c11
-
f86c11
-	if (nm_utils_get_testing ()) {
f86c11
-		/* for test code, we don't write the generated secret-key to disk. */
f86c11
-		success = FALSE;
f86c11
+	} else if (file_content.len >= 16) {
f86c11
+		secret_arr = file_content.bin;
f86c11
+		secret_len = file_content.len;
f86c11
+		success = TRUE;
f86c11
 		goto out;
f86c11
+	} else {
f86c11
+		/* the secret key is borked. Log a warning, but proceed below to generate
f86c11
+		 * a new one. */
f86c11
+		nm_log_warn (LOGD_CORE, "secret-key: too short secret key in \"%s\" (generate new key)", SECRET_KEY_FILE);
f86c11
 	}
f86c11
 
f86c11
-	if (!nm_utils_file_set_contents (SECRET_KEY_FILE, (char *) secret_key, key_len, 0077, &error)) {
f86c11
-		nm_log_warn (LOGD_CORE, "secret-key: failure to persist secret key in \"%s\" (%s) (use non-persistent key)",
f86c11
-		             SECRET_KEY_FILE, error->message);
f86c11
-		success = FALSE;
f86c11
-		goto out;
f86c11
+	/* generate and persist new key */
f86c11
+	{
f86c11
+#define SECRET_KEY_LEN_BASE64 ((((SECRET_KEY_LEN / 3) + 1) * 4) + 4)
f86c11
+		guint8 rnd_buf[SECRET_KEY_LEN];
f86c11
+		guint8 new_content[NM_STRLEN (SECRET_KEY_V2_PREFIX) + SECRET_KEY_LEN_BASE64];
f86c11
+		int base64_state = 0;
f86c11
+		int base64_save = 0;
f86c11
+		gsize len;
f86c11
+
f86c11
+		success = nm_utils_random_bytes (rnd_buf, sizeof (rnd_buf));
f86c11
+
f86c11
+		/* Our key is really binary data. But since we anyway generate a random seed
f86c11
+		 * (with 32 random bytes), don't write it in binary, but instead create
f86c11
+		 * an pure ASCII (base64) representation. Note that the ASCII will still be taken
f86c11
+		 * as-is (no base64 decoding is done). The sole purpose is to write a ASCII file
f86c11
+		 * instead of a binary. The content is gibberish either way. */
f86c11
+		memcpy (new_content, SECRET_KEY_V2_PREFIX, NM_STRLEN (SECRET_KEY_V2_PREFIX));
f86c11
+		len = NM_STRLEN (SECRET_KEY_V2_PREFIX);
f86c11
+		len += g_base64_encode_step (rnd_buf,
f86c11
+		                             sizeof (rnd_buf),
f86c11
+		                             FALSE,
f86c11
+		                             (char *) &new_content[len],
f86c11
+		                             &base64_state,
f86c11
+		                             &base64_save);
f86c11
+		len += g_base64_encode_close (FALSE,
f86c11
+		                              (char *) &new_content[len],
f86c11
+		                              &base64_state,
f86c11
+		                              &base64_save);
f86c11
+		nm_assert (len <= sizeof (new_content));
f86c11
+
f86c11
+		secret_arr = _secret_key_hash_v2 (new_content, len, sha256_digest);
f86c11
+		secret_len = NM_UTILS_CHECKSUM_LENGTH_SHA256;
f86c11
+
f86c11
+		if (!success)
f86c11
+			nm_log_warn (LOGD_CORE, "secret-key: failure to generate good random data for secret-key (use non-persistent key)");
f86c11
+		else if (nm_utils_get_testing ()) {
f86c11
+			/* for test code, we don't write the generated secret-key to disk. */
f86c11
+		} else if (!nm_utils_file_set_contents (SECRET_KEY_FILE,
f86c11
+		                                        (const char *) new_content,
f86c11
+		                                        len,
f86c11
+		                                        0077,
f86c11
+		                                        &error)) {
f86c11
+			nm_log_warn (LOGD_CORE, "secret-key: failure to persist secret key in \"%s\" (%s) (use non-persistent key)",
f86c11
+			             SECRET_KEY_FILE, error->message);
f86c11
+			g_clear_error (&error);
f86c11
+			success = FALSE;
f86c11
+		} else
f86c11
+			nm_log_dbg (LOGD_CORE, "secret-key: persist new secret key to \"%s\"", SECRET_KEY_FILE);
f86c11
+
f86c11
+		nm_explicit_bzero (rnd_buf, sizeof (rnd_buf));
f86c11
+		nm_explicit_bzero (new_content, sizeof (new_content));
f86c11
 	}
f86c11
 
f86c11
 out:
f86c11
-	/* regardless of success or failue, we always return a secret-key. The
f86c11
-	 * caller may choose to ignore the error and proceed. */
f86c11
-	*out_key_len = key_len;
f86c11
-	*out_secret_key = secret_key;
f86c11
+	*out_key_len = secret_len;
f86c11
+	*out_key = nm_memdup (secret_arr, secret_len);
f86c11
 	return success;
f86c11
 }
f86c11
 
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From adf0a12121b5adb9a47f9ca2e84a29597115c5a7 Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Tue, 11 Dec 2018 18:18:17 +0100
f86c11
Subject: [PATCH 05/10] core: fix race creating secret-key
f86c11
f86c11
Reading the secret key may result in generating and
f86c11
writing a new key to disk.
f86c11
f86c11
Do that under the lock.
f86c11
f86c11
(cherry picked from commit bc9f18c609b7aac84110b37ec280cb012364ecf4)
f86c11
(cherry picked from commit db535b693afc25f9d42cbd9178b624b67f080297)
f86c11
---
f86c11
 src/nm-core-utils.c | 13 ++++---------
f86c11
 1 file changed, 4 insertions(+), 9 deletions(-)
f86c11
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index a379e405f..c3d2e3c2a 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2872,7 +2872,7 @@ out:
f86c11
 }
f86c11
 
f86c11
 typedef struct {
f86c11
-	const guint8 *secret_key;
f86c11
+	guint8 *secret_key;
f86c11
 	gsize key_len;
f86c11
 	bool is_good:1;
f86c11
 } SecretKeyData;
f86c11
@@ -2887,19 +2887,14 @@ nm_utils_secret_key_get (const guint8 **out_secret_key,
f86c11
 again:
f86c11
 	secret_key = g_atomic_pointer_get (&secret_key_static);
f86c11
 	if (G_UNLIKELY (!secret_key)) {
f86c11
-		static gsize init_value = 0;
f86c11
 		static SecretKeyData secret_key_data;
f86c11
-		gboolean tmp_success;
f86c11
-		gs_free guint8 *tmp_secret_key = NULL;
f86c11
-		gsize tmp_key_len;
f86c11
+		static gsize init_value = 0;
f86c11
 
f86c11
-		tmp_success = _secret_key_read (&tmp_secret_key, &tmp_key_len);
f86c11
 		if (!g_once_init_enter (&init_value))
f86c11
 			goto again;
f86c11
 
f86c11
-		secret_key_data.secret_key = g_steal_pointer (&tmp_secret_key);
f86c11
-		secret_key_data.key_len = tmp_key_len;
f86c11
-		secret_key_data.is_good = tmp_success;
f86c11
+		secret_key_data.is_good = _secret_key_read (&secret_key_data.secret_key,
f86c11
+		                                            &secret_key_data.key_len);
f86c11
 		secret_key = &secret_key_data;
f86c11
 		g_atomic_pointer_set (&secret_key_static, secret_key);
f86c11
 		g_once_init_leave (&init_value, 1);
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From e8a3a7e25472c74d66790fab14bded799631006b Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 12:11:53 +0100
f86c11
Subject: [PATCH 06/10] shared: expose siphash24() related functionality in
f86c11
 nm-hash-utils.h
f86c11
f86c11
CSiphash is a first class citizen, it's fine to use everwhere where we
f86c11
need it.
f86c11
f86c11
NMHash wraps CSiphash and provides three things:
f86c11
f86c11
1) Convenience macros that make hashing nicer to use.
f86c11
f86c11
2) it uses a randomly generated, per-run hash seed, that can be combined
f86c11
   with a guint static seed.
f86c11
f86c11
3) it's a general API for hashing data. It nowhere promises that it
f86c11
   actually uses siphash24, although currently it does everywhere.
f86c11
   NMHash is not (officially) siphash24.
f86c11
f86c11
Add API nm_hash_siphash42_init() and nm_hash_siphash42() to "nm-hash-utils.h",
f86c11
that exposes (2) for use with regular CSiphash. You of course no longer
f86c11
get the convenice macros (1) but you get plain siphash24 (which
f86c11
NMHash does not give (3)).
f86c11
f86c11
While at it, also add a nm_hash_complete_u64(). Usually, for hasing we
f86c11
want guint types. But we don't need to hide the fact, that the
f86c11
underlying value is first uint64. Expose it.
f86c11
f86c11
(cherry picked from commit db791db4e1ff7a850b4ac49d24d159e2ccbe005c)
f86c11
(cherry picked from commit 0a4bbb18fe9fb80acf038177ae581b7aef2c7883)
f86c11
---
f86c11
 shared/nm-utils/nm-hash-utils.c |  6 ++--
f86c11
 shared/nm-utils/nm-hash-utils.h | 62 +++++++++++++++++++++++++++++----
f86c11
 2 files changed, 59 insertions(+), 9 deletions(-)
f86c11
f86c11
diff --git a/shared/nm-utils/nm-hash-utils.c b/shared/nm-utils/nm-hash-utils.c
f86c11
index 9f164a119..80387c714 100644
f86c11
--- a/shared/nm-utils/nm-hash-utils.c
f86c11
+++ b/shared/nm-utils/nm-hash-utils.c
f86c11
@@ -122,17 +122,17 @@ nm_hash_static (guint static_seed)
f86c11
 }
f86c11
 
f86c11
 void
f86c11
-nm_hash_init (NMHashState *state, guint static_seed)
f86c11
+nm_hash_siphash42_init (CSipHash *h, guint static_seed)
f86c11
 {
f86c11
 	const guint8 *g;
f86c11
 	guint seed[HASH_KEY_SIZE_GUINT];
f86c11
 
f86c11
-	nm_assert (state);
f86c11
+	nm_assert (h);
f86c11
 
f86c11
 	g = _get_hash_key ();
f86c11
 	memcpy (seed, g, HASH_KEY_SIZE);
f86c11
 	seed[0] ^= static_seed;
f86c11
-	c_siphash_init (&state->_state, (const guint8 *) seed);
f86c11
+	c_siphash_init (h, (const guint8 *) seed);
f86c11
 }
f86c11
 
f86c11
 guint
f86c11
diff --git a/shared/nm-utils/nm-hash-utils.h b/shared/nm-utils/nm-hash-utils.h
f86c11
index b797fb75a..cf71a7e9f 100644
f86c11
--- a/shared/nm-utils/nm-hash-utils.h
f86c11
+++ b/shared/nm-utils/nm-hash-utils.h
f86c11
@@ -25,6 +25,39 @@
f86c11
 #include "c-siphash/src/c-siphash.h"
f86c11
 #include "nm-macros-internal.h"
f86c11
 
f86c11
+/*****************************************************************************/
f86c11
+
f86c11
+void nm_hash_siphash42_init (CSipHash *h, guint static_seed);
f86c11
+
f86c11
+/* Siphash24 of binary buffer @arr and @len, using the randomized seed from
f86c11
+ * other NMHash functions.
f86c11
+ *
f86c11
+ * Note, that this is guaranteed to use siphash42 under the hood (contrary to
f86c11
+ * all other NMHash API, which leave this undefined). That matters at the point,
f86c11
+ * where the caller needs to be sure that a reasonably strong hasing algorithm
f86c11
+ * is used.  (Yes, NMHash is all about siphash24, but otherwise that is not promised
f86c11
+ * anywhere).
f86c11
+ *
f86c11
+ * Another difference is, that this returns guint64 (not guint like other NMHash functions).
f86c11
+ *
f86c11
+ * Another difference is, that this may also return zero (not like nm_hash_complete()).
f86c11
+ *
f86c11
+ * Then, why not use c_siphash_hash() directly? Because this also uses the randomized,
f86c11
+ * per-run hash-seed like nm_hash_init(). So, you get siphash24 with a random
f86c11
+ * seed (which is cached for the current run of the program).
f86c11
+ */
f86c11
+static inline guint64
f86c11
+nm_hash_siphash42 (guint static_seed, const void *ptr, gsize n)
f86c11
+{
f86c11
+	CSipHash h;
f86c11
+
f86c11
+	nm_hash_siphash42_init (&h, static_seed);
f86c11
+	c_siphash_append (&h, ptr, n);
f86c11
+	return c_siphash_finalize (&h);
f86c11
+}
f86c11
+
f86c11
+/*****************************************************************************/
f86c11
+
f86c11
 struct _NMHashState {
f86c11
 	CSipHash _state;
f86c11
 };
f86c11
@@ -33,16 +66,33 @@ typedef struct _NMHashState NMHashState;
f86c11
 
f86c11
 guint nm_hash_static (guint static_seed);
f86c11
 
f86c11
-void nm_hash_init (NMHashState *state, guint static_seed);
f86c11
+static inline void
f86c11
+nm_hash_init (NMHashState *state, guint static_seed)
f86c11
+{
f86c11
+	nm_assert (state);
f86c11
+
f86c11
+	nm_hash_siphash42_init (&state->_state, static_seed);
f86c11
+}
f86c11
+
f86c11
+static inline guint64
f86c11
+nm_hash_complete_u64 (NMHashState *state)
f86c11
+{
f86c11
+	nm_assert (state);
f86c11
+
f86c11
+	/* this returns the native u64 hash value. Note that this differs
f86c11
+	 * from nm_hash_complete() in two ways:
f86c11
+	 *
f86c11
+	 * - the type, guint64 vs. guint.
f86c11
+	 * - nm_hash_complete() never returns zero. */
f86c11
+	return c_siphash_finalize (&state->_state);
f86c11
+}
f86c11
 
f86c11
 static inline guint
f86c11
 nm_hash_complete (NMHashState *state)
f86c11
 {
f86c11
 	guint64 h;
f86c11
 
f86c11
-	nm_assert (state);
f86c11
-
f86c11
-	h = c_siphash_finalize (&state->_state);
f86c11
+	h = nm_hash_complete_u64 (state);
f86c11
 
f86c11
 	/* we don't ever want to return a zero hash.
f86c11
 	 *
f86c11
@@ -218,8 +268,8 @@ guint nm_str_hash (gconstpointer str);
f86c11
 	({ \
f86c11
 		NMHashState _h; \
f86c11
 		\
f86c11
-		nm_hash_init (&_h, static_seed); \
f86c11
-		nm_hash_update_val (&_h, val); \
f86c11
+		nm_hash_init (&_h, (static_seed)); \
f86c11
+		nm_hash_update_val (&_h, (val)); \
f86c11
 		nm_hash_complete (&_h); \
f86c11
 	})
f86c11
 
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From 604bf0c568f821f50bc19aac91a6db15d31c2a29 Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 10:10:38 +0100
f86c11
Subject: [PATCH 07/10] core/trivial: rename secret-key to host-key
f86c11
f86c11
Now that the secret-key is hashed with the machine-id, the name is
f86c11
no longer best.
f86c11
f86c11
Sure, part of the key are persisted in /var/lib/NetworkManager/secret_key
f86c11
file, which the user is well advised to keep secret.
f86c11
f86c11
But what nm_utils_secret_key_get() returns is first and foremost a binary
f86c11
key that is per-host and used for hashing a per-host component. It's
f86c11
really the "host-id". Compare that to what we also have, the
f86c11
"machine-id" and the "boot-id".
f86c11
f86c11
Rename.
f86c11
f86c11
(cherry picked from commit 6ffcd263177d01a528a89709609f06550ecded9b)
f86c11
(cherry picked from commit cdb7f6f6d2927aac501efba22557778301834d0e)
f86c11
---
f86c11
 src/devices/nm-device.c |  24 ++++----
f86c11
 src/nm-core-utils.c     | 133 ++++++++++++++++++++++------------------
f86c11
 src/nm-core-utils.h     |  14 ++---
f86c11
 3 files changed, 93 insertions(+), 78 deletions(-)
f86c11
f86c11
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
f86c11
index 8d5866266..8821dfaa9 100644
f86c11
--- a/src/devices/nm-device.c
f86c11
+++ b/src/devices/nm-device.c
f86c11
@@ -7528,8 +7528,8 @@ dhcp4_get_client_id (NMDevice *self,
f86c11
 		NMUtilsStableType stable_type;
f86c11
 		const char *stable_id;
f86c11
 		guint32 salted_header;
f86c11
-		const guint8 *secret_key;
f86c11
-		gsize secret_key_len;
f86c11
+		const guint8 *host_id;
f86c11
+		gsize host_id_len;
f86c11
 
f86c11
 		stable_id = _get_stable_id (self, connection, &stable_type);
f86c11
 		if (!stable_id)
f86c11
@@ -7537,12 +7537,12 @@ dhcp4_get_client_id (NMDevice *self,
f86c11
 
f86c11
 		salted_header = htonl (2011610591 + stable_type);
f86c11
 
f86c11
-		nm_utils_secret_key_get (&secret_key, &secret_key_len);
f86c11
+		nm_utils_host_id_get (&host_id, &host_id_len);
f86c11
 
f86c11
 		sum = g_checksum_new (G_CHECKSUM_SHA1);
f86c11
 		g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header));
f86c11
 		g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1);
f86c11
-		g_checksum_update (sum, (const guchar *) secret_key, secret_key_len);
f86c11
+		g_checksum_update (sum, (const guchar *) host_id, host_id_len);
f86c11
 		nm_utils_checksum_get_digest (sum, digest);
f86c11
 
f86c11
 		client_id_buf = g_malloc (1 + 15);
f86c11
@@ -8317,7 +8317,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
f86c11
 		} else {
f86c11
 			gint64 time;
f86c11
 
f86c11
-			time = nm_utils_secret_key_get_timestamp ();
f86c11
+			time = nm_utils_host_id_get_timestamp ();
f86c11
 			if (!time) {
f86c11
 				duid_error = "cannot retrieve the secret key timestamp";
f86c11
 				goto out_fail;
f86c11
@@ -8334,8 +8334,8 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
f86c11
 		NMUtilsStableType stable_type;
f86c11
 		const char *stable_id = NULL;
f86c11
 		guint32 salted_header;
f86c11
-		const guint8 *secret_key;
f86c11
-		gsize secret_key_len;
f86c11
+		const guint8 *host_id;
f86c11
+		gsize host_id_len;
f86c11
 		union {
f86c11
 			guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256];
f86c11
 			guint8 hwaddr[ETH_ALEN];
f86c11
@@ -8352,12 +8352,12 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
f86c11
 
f86c11
 		salted_header = htonl (670531087 + stable_type);
f86c11
 
f86c11
-		nm_utils_secret_key_get (&secret_key, &secret_key_len);
f86c11
+		nm_utils_host_id_get (&host_id, &host_id_len);
f86c11
 
f86c11
 		sum = g_checksum_new (G_CHECKSUM_SHA256);
f86c11
 		g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header));
f86c11
 		g_checksum_update (sum, (const guchar *) stable_id, -1);
f86c11
-		g_checksum_update (sum, (const guchar *) secret_key, secret_key_len);
f86c11
+		g_checksum_update (sum, (const guchar *) host_id, host_id_len);
f86c11
 		nm_utils_checksum_get_digest (sum, digest.sha256);
f86c11
 
f86c11
 		G_STATIC_ASSERT_EXPR (sizeof (digest) == sizeof (digest.sha256));
f86c11
@@ -8369,11 +8369,11 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
f86c11
 
f86c11
 #define EPOCH_DATETIME_THREE_YEARS  (356 * 24 * 3600 * 3)
f86c11
 
f86c11
-			/* We want a variable time between the secret_key timestamp and three years
f86c11
+			/* We want a variable time between the host_id timestamp and three years
f86c11
 			 * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll
f86c11
-			 * subtract it from the secret_key timestamp.
f86c11
+			 * subtract it from the host_id timestamp.
f86c11
 			 */
f86c11
-			time = nm_utils_secret_key_get_timestamp ();
f86c11
+			time = nm_utils_host_id_get_timestamp ();
f86c11
 			if (!time) {
f86c11
 				duid_error = "cannot retrieve the secret key timestamp";
f86c11
 				goto out_fail;
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index c3d2e3c2a..4ac68c2da 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2657,7 +2657,7 @@ again:
f86c11
 				return NULL;
f86c11
 			}
f86c11
 
f86c11
-			if (nm_utils_secret_key_get (&seed_bin, &seed_len)) {
f86c11
+			if (nm_utils_host_id_get (&seed_bin, &seed_len)) {
f86c11
 				/* we have no valid machine-id. Generate a fake one by hashing
f86c11
 				 * the secret-key. This key is commonly persisted, so it should be
f86c11
 				 * stable accross reboots (despite having a broken system without
f86c11
@@ -2728,9 +2728,9 @@ nm_utils_machine_id_is_fake (void)
f86c11
 #define SECRET_KEY_FILE      NMSTATEDIR"/secret_key"
f86c11
 
f86c11
 static const guint8 *
f86c11
-_secret_key_hash_v2 (const guint8 *seed_arr,
f86c11
-                     gsize seed_len,
f86c11
-                     guint8 *out_digest /* 32 bytes (NM_UTILS_CHECKSUM_LENGTH_SHA256) */)
f86c11
+_host_id_hash_v2 (const guint8 *seed_arr,
f86c11
+                  gsize seed_len,
f86c11
+                  guint8 *out_digest /* 32 bytes (NM_UTILS_CHECKSUM_LENGTH_SHA256) */)
f86c11
 {
f86c11
 	nm_auto_free_checksum GChecksum *sum = g_checksum_new (G_CHECKSUM_SHA256);
f86c11
 	const UuidData *machine_id_data;
f86c11
@@ -2758,8 +2758,8 @@ _secret_key_hash_v2 (const guint8 *seed_arr,
f86c11
 }
f86c11
 
f86c11
 static gboolean
f86c11
-_secret_key_read (guint8 **out_key,
f86c11
-                  gsize *out_key_len)
f86c11
+_host_id_read (guint8 **out_host_id,
f86c11
+               gsize *out_host_id_len)
f86c11
 {
f86c11
 #define SECRET_KEY_LEN 32u
f86c11
 	guint8 sha256_digest[NM_UTILS_CHECKSUM_LENGTH_SHA256];
f86c11
@@ -2797,7 +2797,7 @@ _secret_key_read (guint8 **out_key,
f86c11
 		 * except that it seems simpler not to distinguish between the v2 prefix and the content.
f86c11
 		 * It's all just part of the seed. */
f86c11
 
f86c11
-		secret_arr = _secret_key_hash_v2 (file_content.bin, file_content.len, sha256_digest);
f86c11
+		secret_arr = _host_id_hash_v2 (file_content.bin, file_content.len, sha256_digest);
f86c11
 		secret_len = NM_UTILS_CHECKSUM_LENGTH_SHA256;
f86c11
 		success = TRUE;
f86c11
 		goto out;
f86c11
@@ -2842,7 +2842,7 @@ _secret_key_read (guint8 **out_key,
f86c11
 		                              &base64_save);
f86c11
 		nm_assert (len <= sizeof (new_content));
f86c11
 
f86c11
-		secret_arr = _secret_key_hash_v2 (new_content, len, sha256_digest);
f86c11
+		secret_arr = _host_id_hash_v2 (new_content, len, sha256_digest);
f86c11
 		secret_len = NM_UTILS_CHECKSUM_LENGTH_SHA256;
f86c11
 
f86c11
 		if (!success)
f86c11
@@ -2866,53 +2866,68 @@ _secret_key_read (guint8 **out_key,
f86c11
 	}
f86c11
 
f86c11
 out:
f86c11
-	*out_key_len = secret_len;
f86c11
-	*out_key = nm_memdup (secret_arr, secret_len);
f86c11
+	*out_host_id_len = secret_len;
f86c11
+	*out_host_id = nm_memdup (secret_arr, secret_len);
f86c11
 	return success;
f86c11
 }
f86c11
 
f86c11
 typedef struct {
f86c11
-	guint8 *secret_key;
f86c11
-	gsize key_len;
f86c11
+	guint8 *host_id;
f86c11
+	gsize host_id_len;
f86c11
 	bool is_good:1;
f86c11
-} SecretKeyData;
f86c11
+} HostIdData;
f86c11
 
f86c11
+/**
f86c11
+ * nm_utils_host_id_get:
f86c11
+ * @out_host_id: (out) (transfer none): the binary host key
f86c11
+ * @out_host_id_len: the length of the host key.
f86c11
+ *
f86c11
+ * This returns a per-host key that depends on /var/lib/NetworkManage/secret_key
f86c11
+ * and (depending on the version) on /etc/machine-id. If /var/lib/NetworkManage/secret_key
f86c11
+ * does not exist, it will be generated and persisted for next boot.
f86c11
+ *
f86c11
+ * Returns: %TRUE, if the host key is "good". Note that this function
f86c11
+ *   will always succeed to return a host-key, and that this key
f86c11
+ *   won't change during the run of the program (no matter what).
f86c11
+ *   A %FALSE return possibly means, that the secret_key is not persisted
f86c11
+ *   to disk, and/or that it was generated with bad randomness.
f86c11
+ */
f86c11
 gboolean
f86c11
-nm_utils_secret_key_get (const guint8 **out_secret_key,
f86c11
-                         gsize *out_key_len)
f86c11
+nm_utils_host_id_get (const guint8 **out_host_id,
f86c11
+                      gsize *out_host_id_len)
f86c11
 {
f86c11
-	static const SecretKeyData *volatile secret_key_static;
f86c11
-	const SecretKeyData *secret_key;
f86c11
+	static const HostIdData *volatile host_id_static;
f86c11
+	const HostIdData *host_id;
f86c11
 
f86c11
 again:
f86c11
-	secret_key = g_atomic_pointer_get (&secret_key_static);
f86c11
-	if (G_UNLIKELY (!secret_key)) {
f86c11
-		static SecretKeyData secret_key_data;
f86c11
+	host_id = g_atomic_pointer_get (&host_id_static);
f86c11
+	if (G_UNLIKELY (!host_id)) {
f86c11
+		static HostIdData host_id_data;
f86c11
 		static gsize init_value = 0;
f86c11
 
f86c11
 		if (!g_once_init_enter (&init_value))
f86c11
 			goto again;
f86c11
 
f86c11
-		secret_key_data.is_good = _secret_key_read (&secret_key_data.secret_key,
f86c11
-		                                            &secret_key_data.key_len);
f86c11
-		secret_key = &secret_key_data;
f86c11
-		g_atomic_pointer_set (&secret_key_static, secret_key);
f86c11
+		host_id_data.is_good = _host_id_read (&host_id_data.host_id,
f86c11
+		                                      &host_id_data.host_id_len);
f86c11
+		host_id = &host_id_data;
f86c11
+		g_atomic_pointer_set (&host_id_static, host_id);
f86c11
 		g_once_init_leave (&init_value, 1);
f86c11
 	}
f86c11
 
f86c11
-	*out_secret_key = secret_key->secret_key;
f86c11
-	*out_key_len = secret_key->key_len;
f86c11
-	return secret_key->is_good;
f86c11
+	*out_host_id = host_id->host_id;
f86c11
+	*out_host_id_len = host_id->host_id_len;
f86c11
+	return host_id->is_good;
f86c11
 }
f86c11
 
f86c11
 gint64
f86c11
-nm_utils_secret_key_get_timestamp (void)
f86c11
+nm_utils_host_id_get_timestamp (void)
f86c11
 {
f86c11
 	struct stat stat_buf;
f86c11
-	const guint8 *key;
f86c11
-	gsize key_len;
f86c11
+	const guint8 *host_id;
f86c11
+	gsize host_id_len;
f86c11
 
f86c11
-	if (!nm_utils_secret_key_get (&key, &key_len))
f86c11
+	if (!nm_utils_host_id_get (&host_id, &host_id_len))
f86c11
 		return 0;
f86c11
 
f86c11
 	if (stat (SECRET_KEY_FILE, &stat_buf) != 0)
f86c11
@@ -3379,20 +3394,20 @@ _set_stable_privacy (NMUtilsStableType stable_type,
f86c11
                      const char *ifname,
f86c11
                      const char *network_id,
f86c11
                      guint32 dad_counter,
f86c11
-                     const guint8 *secret_key,
f86c11
-                     gsize key_len,
f86c11
+                     const guint8 *host_id,
f86c11
+                     gsize host_id_len,
f86c11
                      GError **error)
f86c11
 {
f86c11
 	nm_auto_free_checksum GChecksum *sum = NULL;
f86c11
 	guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA256];
f86c11
 	guint32 tmp[2];
f86c11
 
f86c11
-	nm_assert (key_len);
f86c11
+	nm_assert (host_id_len);
f86c11
 	nm_assert (network_id);
f86c11
 
f86c11
 	sum = g_checksum_new (G_CHECKSUM_SHA256);
f86c11
 
f86c11
-	key_len = MIN (key_len, G_MAXUINT32);
f86c11
+	host_id_len = MIN (host_id_len, G_MAXUINT32);
f86c11
 
f86c11
 	if (stable_type != NM_UTILS_STABLE_TYPE_UUID) {
f86c11
 		guint8 stable_type_uint8;
f86c11
@@ -3405,7 +3420,7 @@ _set_stable_privacy (NMUtilsStableType stable_type,
f86c11
 		 *
f86c11
 		 * That is no real problem and it is still impossible to
f86c11
 		 * force a collision here, because of how the remaining
f86c11
-		 * fields are hashed. That is, as we also hash @key_len
f86c11
+		 * fields are hashed. That is, as we also hash @host_id_len
f86c11
 		 * and the terminating '\0' of @network_id, it is unambigiously
f86c11
 		 * possible to revert the process and deduce the @stable_type.
f86c11
 		 */
f86c11
@@ -3416,9 +3431,9 @@ _set_stable_privacy (NMUtilsStableType stable_type,
f86c11
 	g_checksum_update (sum, (const guchar *) ifname, strlen (ifname) + 1);
f86c11
 	g_checksum_update (sum, (const guchar *) network_id, strlen (network_id) + 1);
f86c11
 	tmp[0] = htonl (dad_counter);
f86c11
-	tmp[1] = htonl (key_len);
f86c11
+	tmp[1] = htonl (host_id_len);
f86c11
 	g_checksum_update (sum, (const guchar *) tmp, sizeof (tmp));
f86c11
-	g_checksum_update (sum, (const guchar *) secret_key, key_len);
f86c11
+	g_checksum_update (sum, (const guchar *) host_id, host_id_len);
f86c11
 	nm_utils_checksum_get_digest (sum, digest);
f86c11
 
f86c11
 	while (_is_reserved_ipv6_iid (digest)) {
f86c11
@@ -3439,11 +3454,11 @@ nm_utils_ipv6_addr_set_stable_privacy_impl (NMUtilsStableType stable_type,
f86c11
                                             const char *ifname,
f86c11
                                             const char *network_id,
f86c11
                                             guint32 dad_counter,
f86c11
-                                            guint8 *secret_key,
f86c11
-                                            gsize key_len,
f86c11
+                                            guint8 *host_id,
f86c11
+                                            gsize host_id_len,
f86c11
                                             GError **error)
f86c11
 {
f86c11
-	return _set_stable_privacy (stable_type, addr, ifname, network_id, dad_counter, secret_key, key_len, error);
f86c11
+	return _set_stable_privacy (stable_type, addr, ifname, network_id, dad_counter, host_id, host_id_len, error);
f86c11
 }
f86c11
 
f86c11
 #define RFC7217_IDGEN_RETRIES 3
f86c11
@@ -3463,8 +3478,8 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type,
f86c11
                                        guint32 dad_counter,
f86c11
                                        GError **error)
f86c11
 {
f86c11
-	const guint8 *secret_key;
f86c11
-	gsize key_len;
f86c11
+	const guint8 *host_id;
f86c11
+	gsize host_id_len;
f86c11
 
f86c11
 	g_return_val_if_fail (network_id, FALSE);
f86c11
 
f86c11
@@ -3474,10 +3489,10 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type,
f86c11
 		return FALSE;
f86c11
 	}
f86c11
 
f86c11
-	nm_utils_secret_key_get (&secret_key, &key_len);
f86c11
+	nm_utils_host_id_get (&host_id, &host_id_len);
f86c11
 
f86c11
 	return _set_stable_privacy (stable_type, addr, ifname, network_id, dad_counter,
f86c11
-	                            secret_key, key_len, error);
f86c11
+	                            host_id, host_id_len, error);
f86c11
 }
f86c11
 
f86c11
 /*****************************************************************************/
f86c11
@@ -3549,8 +3564,8 @@ nm_utils_hw_addr_gen_random_eth (const char *current_mac_address,
f86c11
 static char *
f86c11
 _hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
f86c11
                          const char *stable_id,
f86c11
-                         const guint8 *secret_key,
f86c11
-                         gsize key_len,
f86c11
+                         const guint8 *host_id,
f86c11
+                         gsize host_id_len,
f86c11
                          const char *ifname,
f86c11
                          const char *current_mac_address,
f86c11
                          const char *generate_mac_address_mask)
f86c11
@@ -3562,19 +3577,19 @@ _hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
f86c11
 	guint8 stable_type_uint8;
f86c11
 
f86c11
 	nm_assert (stable_id);
f86c11
-	nm_assert (secret_key);
f86c11
+	nm_assert (host_id);
f86c11
 
f86c11
 	sum = g_checksum_new (G_CHECKSUM_SHA256);
f86c11
 
f86c11
-	key_len = MIN (key_len, G_MAXUINT32);
f86c11
+	host_id_len = MIN (host_id_len, G_MAXUINT32);
f86c11
 
f86c11
 	nm_assert (stable_type < (NMUtilsStableType) 255);
f86c11
 	stable_type_uint8 = stable_type;
f86c11
 	g_checksum_update (sum, (const guchar *) &stable_type_uint8, sizeof (stable_type_uint8));
f86c11
 
f86c11
-	tmp = htonl ((guint32) key_len);
f86c11
+	tmp = htonl ((guint32) host_id_len);
f86c11
 	g_checksum_update (sum, (const guchar *) &tmp, sizeof (tmp));
f86c11
-	g_checksum_update (sum, (const guchar *) secret_key, key_len);
f86c11
+	g_checksum_update (sum, (const guchar *) host_id, host_id_len);
f86c11
 	g_checksum_update (sum, (const guchar *) (ifname ?: ""), ifname ? (strlen (ifname) + 1) : 1);
f86c11
 	g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1);
f86c11
 
f86c11
@@ -3588,13 +3603,13 @@ _hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
f86c11
 char *
f86c11
 nm_utils_hw_addr_gen_stable_eth_impl (NMUtilsStableType stable_type,
f86c11
                                       const char *stable_id,
f86c11
-                                      const guint8 *secret_key,
f86c11
-                                      gsize key_len,
f86c11
+                                      const guint8 *host_id,
f86c11
+                                      gsize host_id_len,
f86c11
                                       const char *ifname,
f86c11
                                       const char *current_mac_address,
f86c11
                                       const char *generate_mac_address_mask)
f86c11
 {
f86c11
-	return _hw_addr_gen_stable_eth (stable_type, stable_id, secret_key, key_len, ifname, current_mac_address, generate_mac_address_mask);
f86c11
+	return _hw_addr_gen_stable_eth (stable_type, stable_id, host_id, host_id_len, ifname, current_mac_address, generate_mac_address_mask);
f86c11
 }
f86c11
 
f86c11
 char *
f86c11
@@ -3604,17 +3619,17 @@ nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
f86c11
                                  const char *current_mac_address,
f86c11
                                  const char *generate_mac_address_mask)
f86c11
 {
f86c11
-	const guint8 *secret_key;
f86c11
-	gsize key_len;
f86c11
+	const guint8 *host_id;
f86c11
+	gsize host_id_len;
f86c11
 
f86c11
 	g_return_val_if_fail (stable_id, NULL);
f86c11
 
f86c11
-	nm_utils_secret_key_get (&secret_key, &key_len);
f86c11
+	nm_utils_host_id_get (&host_id, &host_id_len);
f86c11
 
f86c11
 	return _hw_addr_gen_stable_eth (stable_type,
f86c11
 	                                stable_id,
f86c11
-	                                secret_key,
f86c11
-	                                key_len,
f86c11
+	                                host_id,
f86c11
+	                                host_id_len,
f86c11
 	                                ifname,
f86c11
 	                                current_mac_address,
f86c11
 	                                generate_mac_address_mask);
f86c11
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
f86c11
index ab9dade21..c93e69bbd 100644
f86c11
--- a/src/nm-core-utils.h
f86c11
+++ b/src/nm-core-utils.h
f86c11
@@ -289,9 +289,9 @@ gboolean nm_utils_machine_id_is_fake (void);
f86c11
 const char *nm_utils_get_boot_id_str (void);
f86c11
 const struct _NMUuid *nm_utils_get_boot_id_bin (void);
f86c11
 
f86c11
-gboolean nm_utils_secret_key_get (const guint8 **out_secret_key,
f86c11
-                                  gsize *out_key_len);
f86c11
-gint64 nm_utils_secret_key_get_timestamp (void);
f86c11
+gboolean nm_utils_host_id_get (const guint8 **out_host_id,
f86c11
+                               gsize *out_host_id_len);
f86c11
+gint64 nm_utils_host_id_get_timestamp (void);
f86c11
 
f86c11
 /* IPv6 Interface Identifier helpers */
f86c11
 
f86c11
@@ -359,8 +359,8 @@ gboolean nm_utils_ipv6_addr_set_stable_privacy_impl (NMUtilsStableType stable_ty
f86c11
                                                      const char *ifname,
f86c11
                                                      const char *network_id,
f86c11
                                                      guint32 dad_counter,
f86c11
-                                                     guint8 *secret_key,
f86c11
-                                                     gsize key_len,
f86c11
+                                                     guint8 *host_id,
f86c11
+                                                     gsize host_id_len,
f86c11
                                                      GError **error);
f86c11
 
f86c11
 gboolean nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType id_type,
f86c11
@@ -374,8 +374,8 @@ char *nm_utils_hw_addr_gen_random_eth (const char *current_mac_address,
f86c11
                                        const char *generate_mac_address_mask);
f86c11
 char *nm_utils_hw_addr_gen_stable_eth_impl (NMUtilsStableType stable_type,
f86c11
                                             const char *stable_id,
f86c11
-                                            const guint8 *secret_key,
f86c11
-                                            gsize key_len,
f86c11
+                                            const guint8 *host_id,
f86c11
+                                            gsize host_id_len,
f86c11
                                             const char *ifname,
f86c11
                                             const char *current_mac_address,
f86c11
                                             const char *generate_mac_address_mask);
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From f135dfbf60b58123e75a7d560a44b815332ad5d0 Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 10:14:51 +0100
f86c11
Subject: [PATCH 08/10] core/trivial: rename nm_utils_get_boot_id_*()
f86c11
f86c11
Rename to nm_utils_boot_id_*(), it matches nm_utils_machine_id_*()
f86c11
and nm_utils_host_id_get().
f86c11
f86c11
(cherry picked from commit d693e03a74bee600ba14ee8dad666ff6fe658ca2)
f86c11
(cherry picked from commit 4482c4d4af091baa16f10f5ac42919095e079559)
f86c11
---
f86c11
 src/devices/nm-device.c | 2 +-
f86c11
 src/nm-core-utils.c     | 6 +++---
f86c11
 src/nm-core-utils.h     | 4 ++--
f86c11
 3 files changed, 6 insertions(+), 6 deletions(-)
f86c11
f86c11
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
f86c11
index 8821dfaa9..738e032e3 100644
f86c11
--- a/src/devices/nm-device.c
f86c11
+++ b/src/devices/nm-device.c
f86c11
@@ -1288,7 +1288,7 @@ _get_stable_id (NMDevice *self,
f86c11
 		stable_type = nm_utils_stable_id_parse (stable_id,
f86c11
 		                                        nm_device_get_ip_iface (self),
f86c11
 		                                        !hwaddr_is_fake ? hwaddr : NULL,
f86c11
-		                                        nm_utils_get_boot_id_str (),
f86c11
+		                                        nm_utils_boot_id_str (),
f86c11
 		                                        uuid,
f86c11
 		                                        &generated);
f86c11
 
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index 4ac68c2da..18d79bd1d 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2669,7 +2669,7 @@ again:
f86c11
 				 * to read/write the secret-key to disk. Fallback to boot-id. The boot-id
f86c11
 				 * itself may be fake and randomly generated ad-hoc, but that is as best
f86c11
 				 * as it gets.  */
f86c11
-				seed_bin = (const guint8 *) nm_utils_get_boot_id_bin ();
f86c11
+				seed_bin = (const guint8 *) nm_utils_boot_id_bin ();
f86c11
 				seed_len = sizeof (NMUuid);
f86c11
 				fake_type = "boot-id";
f86c11
 				hash_seed = "7ff0c8f5-5399-4901-ab63-61bf594abe8b";
f86c11
@@ -2975,13 +2975,13 @@ again:
f86c11
 }
f86c11
 
f86c11
 const char *
f86c11
-nm_utils_get_boot_id_str (void)
f86c11
+nm_utils_boot_id_str (void)
f86c11
 {
f86c11
 	return _boot_id_get ()->str;
f86c11
 }
f86c11
 
f86c11
 const NMUuid *
f86c11
-nm_utils_get_boot_id_bin (void)
f86c11
+nm_utils_boot_id_bin (void)
f86c11
 {
f86c11
 	return &_boot_id_get ()->bin;
f86c11
 }
f86c11
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
f86c11
index c93e69bbd..51a695f9f 100644
f86c11
--- a/src/nm-core-utils.h
f86c11
+++ b/src/nm-core-utils.h
f86c11
@@ -286,8 +286,8 @@ const char *nm_utils_machine_id_str (void);
f86c11
 const struct _NMUuid *nm_utils_machine_id_bin (void);
f86c11
 gboolean nm_utils_machine_id_is_fake (void);
f86c11
 
f86c11
-const char *nm_utils_get_boot_id_str (void);
f86c11
-const struct _NMUuid *nm_utils_get_boot_id_bin (void);
f86c11
+const char *nm_utils_boot_id_str (void);
f86c11
+const struct _NMUuid *nm_utils_boot_id_bin (void);
f86c11
 
f86c11
 gboolean nm_utils_host_id_get (const guint8 **out_host_id,
f86c11
                                gsize *out_host_id_len);
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From 221a0ad9f6594ad0e91211f1fcc0bbe273b7c0cb Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 11:03:02 +0100
f86c11
Subject: [PATCH 09/10] core: split initializing host-id singleton out of
f86c11
 nm_utils_host_id_get()
f86c11
f86c11
(cherry picked from commit e9887d4816805d939e91215ad137b94ffa3c2c5d)
f86c11
(cherry picked from commit 164d796cf87e1f99ac2a2581f0f7096e6e230408)
f86c11
---
f86c11
 src/nm-core-utils.c | 47 ++++++++++++++++++++++++++-------------------
f86c11
 1 file changed, 27 insertions(+), 20 deletions(-)
f86c11
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index 18d79bd1d..b4997db21 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2877,6 +2877,31 @@ typedef struct {
f86c11
 	bool is_good:1;
f86c11
 } HostIdData;
f86c11
 
f86c11
+static const HostIdData *
f86c11
+_host_id_get (void)
f86c11
+{
f86c11
+	static const HostIdData *volatile host_id_static;
f86c11
+	const HostIdData *host_id;
f86c11
+
f86c11
+again:
f86c11
+	host_id = g_atomic_pointer_get (&host_id_static);
f86c11
+	if (G_UNLIKELY (!host_id)) {
f86c11
+		static HostIdData host_id_data;
f86c11
+		static gsize init_value = 0;
f86c11
+
f86c11
+		if (!g_once_init_enter (&init_value))
f86c11
+			goto again;
f86c11
+
f86c11
+		host_id_data.is_good = _host_id_read (&host_id_data.host_id,
f86c11
+		                                      &host_id_data.host_id_len);
f86c11
+		host_id = &host_id_data;
f86c11
+		g_atomic_pointer_set (&host_id_static, host_id);
f86c11
+		g_once_init_leave (&init_value, 1);
f86c11
+	}
f86c11
+
f86c11
+	return host_id;
f86c11
+}
f86c11
+
f86c11
 /**
f86c11
  * nm_utils_host_id_get:
f86c11
  * @out_host_id: (out) (transfer none): the binary host key
f86c11
@@ -2896,25 +2921,9 @@ gboolean
f86c11
 nm_utils_host_id_get (const guint8 **out_host_id,
f86c11
                       gsize *out_host_id_len)
f86c11
 {
f86c11
-	static const HostIdData *volatile host_id_static;
f86c11
 	const HostIdData *host_id;
f86c11
 
f86c11
-again:
f86c11
-	host_id = g_atomic_pointer_get (&host_id_static);
f86c11
-	if (G_UNLIKELY (!host_id)) {
f86c11
-		static HostIdData host_id_data;
f86c11
-		static gsize init_value = 0;
f86c11
-
f86c11
-		if (!g_once_init_enter (&init_value))
f86c11
-			goto again;
f86c11
-
f86c11
-		host_id_data.is_good = _host_id_read (&host_id_data.host_id,
f86c11
-		                                      &host_id_data.host_id_len);
f86c11
-		host_id = &host_id_data;
f86c11
-		g_atomic_pointer_set (&host_id_static, host_id);
f86c11
-		g_once_init_leave (&init_value, 1);
f86c11
-	}
f86c11
-
f86c11
+	host_id = _host_id_get ();
f86c11
 	*out_host_id = host_id->host_id;
f86c11
 	*out_host_id_len = host_id->host_id_len;
f86c11
 	return host_id->is_good;
f86c11
@@ -2924,10 +2933,8 @@ gint64
f86c11
 nm_utils_host_id_get_timestamp (void)
f86c11
 {
f86c11
 	struct stat stat_buf;
f86c11
-	const guint8 *host_id;
f86c11
-	gsize host_id_len;
f86c11
 
f86c11
-	if (!nm_utils_host_id_get (&host_id, &host_id_len))
f86c11
+	if (!_host_id_get ()->is_good)
f86c11
 		return 0;
f86c11
 
f86c11
 	if (stat (SECRET_KEY_FILE, &stat_buf) != 0)
f86c11
-- 
f86c11
2.19.2
f86c11
f86c11
f86c11
From 51853f1456413b6ba45890932d4d4cf08b4f76b0 Mon Sep 17 00:00:00 2001
f86c11
From: Thomas Haller <thaller@redhat.com>
f86c11
Date: Wed, 12 Dec 2018 11:04:12 +0100
f86c11
Subject: [PATCH 10/10] core: never fail reading host-id timestamp and never
f86c11
 change it
f86c11
f86c11
The timestamp of the host-id is the timestamp of the secret_key file.
f86c11
Under normal circumstances, reading the timestamp should never fail,
f86c11
and reading it multiple times should always yield the same result.
f86c11
f86c11
If we unexpectedly fail to read the timestamp from the file we want:
f86c11
f86c11
- log a warning, so that the user can find out what's wrong. But
f86c11
  do so only once.
f86c11
f86c11
- we don't want to handle errors or fail operation due to a missing
f86c11
  timestamp. Remember, it's not supposed to ever fail, and if it does,
f86c11
  just log a warning and proceed with a fake timestamp instead. In
f86c11
  that case something is wrong, but using a non-stable, fake timestamp
f86c11
  is the least of the problems here.
f86c11
  We already have a stable identifier (the host-id) which we can use to
f86c11
  generate a fake timestamp. Use it.
f86c11
f86c11
In case the user would replace the secret_key file, we also don't want
f86c11
that accessing nm_utils_host_id_get_timestamp*() yields different
f86c11
results. It's not implemented (nor necessary) to support reloading a
f86c11
different timestamp. Hence, nm_utils_host_id_get_timestamp() should
f86c11
memoize the value and ensure that it never changes.
f86c11
f86c11
(cherry picked from commit a68d027ba4537a6e30272e39a9f7927bcdca0eee)
f86c11
(cherry picked from commit 62722347c58fc0dfc8805a41813781e5a4ecacdf)
f86c11
---
f86c11
 src/devices/nm-device.c | 18 +++--------
f86c11
 src/nm-core-utils.c     | 66 ++++++++++++++++++++++++++++++++++-------
f86c11
 src/nm-core-utils.h     |  2 +-
f86c11
 3 files changed, 61 insertions(+), 25 deletions(-)
f86c11
f86c11
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
f86c11
index 738e032e3..d72c946bd 100644
f86c11
--- a/src/devices/nm-device.c
f86c11
+++ b/src/devices/nm-device.c
f86c11
@@ -8315,15 +8315,8 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
f86c11
 		if (nm_streq (duid, "ll")) {
f86c11
 			duid_out = generate_duid_ll (g_bytes_get_data (hwaddr, NULL));
f86c11
 		} else {
f86c11
-			gint64 time;
f86c11
-
f86c11
-			time = nm_utils_host_id_get_timestamp ();
f86c11
-			if (!time) {
f86c11
-				duid_error = "cannot retrieve the secret key timestamp";
f86c11
-				goto out_fail;
f86c11
-			}
f86c11
-
f86c11
-			duid_out = generate_duid_llt (g_bytes_get_data (hwaddr, NULL), time);
f86c11
+			duid_out = generate_duid_llt (g_bytes_get_data (hwaddr, NULL),
f86c11
+			                              nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NS_PER_SECOND);
f86c11
 		}
f86c11
 
f86c11
 		goto out_good;
f86c11
@@ -8373,11 +8366,8 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole
f86c11
 			 * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll
f86c11
 			 * subtract it from the host_id timestamp.
f86c11
 			 */
f86c11
-			time = nm_utils_host_id_get_timestamp ();
f86c11
-			if (!time) {
f86c11
-				duid_error = "cannot retrieve the secret key timestamp";
f86c11
-				goto out_fail;
f86c11
-			}
f86c11
+			time = nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NS_PER_SECOND;
f86c11
+
f86c11
 			/* don't use too old timestamps. They cannot be expressed in DUID-LLT and
f86c11
 			 * would all be truncated to zero. */
f86c11
 			time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS);
f86c11
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
f86c11
index b4997db21..d5e6346de 100644
f86c11
--- a/src/nm-core-utils.c
f86c11
+++ b/src/nm-core-utils.c
f86c11
@@ -2727,6 +2727,49 @@ nm_utils_machine_id_is_fake (void)
f86c11
 #define SECRET_KEY_V2_PREFIX "nm-v2:"
f86c11
 #define SECRET_KEY_FILE      NMSTATEDIR"/secret_key"
f86c11
 
f86c11
+static gboolean
f86c11
+_host_id_read_timestamp (gboolean use_secret_key_file,
f86c11
+                         const guint8 *host_id,
f86c11
+                         gsize host_id_len,
f86c11
+                         gint64 *out_timestamp_ns)
f86c11
+{
f86c11
+	struct stat st;
f86c11
+	gint64 now;
f86c11
+	guint64 v;
f86c11
+
f86c11
+	if (   use_secret_key_file
f86c11
+	    && stat (SECRET_KEY_FILE, &st) == 0) {
f86c11
+		/* don't check for overflow or timestamps in the future. We get whatever
f86c11
+		 * (bogus) date is on the file. */
f86c11
+		*out_timestamp_ns = (st.st_mtim.tv_sec * NM_UTILS_NS_PER_SECOND) + st.st_mtim.tv_nsec;
f86c11
+		return TRUE;
f86c11
+	}
f86c11
+
f86c11
+	/* generate a fake timestamp based on the host-id.
f86c11
+	 *
f86c11
+	 * This really should never happen under normal circumstances. We already
f86c11
+	 * are in a code path, where the system has a problem (unable to get good randomness
f86c11
+	 * and/or can't access the secret_key). In such a scenario, a fake timestamp is the
f86c11
+	 * least of our problems.
f86c11
+	 *
f86c11
+	 * At least, generate something sensible so we don't have to worry about the
f86c11
+	 * timestamp. It is wrong to worry about using a fake timestamp (which is tied to
f86c11
+	 * the secret_key) if we are unable to access the secret_key file in the first place.
f86c11
+	 *
f86c11
+	 * Pick a random timestamp from the past two years. Yes, this timestamp
f86c11
+	 * is not stable accross restarts, but apparently neither is the host-id
f86c11
+	 * nor the secret_key itself. */
f86c11
+
f86c11
+#define EPOCH_TWO_YEARS  (G_GINT64_CONSTANT (2 * 365 * 24 * 3600) * NM_UTILS_NS_PER_SECOND)
f86c11
+
f86c11
+	v = nm_hash_siphash42 (1156657133u, host_id, host_id_len);
f86c11
+
f86c11
+	now = time (NULL);
f86c11
+	*out_timestamp_ns = NM_MAX ((gint64) 1,
f86c11
+	                            (now * NM_UTILS_NS_PER_SECOND) - ((gint64) (v % ((guint64) (EPOCH_TWO_YEARS)))));
f86c11
+	return FALSE;
f86c11
+}
f86c11
+
f86c11
 static const guint8 *
f86c11
 _host_id_hash_v2 (const guint8 *seed_arr,
f86c11
                   gsize seed_len,
f86c11
@@ -2874,7 +2917,9 @@ out:
f86c11
 typedef struct {
f86c11
 	guint8 *host_id;
f86c11
 	gsize host_id_len;
f86c11
+	gint64 timestamp_ns;
f86c11
 	bool is_good:1;
f86c11
+	bool timestamp_is_good:1;
f86c11
 } HostIdData;
f86c11
 
f86c11
 static const HostIdData *
f86c11
@@ -2894,6 +2939,15 @@ again:
f86c11
 
f86c11
 		host_id_data.is_good = _host_id_read (&host_id_data.host_id,
f86c11
 		                                      &host_id_data.host_id_len);
f86c11
+
f86c11
+		host_id_data.timestamp_is_good = _host_id_read_timestamp (host_id_data.is_good,
f86c11
+		                                                          host_id_data.host_id,
f86c11
+		                                                          host_id_data.host_id_len,
f86c11
+		                                                          &host_id_data.timestamp_ns);
f86c11
+		if (   !host_id_data.timestamp_is_good
f86c11
+		    && host_id_data.is_good)
f86c11
+			nm_log_warn (LOGD_CORE, "secret-key: failure reading host timestamp (use fake one)");
f86c11
+
f86c11
 		host_id = &host_id_data;
f86c11
 		g_atomic_pointer_set (&host_id_static, host_id);
f86c11
 		g_once_init_leave (&init_value, 1);
f86c11
@@ -2930,17 +2984,9 @@ nm_utils_host_id_get (const guint8 **out_host_id,
f86c11
 }
f86c11
 
f86c11
 gint64
f86c11
-nm_utils_host_id_get_timestamp (void)
f86c11
+nm_utils_host_id_get_timestamp_ns (void)
f86c11
 {
f86c11
-	struct stat stat_buf;
f86c11
-
f86c11
-	if (!_host_id_get ()->is_good)
f86c11
-		return 0;
f86c11
-
f86c11
-	if (stat (SECRET_KEY_FILE, &stat_buf) != 0)
f86c11
-		return 0;
f86c11
-
f86c11
-	return stat_buf.st_mtim.tv_sec;
f86c11
+	return _host_id_get ()->timestamp_ns;
f86c11
 }
f86c11
 
f86c11
 /*****************************************************************************/
f86c11
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
f86c11
index 51a695f9f..16ca50b60 100644
f86c11
--- a/src/nm-core-utils.h
f86c11
+++ b/src/nm-core-utils.h
f86c11
@@ -291,7 +291,7 @@ const struct _NMUuid *nm_utils_boot_id_bin (void);
f86c11
 
f86c11
 gboolean nm_utils_host_id_get (const guint8 **out_host_id,
f86c11
                                gsize *out_host_id_len);
f86c11
-gint64 nm_utils_host_id_get_timestamp (void);
f86c11
+gint64 nm_utils_host_id_get_timestamp_ns (void);
f86c11
 
f86c11
 /* IPv6 Interface Identifier helpers */
f86c11
 
f86c11
-- 
f86c11
2.19.2
f86c11