core: add nm_utils_get_secret_key() util

(cherry picked from commit d787b8c827)
This commit is contained in:
Thomas Haller 2016-04-25 18:14:25 +02:00
parent 50dc5fecab
commit de22249183
3 changed files with 69 additions and 49 deletions

View file

@ -2559,6 +2559,63 @@ nm_utils_is_specific_hostname (const char *name)
/******************************************************************/
guint8 *
nm_utils_secret_key_read (gsize *out_key_len, GError **error)
{
guint8 *secret_key = NULL;
gsize key_len;
/* out_key_len is not optional, because without it you cannot safely
* access the returned memory. */
*out_key_len = 0;
/* Let's try to load a saved secret key first. */
if (g_file_get_contents (NMSTATEDIR "/secret_key", (char **) &secret_key, &key_len, NULL)) {
if (key_len < 16) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Key is too short to be usable");
key_len = 0;
}
} else {
int urandom = open ("/dev/urandom", O_RDONLY);
mode_t key_mask;
if (urandom == -1) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Can't open /dev/urandom: %s", strerror (errno));
key_len = 0;
goto out;
}
/* RFC7217 mandates the key SHOULD be at least 128 bits.
* Let's use twice as much. */
key_len = 32;
secret_key = g_malloc (key_len);
key_mask = umask (0077);
if (read (urandom, secret_key, key_len) == key_len) {
if (!g_file_set_contents (NMSTATEDIR "/secret_key", (char *) secret_key, key_len, error)) {
g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key: ");
key_len = 0;
}
} else {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Could not obtain a secret");
key_len = 0;
}
umask (key_mask);
close (urandom);
}
out:
if (key_len) {
*out_key_len = key_len;
return secret_key;
}
g_free (secret_key);
return NULL;
}
/* Returns the "u" (universal/local) bit value for a Modified EUI-64 */
static gboolean
get_gre_eui64_u_bit (guint32 addr)
@ -2686,7 +2743,7 @@ _set_stable_privacy (struct in6_addr *addr,
const char *ifname,
const char *uuid,
guint dad_counter,
gchar *secret_key,
guint8 *secret_key,
gsize key_len,
GError **error)
{
@ -2744,9 +2801,8 @@ nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
guint dad_counter,
GError **error)
{
gchar *secret_key = NULL;
gs_free guint8 *secret_key = NULL;
gsize key_len = 0;
gboolean success = FALSE;
if (dad_counter >= RFC7217_IDGEN_RETRIES) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@ -2754,50 +2810,12 @@ nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
return FALSE;
}
/* Let's try to load a saved secret key first. */
if (g_file_get_contents (NMSTATEDIR "/secret_key", &secret_key, &key_len, NULL)) {
if (key_len < 16) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Key is too short to be usable");
key_len = 0;
}
} else {
int urandom = open ("/dev/urandom", O_RDONLY);
mode_t key_mask;
secret_key = nm_utils_secret_key_read (&key_len, error);
if (!secret_key)
return FALSE;
if (urandom == -1) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Can't open /dev/urandom: %s", strerror (errno));
return FALSE;
}
/* RFC7217 mandates the key SHOULD be at least 128 bits.
* Let's use twice as much. */
key_len = 32;
secret_key = g_malloc (key_len);
key_mask = umask (0077);
if (read (urandom, secret_key, key_len) == key_len) {
if (!g_file_set_contents (NMSTATEDIR "/secret_key", secret_key, key_len, error)) {
g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key: ");
key_len = 0;
}
} else {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Could not obtain a secret");
key_len = 0;
}
umask (key_mask);
close (urandom);
}
if (key_len) {
success = _set_stable_privacy (addr, ifname, uuid, dad_counter,
secret_key, key_len, error);
}
g_free (secret_key);
return success;
return _set_stable_privacy (addr, ifname, uuid, dad_counter,
secret_key, key_len, error);
}
/**

View file

@ -306,6 +306,8 @@ const char *nm_utils_ip4_property_path (const char *ifname, const char *property
gboolean nm_utils_is_specific_hostname (const char *name);
guint8 *nm_utils_secret_key_read (gsize *out_key_len, GError **error);
/* IPv6 Interface Identifer helpers */
/**

View file

@ -34,17 +34,17 @@ test_stable_privacy (void)
struct in6_addr addr1;
inet_pton (AF_INET6, "1234::", &addr1);
_set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, "key", 3, NULL);
_set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1234::4ceb:14cd:3d54:793f");
/* We get an address without the UUID. */
inet_pton (AF_INET6, "1::", &addr1);
_set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL);
_set_stable_privacy (&addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1::11aa:2530:9144:dafa");
/* We get a different address in a different network. */
inet_pton (AF_INET6, "2::", &addr1);
_set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL);
_set_stable_privacy (&addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "2::338e:8d:c11:8726");
}