summaryrefslogtreecommitdiffstats
path: root/src/gsm
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2017-07-10 14:32:48 +0200
committerMax <msuraev@sysmocom.de>2017-10-09 10:18:07 +0000
commit4b2b0cc15d51d7916a939de06a7e83d8042211dc (patch)
tree46f9a1c95554b341dc94fc303b70ae3a93e7cfa0 /src/gsm
parent81dc67d03f9e1881a6115be51cd92956f5932e43 (diff)
Add function to generate random identifier
The function is a wrapper on top of getrandom() (if available via glibc) or corresponding syscall. If neither is available than failure is always returned. It's intended to generate small random data good enough for session identifiers and keys. To generate long-term cryptographic keys it's better to use special crypto libraries (like GnuTLS for example) instead. As an example it's used to replace old insecure random number generator in osmo-auc-gen utility. Change-Id: I0241b814ea4c4ce1458f7ad76e31d390383c2048 Related: OS#1694
Diffstat (limited to 'src/gsm')
-rw-r--r--src/gsm/gsm_utils.c48
-rw-r--r--src/gsm/libosmogsm.map1
2 files changed, 49 insertions, 0 deletions
diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c
index 477f076d..f572c643 100644
--- a/src/gsm/gsm_utils.c
+++ b/src/gsm/gsm_utils.c
@@ -91,9 +91,18 @@
#include <errno.h>
#include <ctype.h>
#include <inttypes.h>
+#include <time.h>
+#include <unistd.h>
#include "../../config.h"
+/* FIXME: this can be removed once we bump glibc requirements to 2.25: */
+#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)
+#include <linux/random.h>
+#elif HAVE_DECL_SYS_GETRANDOM
+#include <sys/syscall.h>
+#endif
+
/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet
* Greek symbols at hex positions 0x10 and 0x12-0x1a
* left out as they can't be handled with a char and
@@ -387,6 +396,45 @@ int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *oct
return y;
}
+/*! Generate random identifier
+ * We use /dev/urandom (default when GRND_RANDOM flag is not set).
+ * Both /dev/(u)random numbers are coming from the same CSPRNG anyway (at least on GNU/Linux >= 4.8).
+ * See also RFC4086.
+ * \param[out] out Buffer to be filled with random data
+ * \param[in] len Number of random bytes required
+ * \returns 0 on success, or a negative error code on error.
+ */
+int osmo_get_rand_id(uint8_t *out, size_t len)
+{
+ int rc;
+
+ /* this function is intended for generating short identifiers only, not arbitrary-length random data */
+ if (len > OSMO_MAX_RAND_ID_LEN)
+ return -E2BIG;
+
+#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)
+ rc = getrandom(out, len, GRND_NONBLOCK);
+#elif HAVE_DECL_SYS_GETRANDOM
+#pragma message ("Using direct syscall access for getrandom(): consider upgrading to glibc >= 2.25")
+ /* FIXME: this can be removed once we bump glibc requirements to 2.25: */
+ rc = syscall(SYS_getrandom, out, len, GRND_NONBLOCK);
+#else
+#pragma message ("Secure random unavailable: calls to osmo_get_rand_id() will always fail!")
+ return -ENOTSUP;
+#endif
+ /* getrandom() failed entirely: */
+ if (rc < 0)
+ return -errno;
+
+ /* getrandom() failed partially due to signal interruption:
+ this should never happen (according to getrandom(2)) as long as OSMO_MAX_RAND_ID_LEN < 256
+ because we do not set GRND_RANDOM but it's better to be paranoid and check anyway */
+ if (rc != len)
+ return -EAGAIN;
+
+ return 0;
+}
+
/*! Build the RSL uplink measurement IE (3GPP TS 08.58 ยง 9.3.25)
* \param[in] mru Unidirectional measurement report structure
* \param[in] dtxd_used Indicates if DTXd was used during measurement report
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 95b2ca9f..5598859a 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -39,6 +39,7 @@ abis_nm_get_sw_desc_len;
osmo_sitype_strs;
osmo_c4;
+osmo_get_rand_id;
bitvec_add_range1024;
comp128;
comp128v2;