blob: bbdfc4d2a7f2a2454e61adf915e746aed5e080d6 [file] [log] [blame]
Timothy Chen15adeee2020-09-09 15:44:35 -07001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4//
5// Key manager top level
6//
7
8`include "prim_assert.sv"
9
10module keymgr_ctrl import keymgr_pkg::*;(
11 input clk_i,
12 input rst_ni,
13
14 // lifecycle enforcement
15 input keymgr_en_i,
16
17 // entropy input
18 input [(LfsrWidth/2)-1:0] entropy_i,
19 output logic prng_en_o,
20
21 // Software interface
22 input init_i,
Timothy Chen1d05bd62020-10-07 18:42:07 -070023 output logic init_done_o,
Timothy Chen15adeee2020-09-09 15:44:35 -070024 input op_start_i,
Timothy Chen1d05bd62020-10-07 18:42:07 -070025 input keymgr_ops_e op_i,
Timothy Chen15adeee2020-09-09 15:44:35 -070026 output logic op_done_o,
27 output keymgr_op_status_e status_o,
28 output logic [ErrLastPos-1:0] error_o,
29 output logic data_valid_o,
30 output keymgr_working_state_e working_state_o,
31
32 // Data input
33 input [KeyWidth-1:0] root_key_i,
34 output keymgr_gen_out_e hw_sel_o,
35 output keymgr_stage_e stage_sel_o,
36
37 // KMAC ctrl interface
38 output logic adv_en_o,
39 output logic id_en_o,
40 output logic gen_en_o,
41 output logic [Shares-1:0][KeyWidth-1:0] key_o,
42 output logic load_key_o,
43 input kmac_done_i,
44 input kmac_input_invalid_i, // asserted when selected data fails criteria check
45 input kmac_fsm_err_i, // asserted when kmac fsm reaches unexpected state
Timothy Cheneaa3f2b2020-10-27 17:10:15 -070046 input kmac_op_err_i, // asserted when kmac itself reports an error
Timothy Chen15adeee2020-09-09 15:44:35 -070047 input kmac_cmd_err_i, // asserted when more than one command given to kmac
48 input [Shares-1:0][KeyWidth-1:0] kmac_data_i
49);
50 localparam int EntropyWidth = LfsrWidth / 2;
51 localparam int EntropyRounds = KeyWidth / EntropyWidth;
52 localparam int CntWidth = $clog2(EntropyRounds + 1);
53
54 keymgr_working_state_e state_q, state_d;
55 logic [Shares-1:0][EntropyRounds-1:0][EntropyWidth-1:0] key_state_q, key_state_d;
56
57 logic [CntWidth-1:0] cnt;
58 logic cnt_en;
59 logic cnt_clr;
60 logic data_valid;
61 logic adv_en_q;
62 logic op_accepted;
63 logic invalid_op;
64
65 // disable is treated like an advanced call
66 logic advance_sel;
67 logic disable_sel;
68 logic gen_id_sel;
69 logic gen_out_sw_sel;
70 logic gen_out_hw_sel;
71 logic gen_out_sel;
72 logic gen_sel;
73
74 // something went wrong with the kmac interface operation
75 logic kmac_op_err;
76
77 assign advance_sel = op_i == OpAdvance & keymgr_en_i;
78 assign gen_id_sel = op_i == OpGenId & keymgr_en_i;
79 assign gen_out_sw_sel = op_i == OpGenSwOut & keymgr_en_i;
80 assign gen_out_hw_sel = op_i == OpGenHwOut & keymgr_en_i;
81 assign gen_out_sel = gen_out_sw_sel | gen_out_hw_sel;
82 assign gen_sel = gen_id_sel | gen_out_sel;
83
84 // disable is selected whenever a normal operation is not, and when
85 // keymgr is disabled
86 assign disable_sel = !(gen_sel | advance_sel) | !keymgr_en_i;
87
88 assign adv_en_o = op_accepted & (advance_sel | disable_sel);
89 assign id_en_o = op_accepted & gen_id_sel;
90 assign gen_en_o = op_accepted & gen_out_sel;
91 assign load_key_o = adv_en_o & !adv_en_q;
92
93 // check incoming kmac data validity
94 // also check inputs used during compute
95 assign data_valid = valid_data_chk(kmac_data_i[0]) & valid_data_chk(kmac_data_i[1])
Timothy Chen1d05bd62020-10-07 18:42:07 -070096 & !kmac_input_invalid_i & !kmac_op_err;
Timothy Chen15adeee2020-09-09 15:44:35 -070097
98 // Unlike the key state, the working state can be safely reset.
99 always_ff @(posedge clk_i or negedge rst_ni) begin
100 if (!rst_ni) begin
101 state_q <= StReset;
102 adv_en_q <= 1'b0;
103 end else begin
104 state_q <= state_d;
105 adv_en_q <= adv_en_o;
106 end
107 end
108
109 // prevents unknowns from reaching the outside world.
110 // whatever operation causes the input data select to be disabled should
111 // also not expose the key state
112 assign key_o = disable_sel ? {EntropyRounds * Shares {entropy_i}} : key_state_q;
113
114 // key state is intentionally not reset
115 always_ff @(posedge clk_i) begin
116 key_state_q <= key_state_d;
117 end
118
119 always_ff @(posedge clk_i or negedge rst_ni) begin
120 if (!rst_ni) begin
121 cnt <= '0;
122 end else if (cnt_clr) begin
123 cnt <= '0;
124 end else if (cnt_en) begin
125 cnt <= cnt + 1'b1;
126 end
127 end
128
Timothy Cheneaa3f2b2020-10-27 17:10:15 -0700129 assign kmac_op_err = kmac_cmd_err_i | kmac_fsm_err_i | kmac_op_err_i;
Timothy Chen15adeee2020-09-09 15:44:35 -0700130
131 always_comb begin
132 // persistent data
133 state_d = state_q;
134 key_state_d = key_state_q;
135
136 // locally consumed select signals
137 cnt_en = 1'b0;
138 cnt_clr = 1'b0;
139 op_accepted = 1'b0;
140 invalid_op = 1'b0;
141
142 // data update and select signals
143 hw_sel_o = HwKey;
144 stage_sel_o = Disable;
145
146 // enable prng toggling
147 prng_en_o = 1'b1;
148
Timothy Chen1d05bd62020-10-07 18:42:07 -0700149 op_done_o = 1'b0;
150 init_done_o = 1'b0;
151
Timothy Chen15adeee2020-09-09 15:44:35 -0700152 // TBD
153 // Wait for some more software feedback to see if the states remain so similar.
154 // If yes, we can merge 3 states below with some minor tweaking.
155 unique case (state_q)
156 // This state does not accept any command. Issuing any command
157 // will cause an immediate error
158 StReset: begin
159 // in reset state, don't enable entropy yet, since there are no users.
160 // long term, this should be replaced by a req/ack with csrng
161 prng_en_o = 1'b0;
162 op_done_o = op_start_i;
163 invalid_op = op_start_i;
164
Timothy Chen1d05bd62020-10-07 18:42:07 -0700165 // When initialization command is given, begin.
166 // Note, if init is called at the same time as start, it is considered
167 // an invalid command sequence.
168 if (init_i && !invalid_op && keymgr_en_i) begin
169 state_d = StWipe;
170 end else begin
171 state_d = StReset;
172 init_done_o = init_i & invalid_op;
173 end
Timothy Chen15adeee2020-09-09 15:44:35 -0700174 end
175
Timothy Chen1d05bd62020-10-07 18:42:07 -0700176 // This state does not accept any command.
Timothy Chen15adeee2020-09-09 15:44:35 -0700177 StWipe: begin
Timothy Chen15adeee2020-09-09 15:44:35 -0700178 // populate both shares with the same entropy
179 // This is the default mask
180 if (cnt < EntropyRounds) begin
181 cnt_en = 1'b1;
182 for (int i = 0; i < Shares; i++) begin
183 key_state_d[i][cnt] = entropy_i;
184 end
185 end
186 // when mask population is complete, xor the root_key into the zero share
187 // if in the future the root key is updated to 2 shares, it will direclty overwrite
188 // the values here
189 else begin
190 cnt_clr = 1'b1;
191 key_state_d[0] = key_state_q[0] ^ root_key_i;
Timothy Chen1d05bd62020-10-07 18:42:07 -0700192 init_done_o = 1'b1;
Timothy Chen15adeee2020-09-09 15:44:35 -0700193 state_d = StInit;
194 end
195 end
196
197 // Beginning from the Init state, operations are accepted.
198 // Only valid operation is advance state. If invalid command received,
199 // random data is selected for operation and no persistent state is changed.
200 StInit: begin
201 op_done_o = op_start_i & kmac_done_i;
202
203 if (op_start_i || !keymgr_en_i) begin
204 op_accepted = 1'b1;
205 stage_sel_o = !advance_sel ? Disable : Creator;
206 end
207
208 // key state is updated when it is an advance call
209 if (op_done_o && (disable_sel || kmac_op_err)) begin
210 key_state_d = kmac_data_i;
211 state_d = StDisabled;
212 end else if (op_done_o && advance_sel) begin
213 key_state_d = data_valid ? kmac_data_i : key_state_q;
214 state_d = StCreatorRootKey;
215 end else if (op_done_o) begin
216 invalid_op = 1'b1;
217 end
218 end
219
220 // all commands are valid during this stage
221 StCreatorRootKey: begin
222 op_done_o = op_start_i & kmac_done_i;
223
224 // when generating, select creator data input
225 // when advancing, select owner intermediate key as target
226 // when disabling, select random data input
227
228 if (op_start_i || !keymgr_en_i) begin
229 op_accepted = 1'b1;
230 stage_sel_o = disable_sel ? Disable :
231 advance_sel ? OwnerInt : Creator;
232 hw_sel_o = gen_out_hw_sel ? HwKey : SwKey;
233 end
234
235 // key state is updated when it is an advance call
236 if (op_done_o && (disable_sel || kmac_op_err)) begin
237 key_state_d = kmac_data_i;
238 state_d = StDisabled;
239 end else if (op_done_o && advance_sel) begin
240 key_state_d = data_valid ? kmac_data_i : key_state_q;
241 state_d = StOwnerIntKey;
242 end
243 end
244
245
246 // all commands are valid during this stage
247 StOwnerIntKey: begin
248 op_done_o = op_start_i & kmac_done_i;
249
250 // when generating, select creator data input
251 // when advancing, select owner intermediate key as target
252 // when disabling, select random data input
253 if (op_start_i || !keymgr_en_i) begin
254 op_accepted = 1'b1;
255 stage_sel_o = disable_sel ? Disable :
256 advance_sel ? Owner : OwnerInt;
257 hw_sel_o = gen_out_hw_sel ? HwKey : SwKey;
258 end
259
260 if (op_done_o && (disable_sel || kmac_op_err)) begin
261 key_state_d = kmac_data_i;
262 state_d = StDisabled;
263 end else if (op_done_o && advance_sel) begin
264 key_state_d = data_valid ? kmac_data_i : key_state_q;
265 state_d = StOwnerKey;
266 end
267 end
268
269 // all commands are valid during this stage
270 // however advance goes directly to disabled state
271 StOwnerKey: begin
272 op_done_o = op_start_i & kmac_done_i;
273
274 if (op_start_i || !keymgr_en_i) begin
275 op_accepted = 1'b1;
276 stage_sel_o = disable_sel || advance_sel ? Disable : Owner;
277 hw_sel_o = gen_out_hw_sel ? HwKey : SwKey;
278 end
279
280 // Calling advanced from ownerKey also leads to disable
281 // Thus data_valid is not checked
282 if (op_done_o && (advance_sel || disable_sel || kmac_op_err)) begin
283 key_state_d = kmac_data_i;
284 state_d = StDisabled;
285 end
286 end
287
288 // Terminal state (StDisabled is included)
289 // However, it will continue to kick off dummy transactions
290 default: begin
291 op_done_o = op_start_i & kmac_done_i;
292
293 // accept any command, but always select fake data
294 op_accepted = op_start_i;
295 stage_sel_o = Disable;
296 hw_sel_o = gen_out_hw_sel ? HwKey : SwKey;
297
Timothy Chen1d05bd62020-10-07 18:42:07 -0700298 // During disabled state, continue to update state
299 key_state_d = (op_done_o && advance_sel) ? kmac_data_i : key_state_q;
Timothy Chen15adeee2020-09-09 15:44:35 -0700300
301 // Despite accepting all commands, operations are always
302 // considered invalid in disabled state
Timothy Chen1d05bd62020-10-07 18:42:07 -0700303 // TBD this may be changed later if we decide to hide disable state from
304 // software.
305 invalid_op = op_start_i;
Timothy Chen15adeee2020-09-09 15:44:35 -0700306 end
307
308 endcase // unique case (state_q)
309 end
310
311
312 // Current working state provided for software read
313 assign working_state_o = state_q;
314
315 // if operation was never accepted (ie a generate was called in StReset / StWipe), then
316 // never update the sw / hw outputs when operation is complete
317 assign data_valid_o = op_done_o & op_accepted & data_valid & gen_sel;
318
319 // data errors are not relevant when operation was not accepted.
320 assign error_o[ErrInvalidOp] = invalid_op;
321 assign error_o[ErrInvalidCmd] = op_start_i & op_accepted & kmac_op_err;
322 assign error_o[ErrInvalidIn] = op_done_o & op_accepted & kmac_input_invalid_i;
323 assign error_o[ErrInvalidOut] = op_done_o & op_accepted & ~data_valid;
324
325 always_comb begin
326 status_o = OpIdle;
327 if (op_done_o) begin
328 status_o = |error_o ? OpDoneFail : OpDoneSuccess;
329 end else if (op_start_i) begin
330 status_o = OpWip;
331 end
332 end
333
334
335
336 ///////////////////////////////
337 // Functions
338 ///////////////////////////////
339
340 // unclear what this is supposed to be yet
341 // right now just check to see if it not all 0's and not all 1's
342 function automatic logic valid_data_chk (logic [KeyWidth-1:0] value);
343
344 return |value & ~&value;
345
346 endfunction // byte_mask
347
348endmodule