diff --git a/Makefile.am b/Makefile.am index 50879e6f81..9cef085d51 100644 --- a/Makefile.am +++ b/Makefile.am @@ -610,9 +610,11 @@ janus_pp_rec_CFLAGS = \ -I$(top_builddir)/postprocessing \ $(LIBCURL_CFLAGS) \ $(POST_PROCESSING_CFLAGS) \ + $(BORINGSSL_CFLAGS) \ $(NULL) janus_pp_rec_LDADD = \ + $(BORINGSSL_LIBS) \ $(POST_PROCESSING_LIBS) \ $(LIBCURL_LDFLAGS) $(LIBCURL_LIBS) \ $(NULL) @@ -637,9 +639,11 @@ mjr2pcap_SOURCES = \ mjr2pcap_CFLAGS = \ $(AM_CFLAGS) \ $(POST_PROCESSING_CFLAGS) \ + $(BORINGSSL_CFLAGS) \ $(NULL) mjr2pcap_LDADD = \ + $(BORINGSSL_LIBS) \ $(POST_PROCESSING_LIBS) \ $(POST_PROCESSING_MANUAL_LIBS) \ $(NULL) @@ -659,9 +663,11 @@ pcap2mjr_CFLAGS = \ -I$(top_builddir)/postprocessing \ $(POST_PROCESSING_CFLAGS) \ $(PCAP_CFLAGS) \ + $(BORINGSSL_CFLAGS) \ $(NULL) pcap2mjr_LDADD = \ + $(BORINGSSL_LIBS) \ $(POST_PROCESSING_LIBS) \ $(POST_PROCESSING_MANUAL_LIBS) \ $(PCAP_LIBS) \ diff --git a/configure.ac b/configure.ac index 8ff2197183..80816f2205 100644 --- a/configure.ac +++ b/configure.ac @@ -954,6 +954,8 @@ AS_IF([test "x$enable_post_processing" = "xyes"], [ glib-2.0 >= $glib_version jansson >= $jansson_version + libssl >= $ssl_version + libcrypto libavutil libavcodec libavformat diff --git a/fuzzers/rtcp_fuzzer.c b/fuzzers/rtcp_fuzzer.c index 7fe297084d..0497e6f82f 100644 --- a/fuzzers/rtcp_fuzzer.c +++ b/fuzzers/rtcp_fuzzer.c @@ -13,6 +13,11 @@ gboolean janus_log_colors = FALSE; char *janus_log_global_prefix = NULL; int lock_debug = 0; +/* This is to avoid linking with openSSL */ +int RAND_bytes(uint8_t *key, int len) { + return 0; +} + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { /* Sanity Checks */ /* Max UDP payload with MTU=1500 */ diff --git a/fuzzers/sdp_fuzzer.c b/fuzzers/sdp_fuzzer.c index f4c3bdacae..b3ce705b39 100644 --- a/fuzzers/sdp_fuzzer.c +++ b/fuzzers/sdp_fuzzer.c @@ -14,6 +14,11 @@ char *janus_log_global_prefix = NULL; int lock_debug = 0; int refcount_debug = 0; +/* This is to avoid linking with openSSL */ +int RAND_bytes(uint8_t *key, int len) { + return 0; +} + int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { /* Since we're fuzzing SDP, and that in our case SDP always comes * from a Jansson call, this will need to be a valid string */ diff --git a/janus.c b/janus.c index 13907957d7..5b887bd872 100644 --- a/janus.c +++ b/janus.c @@ -4996,6 +4996,11 @@ gint main(int argc, char *argv[]) SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); + /* Check if random pool looks ok (this does not give any guarantees for later, though) */ + if(RAND_status() != 1) { + JANUS_LOG(LOG_FATAL, "Random pool is not properly seeded, cannot generate random numbers\n"); + exit(1); + } /* ... and DTLS-SRTP in particular */ const char *dtls_ciphers = NULL; item = janus_config_get(config, config_certs, janus_config_type_item, "dtls_ciphers"); diff --git a/plugins/janus_nosip.c b/plugins/janus_nosip.c index b8330d3e19..8198670059 100644 --- a/plugins/janus_nosip.c +++ b/plugins/janus_nosip.c @@ -786,11 +786,6 @@ int janus_nosip_init(janus_callbacks *callback, const char *config_path) { } JANUS_LOG(LOG_VERB, "Local IP set to %s\n", local_ip); -#ifdef HAVE_SRTP_2 - /* Init randomizer (for randum numbers in SRTP) */ - RAND_poll(); -#endif - sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)janus_nosip_session_destroy); messages = g_async_queue_new_full((GDestroyNotify) janus_nosip_message_free); /* This is the callback we'll need to invoke to contact the Janus core */ diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index ca1c4758b0..18c2075d68 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -1924,11 +1924,6 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) { } JANUS_LOG(LOG_VERB, "Local IP set to %s\n", local_ip); -#ifdef HAVE_SRTP_2 - /* Init randomizer (for randum numbers in SRTP) */ - RAND_poll(); -#endif - /* Setup sofia */ su_init(); if(notify_events && callback->events_is_enabled()) { diff --git a/utils.c b/utils.c index 99b861e7e2..80b0fa0b12 100644 --- a/utils.c +++ b/utils.c @@ -21,6 +21,7 @@ #include #include +#include #include "utils.h" #include "debug.h" @@ -71,23 +72,25 @@ gboolean janus_strcmp_const_time(const void *str1, const void *str2) { } guint32 janus_random_uint32(void) { - return g_random_int(); + guint32 ret = 0; + if(RAND_bytes((void *)&ret, sizeof(ret)) != 1) { + JANUS_LOG(LOG_WARN, "Safe RAND_bytes() failed, falling back to unsafe PRNG\n"); + return g_random_int(); + } + return ret; +} + +guint64 janus_random_uint64_full(void) { + guint64 ret = 0; + if(RAND_bytes((void *)&ret, sizeof(ret)) != 1) { + JANUS_LOG(LOG_WARN, "Safe RAND_bytes() failed, falling back to unsafe PRNG\n"); + return (g_random_int() << 32) | g_random_int(); + } + return ret; } guint64 janus_random_uint64(void) { - /* - * FIXME This needs to be improved, and use something that generates - * more strongly random stuff... using /dev/urandom is probably not - * a good idea, as we don't want to make it harder to cross compile Janus - * - * TODO Look into what libssl and/or libcrypto provide in that respect - * - * PS: JavaScript only supports integer up to 2^53, so we need to - * make sure the number is below 9007199254740992 for safety - */ - guint64 num = g_random_int() & 0x1FFFFF; - num = (num << 32) | g_random_int(); - return num; + return janus_random_uint64_full() & 0x1FFFFFFFFFFFFF; } char *janus_random_uuid(void) { @@ -100,8 +103,8 @@ char *janus_random_uuid(void) { const char *template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"; const char *samples = "0123456789abcdef"; union { unsigned char b[16]; uint64_t word[2]; } rnd; - rnd.word[0] = janus_random_uint64(); - rnd.word[1] = janus_random_uint64(); + rnd.word[0] = janus_random_uint64_full(); + rnd.word[1] = janus_random_uint64_full(); /* Generate the string */ char uuid[37], *dst = uuid; const char *p = template; diff --git a/utils.h b/utils.h index 127433e793..22eb3f041e 100644 --- a/utils.h +++ b/utils.h @@ -61,16 +61,37 @@ gboolean janus_is_true(const char *value); gboolean janus_strcmp_const_time(const void *str1, const void *str2); /*! \brief Helper to generate random 32-bit unsigned integers (useful for SSRCs, etc.) - * @note Currently just wraps g_random_int() - * @returns A random 32-bit unsigned integer */ + * @note Warning: this will fall back to a non-cryptographically safe PRNG in case + * the crypto library RAND_bytes() call fails. + * @returns A (mostly crypto-safe) random 32-bit unsigned integer */ guint32 janus_random_uint32(void); -/*! \brief Helper to generate random 64-bit unsigned integers (useful for Janus IDs) - * @returns A random 64-bit unsigned integer */ +/*! \brief Helper to generate random 64-bit unsigned integers + * @note Unlike janus_random_uint64(), which actually only generates 52 bits, this + * generates the full 64 bits. See the janus_random_uint64() docstring for details. + * Warning: this will fall back to a non-cryptographically safe PRNG in case + * the crypto library RAND_bytes() call fails. + * @returns A (mostly crypto-safe) random 52-bit unsigned integer */ +guint64 janus_random_uint64_full(void); + +/*! \brief Helper to generate random 52 bit unsigned integers + * @note The reason for 52 instead of 64 bits: Javascript does not have real integers, + * its builtin "number" type is a float64. Thus, only integer values up to + * Number.MAX_SAFE_INTEGER == 2^53 - 1 == 9007199254740991 + * can be safely represented in Javascript. This method returns such numbers. + * Use this method instead of janus_random_uint64_full() whenever you generate numbers which + * might end up in Javascript (via JSON API). + * This method is called janus_random_uint64() instead of janus_random_uint52() (or similar) + * for backwards compatibility. + * Warning: this will fall back to a non-cryptographically safe PRNG in case + * the crypto library RAND_bytes() call fails. + * @returns A (mostly crypto-safe) random 64-bit unsigned integer */ guint64 janus_random_uint64(void); /*! \brief Helper to generate random UUIDs (needed by some plugins) - * @returns A random UUID string, which must be deallocated with \c g_free */ + * Warning: this will fall back to a non-cryptographically safe PRNG in case + * the crypto library RAND_bytes() call fails. + * @returns A (mostly crypto-safe) random UUID string, which must be deallocated with \c g_free */ char *janus_random_uuid(void); /*! \brief Helper to generate an allocated copy of a guint64 number