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