Example #3 - mbedtls adapter in azure-iot-sdk-c

From azure-iot-sdk-c/c-utility/adapters/tlsio_mbedtls.c
297 static int tlsio_entropy_poll(void *v, unsigned char *output, size_t len, size_t *olen)
298 {
299     srand(time(NULL));
300     char *c = (char*)malloc(len);
301     memset(c, 0, len);
302     for (uint16_t i = 0; i < len; i++) {
303         c[i] = rand() % 256;
304     }
305     memmove(output, c, len);
306     *olen = len;
307 
308     free(c);
309     return(0);
310 }

Below is the author of this page's comments on the above block. The primary focus is the entropy related logic, however there are glaring mistakes which would be irresponsible to not correct.

From azure-iot-sdk-c/c-utility/adapters/tlsio_mbedtls.c
297 static int tlsio_entropy_poll(void *v, unsigned char *output, size_t len, size_t *olen)
298 {
        /* This client requires accurate time sync per it's design documentation for authentication to work, thus time() (which is an integer number of seconds) is highly known */
299     srand(time(NULL));
        /* There is no need to allocate a new buffer.  The result of malloc() is not checked.  The memory is not locked (ie mlock()) thus it can be swapped to non-volatile storage. */
300     char *c = (char*)malloc(len);
        /* There is no failure of the assignment loop below, thus the entirety of the buffer pointed to by "c" is overwritten, making the memset() below useless (or optimized out by the compiler). */
301     memset(c, 0, len);
302     for (uint16_t i = 0; i < len; i++) {
            /* Below the least significant byte returned by rand() is placed into the buffer.  Since we know what time it is (within a whole second), and that srand() has been seeded with the time,
             * we know what is in the buffer pointed to by "c"
             */
303         c[i] = rand() % 256;
304     }
        /* memmove is never necessary here because "output" can not overlap with "c". */
305     memmove(output, c, len);
306     *olen = len;
307
        /* before free()ing the buffer pointed to by "c", it should be securely erased, although again - it should have never been allocated in the first place */ 
308     free(c);
309     return(0);
310 }

Below is the next section of code with the author of this page's comments added

312 static void mbedtls_init(void *instance, const char *host) {
313     TLS_IO_INSTANCE *result = (TLS_IO_INSTANCE *)instance;
        /* The contents of "pers" is always "azure_iot_client\000" */
314     char *pers = "azure_iot_client";
315 
316     // mbedTLS initialize...
317     mbedtls_entropy_init(&result->entropy);
318     mbedtls_ctr_drbg_init(&result->ctr_drbg);
319     mbedtls_ssl_init(&result->ssl);
320     mbedtls_ssl_session_init(&result->ssn);
321     mbedtls_ssl_config_init(&result->config);
322     mbedtls_x509_crt_init(&result->trusted_certificates_parsed);
        /* below, the mbedtls library is given a pointer to the tlsio_entropy_poll() function which is commented directly above.
         * If mbedtls is compiled without additional entropy sources, then tlsio_entropy_poll() will be the only source from which the AES256 CTR DRBG
	 * establishes / reseeds itself
	 */
323     mbedtls_entropy_add_source(&result->entropy, tlsio_entropy_poll, NULL, 128, 0);
        /* below, the drbg (Deterministic Random Bit Generator) is given the same static "additional" seed of "azure_iot_client" every time
         * thus it is effectually the same as not providing an "additional" seed component
         */
324     mbedtls_ctr_drbg_seed(&result->ctr_drbg, mbedtls_entropy_func, &result->entropy, (const unsigned char *)pers, strlen(pers));
325     mbedtls_ssl_config_defaults(&result->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
326     mbedtls_ssl_conf_rng(&result->config, mbedtls_ctr_drbg_random, &result->ctr_drbg);

**Fortunately, the default mbedtls build options will add additional sources of "entropy"

Below is a sample program to show how reliably and trivially a potential bad actor can "defeat" the tlsio_entropy_poll() function if it were to stand alone

$ curl https://priverify.com/sd/demo/libc_random/example003_libc_random.c --output example003_libc_random.c
$ curl https://priverify.com/sd/demo/libc_random/compare_outputs_1_to_3.pl --output compare_outputs_1_to_3.pl
$ gcc -std=gnu11 example003_libc_random.c -o example003_libc_random
$ chmod +x compare_outputs_1_to_3.pl
$ ./example003_libc_random 512
OK
This site uses cookies. Please read our Privacy Policy