diff --git a/configure.ac b/configure.ac index 33c151e72..d9390cf87 100644 --- a/configure.ac +++ b/configure.ac @@ -73,6 +73,9 @@ AC_ARG_ENABLE(doxygen, AC_PATH_PROG(DOXYGEN,doxygen,false) AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false && test "x$doxygen" = "xyes") +# check for syscal fallback on glibc < 2.25 - can be removed once glibc version requirement is bumped +AC_CHECK_DECLS([SYS_getrandom], [], [], [[#include ]]) + # The following test is taken from WebKit's webkit.m4 saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden " diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h index bfcef08b6..83e29cac5 100644 --- a/include/osmocom/gsm/gsm_utils.h +++ b/include/osmocom/gsm/gsm_utils.h @@ -38,6 +38,9 @@ #define GSM_MAX_FN (26*51*2048) +/* Max length of random identifier which can be requested via osmo_get_rand_id() */ +#define OSMO_MAX_RAND_ID_LEN 16 + struct gsm_time { uint32_t fn; /* FN count */ uint16_t t1; /* FN div (26*51) */ @@ -60,6 +63,8 @@ enum gsm_band { const char *gsm_band_name(enum gsm_band band); enum gsm_band gsm_band_parse(const char *mhz); +int osmo_get_rand_id(uint8_t *out, size_t len); + /*! * Decode a sequence of GSM 03.38 encoded 7 bit characters. * diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 477f076d9..f572c6435 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -91,9 +91,18 @@ #include #include #include +#include +#include #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 +#elif HAVE_DECL_SYS_GETRANDOM +#include +#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 95b2ca9fb..5598859a9 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; diff --git a/utils/osmo-auc-gen.c b/utils/osmo-auc-gen.c index 1f5c83867..9d1215c80 100644 --- a/utils/osmo-auc-gen.c +++ b/utils/osmo-auc-gen.c @@ -34,6 +34,7 @@ #include #include +#include static void dump_triplets_dat(struct osmo_auth_vector *vec) { @@ -247,14 +248,11 @@ int main(int argc, char **argv) } if (!rand_is_set) { - int i; - printf("WARNING: We're using really weak random numbers!\n\n"); - srand(time(NULL)); - - for (i = 0; i < 4; ++i) { - uint32_t r; - r = rand(); - memcpy(&_rand[i*4], &r, 4); + rc = osmo_get_rand_id(_rand, 16); + if (rc < 0) { + fprintf(stderr, "\nError: unable to obtain secure random numbers: %s!\n", + strerror(-rc)); + exit(3); } }