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 
21 namespace crypto {
22 
23 namespace 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 
31 namespace {
32 
33 uint8_t entropy_buf[ENTROPY_COLLECTOR_TEST_MAXLEN];
34 size_t entropy_len;
35 
36 } // namespace
37 
38 fbl::RefPtr<VmObject> entropy_vmo;
39 bool entropy_was_lost = false;
40 
SetupEntropyVmo(uint level)41 static 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.
EarlyBootTest()69 void 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 
124 void EarlyBootTest() {
125 }
126 
127 #endif // ENABLE_ENTROPY_COLLECTOR_TEST
128 
129 } // namespace entropy
130 
131 } // namespace crypto
132 
133 #if ENABLE_ENTROPY_COLLECTOR_TEST
134 LK_INIT_HOOK(setup_entropy_vmo, crypto::entropy::SetupEntropyVmo,
135              LK_INIT_LEVEL_VM + 1);
136 #endif
137