Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <stdio.h>
26 : #include <string.h>
27 : #include <stdbool.h>
28 : #include <openenclave/enclave.h>
29 :
30 : #include "hal/access.h"
31 : #include "hal/log.h"
32 :
33 : #include "secret_store.h"
34 : #include "pin_policy.h"
35 :
36 : #define MAX_RETRIES 3
37 :
38 : #define SEST_PASSWORD_KEY "password"
39 : #define SEST_RETRIES_KEY "retries"
40 :
41 : // Globals
42 : static bool G_wiped;
43 : static bool G_locked;
44 : static uint8_t G_available_retries;
45 : static char G_password[MAX_PIN_LENGTH];
46 : static uint8_t G_password_length;
47 : static access_wiped_callback_t G_wiped_callback;
48 :
49 25 : bool access_init(access_wiped_callback_t wiped_callback) {
50 25 : G_locked = true;
51 25 : G_wiped = true;
52 25 : G_wiped_callback = wiped_callback;
53 :
54 25 : if (!sest_exists(SEST_PASSWORD_KEY) && !sest_exists(SEST_RETRIES_KEY)) {
55 : // Module is in a wiped and locked state. Nothing left to do
56 5 : return true;
57 : }
58 :
59 : // Read password
60 20 : if (!(G_password_length = sest_read(
61 : SEST_PASSWORD_KEY, (uint8_t*)G_password, sizeof(G_password)))) {
62 : LOG("Could not load the current password\n");
63 1 : return false;
64 : }
65 :
66 : // Make sure password is sound
67 19 : if (!pin_policy_is_valid_pin(G_password, G_password_length)) {
68 : LOG("Detected invalid password\n");
69 1 : return false;
70 : }
71 :
72 : // Read retries
73 18 : if (sest_read(SEST_RETRIES_KEY,
74 : (uint8_t*)&G_available_retries,
75 : sizeof(G_available_retries)) != sizeof(G_available_retries)) {
76 : LOG("Could not read the current retries\n");
77 1 : return false;
78 : }
79 :
80 : // Make sure number of retries read is sound
81 17 : if (!G_available_retries || G_available_retries > MAX_RETRIES) {
82 : LOG("Detected invalid retries\n");
83 2 : return false;
84 : }
85 :
86 15 : G_wiped = false;
87 : LOG("Password loaded. Access is locked\n");
88 15 : return true;
89 : }
90 :
91 4 : bool access_wipe() {
92 4 : G_wiped = true;
93 4 : G_locked = true;
94 :
95 4 : bool success = true;
96 4 : success &= sest_remove(SEST_PASSWORD_KEY);
97 4 : success &= sest_remove(SEST_RETRIES_KEY);
98 :
99 4 : return success;
100 : }
101 :
102 13 : bool access_unlock(char* password, uint8_t password_length) {
103 13 : if (G_wiped) {
104 : LOG("Access module is wiped\n");
105 1 : return false;
106 : }
107 :
108 12 : if (!G_locked) {
109 : LOG("Access module already unlocked\n");
110 1 : return true;
111 : }
112 :
113 11 : if (password_length != G_password_length ||
114 8 : memcmp(password, G_password, G_password_length)) {
115 : LOG("Invalid password\n");
116 3 : G_available_retries--;
117 3 : sest_write(SEST_RETRIES_KEY,
118 : (uint8_t*)&G_available_retries,
119 : sizeof(G_available_retries));
120 3 : if (G_available_retries == 0) {
121 : LOG("Too many unlock retries. Forcing wipe...\n");
122 1 : access_wipe();
123 1 : G_wiped_callback();
124 : }
125 3 : return false;
126 : }
127 :
128 : LOG("Access module unlocked\n");
129 8 : G_locked = false;
130 8 : G_available_retries = MAX_RETRIES;
131 8 : sest_write(SEST_RETRIES_KEY,
132 : (uint8_t*)&G_available_retries,
133 : sizeof(G_available_retries));
134 8 : return true;
135 : }
136 :
137 7 : uint8_t access_get_retries() {
138 7 : return G_available_retries;
139 : }
140 :
141 40 : bool access_is_wiped() {
142 40 : return G_wiped;
143 : }
144 :
145 41 : bool access_is_locked() {
146 41 : return G_locked;
147 : }
148 :
149 5 : bool access_set_password(char* password, uint8_t password_length) {
150 5 : if (G_locked && !G_wiped) {
151 : LOG("Access module is locked, password change not possible\n");
152 1 : return false;
153 : }
154 :
155 4 : if (!pin_policy_is_valid_pin(password, password_length)) {
156 : LOG("Invalid password\n");
157 1 : return false;
158 : }
159 :
160 3 : if (!sest_write(SEST_PASSWORD_KEY, (uint8_t*)password, password_length)) {
161 : LOG("Error writing password\n");
162 1 : return false;
163 : }
164 :
165 2 : G_password_length = password_length;
166 2 : memcpy(G_password, password, password_length);
167 2 : G_wiped = false;
168 2 : G_available_retries = MAX_RETRIES;
169 2 : sest_write(SEST_RETRIES_KEY,
170 : (uint8_t*)&G_available_retries,
171 : sizeof(G_available_retries));
172 2 : G_locked = true;
173 : LOG("Password set, access locked\n");
174 2 : return true;
175 : }
176 :
177 4 : bool access_output_password_USE_FROM_EXPORT_ONLY(uint8_t* out,
178 : size_t* out_size) {
179 : // We need a password
180 4 : if (access_is_wiped()) {
181 : LOG("Access: no password available to output\n");
182 1 : return false;
183 : }
184 :
185 : // Output buffer validations
186 3 : if (*out_size < sizeof(G_password)) {
187 : LOG("Access: output buffer to small to write password\n");
188 1 : return false;
189 : }
190 2 : if (!oe_is_within_enclave(out, *out_size)) {
191 : LOG("Access: output buffer not strictly within the enclave\n");
192 1 : return false;
193 : }
194 :
195 : // Write seed
196 1 : memcpy(out, G_password, sizeof(G_password));
197 1 : *out_size = sizeof(G_password);
198 1 : return true;
199 : }
|