1// Copyright 2017 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <lib/crypto/entropy/quality_test.h> 8 9#include <dev/hw_rng.h> 10#include <kernel/cmdline.h> 11#include <inttypes.h> 12#include <lib/crypto/entropy/collector.h> 13#include <lib/crypto/entropy/hw_rng_collector.h> 14#include <lib/crypto/entropy/jitterentropy_collector.h> 15#include <lk/init.h> 16#include <string.h> 17#include <platform.h> 18#include <vm/vm_object_paged.h> 19#include <zircon/types.h> 20 21namespace crypto { 22 23namespace entropy { 24 25#if ENABLE_ENTROPY_COLLECTOR_TEST 26 27#ifndef ENTROPY_COLLECTOR_TEST_MAXLEN 28#define ENTROPY_COLLECTOR_TEST_MAXLEN (1024u * 1024u) 29#endif 30 31namespace { 32 33uint8_t entropy_buf[ENTROPY_COLLECTOR_TEST_MAXLEN]; 34size_t entropy_len; 35 36} // namespace 37 38fbl::RefPtr<VmObject> entropy_vmo; 39bool entropy_was_lost = false; 40 41static void SetupEntropyVmo(uint level) { 42 if (VmObjectPaged::Create(PMM_ALLOC_FLAG_ANY, 0u, entropy_len, &entropy_vmo) != ZX_OK) { 43 printf("entropy-boot-test: Failed to create entropy_vmo (data lost)\n"); 44 entropy_was_lost = true; 45 return; 46 } 47 size_t actual; 48 if (entropy_vmo->Write(entropy_buf, 0, entropy_len, &actual) != ZX_OK) { 49 printf("entropy-boot-test: Failed to write to entropy_vmo (data lost)\n"); 50 entropy_was_lost = true; 51 return; 52 } 53 if (actual < entropy_len) { 54 printf("entropy-boot-test: partial write to entropy_vmo (data lost)\n"); 55 entropy_was_lost = true; 56 return; 57 } 58 constexpr const char *name = "debug/entropy.bin"; 59 if (entropy_vmo->set_name(name, strlen(name)) != ZX_OK) { 60 // The name is needed because devmgr uses it to add the VMO as a file in 61 // the /boot filesystem. 62 printf("entropy-boot-test: could not name entropy_vmo (data lost)\n"); 63 entropy_was_lost = true; 64 return; 65 } 66} 67 68// Run the entropy collector test. 69void EarlyBootTest() { 70 const char* src_name = cmdline_get("kernel.entropy-test.src"); 71 if (!src_name) { 72 src_name = ""; 73 } 74 75 entropy::Collector* collector = nullptr; 76 entropy::Collector* candidate; 77 char candidate_name[ZX_MAX_NAME_LEN]; 78 79 // TODO(andrewkrieger): find a nicer way to enumerate all entropy collectors 80 if (HwRngCollector::GetInstance(&candidate) == ZX_OK) { 81 candidate->get_name(candidate_name, sizeof(candidate_name)); 82 if (strncmp(candidate_name, src_name, ZX_MAX_NAME_LEN) == 0) { 83 collector = candidate; 84 } 85 } 86 if (!collector && 87 JitterentropyCollector::GetInstance(&candidate) == ZX_OK) { 88 candidate->get_name(candidate_name, sizeof(candidate_name)); 89 if (strncmp(candidate_name, src_name, ZX_MAX_NAME_LEN) == 0) { 90 collector = candidate; 91 } 92 } 93 94 // TODO(andrewkrieger): add other entropy collectors. 95 96 if (!collector) { 97 printf("entropy-boot-test: unrecognized source \"%s\"\n", src_name); 98 printf("entropy-boot-test: skipping test.\n"); 99 return; 100 } 101 102 entropy_len = cmdline_get_uint64("kernel.entropy-test.len", sizeof(entropy_buf)); 103 if (entropy_len > sizeof(entropy_buf)) { 104 entropy_len = sizeof(entropy_buf); 105 printf("entropy-boot-test: only recording %zu bytes (try defining " 106 "ENTROPY_COLLECTOR_TEST_MAXLEN)\n", sizeof(entropy_buf)); 107 } 108 109 zx_time_t start = current_time(); 110 size_t result = collector->DrawEntropy(entropy_buf, entropy_len); 111 zx_time_t end = current_time(); 112 113 if (result < entropy_len) { 114 printf("entropy-boot-test: source only returned %zu bytes.\n", result); 115 entropy_len = result; 116 } else { 117 printf("entropy-boot-test: successful draw in %" PRIu64 " nanoseconds.\n", end - start); 118 } 119} 120 121 122#else // ENABLE_ENTROPY_COLLECTOR_TEST 123 124void EarlyBootTest() { 125} 126 127#endif // ENABLE_ENTROPY_COLLECTOR_TEST 128 129} // namespace entropy 130 131} // namespace crypto 132 133#if ENABLE_ENTROPY_COLLECTOR_TEST 134LK_INIT_HOOK(setup_entropy_vmo, crypto::entropy::SetupEntropyVmo, 135 LK_INIT_LEVEL_VM + 1); 136#endif 137