Software APIs
sha3_sca.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/tests/penetrationtests/firmware/sca/sha3_sca.h"
6 
8 #include "sw/device/lib/base/status.h"
11 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
12 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
13 #include "sw/device/lib/ujson/ujson.h"
14 #include "sw/device/sca/lib/prng.h"
15 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
16 #include "sw/device/tests/penetrationtests/json/commands.h"
17 #include "sw/device/tests/penetrationtests/json/sha3_sca_commands.h"
18 
20 #include "kmac_regs.h"
21 
22 enum {
23  /**
24  * Key length in bytes.
25  */
26  kKeyLength = 16,
27  /**
28  * Message length in bytes.
29  */
30  kMessageLength = 16,
31  /**
32  * Digest length in 32-bit words.
33  */
34  kDigestLength = 8,
35  /**
36  * Number of cycles (at `kClockFreqCpuHz`) that Ibex should sleep to minimize
37  * noise during SHA3 operations. Caution: This number should be chosen to
38  * provide enough time. Otherwise, Ibex might wake up while SHA3 is still busy
39  * and disturb the capture. Currently, we use a start trigger delay of 320
40  * clock cycles and the scope captures 120 clock cycles at kClockFreqCpuHz.
41  * On the scope side, an offset of 320 clock cycles can be used to ignore the
42  * start trigger delay for the PROCESS command.
43  */
44  kIbexSha3SleepCycles = 1060,
45  /**
46  * Number of cycles (at `kClockFreqCpuHz`) that Ibex should sleep to minimize
47  * noise during loading and hashing the message.
48  */
49  kIbexLoadHashMessageSleepCycles = 500,
50  /**
51  * Max number of traces per batch.
52  */
53  kNumBatchOpsMax = 128,
54 };
55 
56 /**
57  * Enable FPGA mode.
58  */
59 static bool fpga_mode = false;
60 
61 /**
62  * A handle to KMAC.
63  */
64 static dif_kmac_t kmac;
65 
66 /**
67  * The KMAC config.
68  */
69 static dif_kmac_config_t config = (dif_kmac_config_t){
70  .entropy_mode = kDifKmacEntropyModeSoftware,
71  .entropy_fast_process = kDifToggleDisabled,
72  .entropy_seed = {0xb153e3fe, 0x09596819, 0x3e85a6e8, 0xb6dcdaba, 0x50dc409c,
73  0x11e1ebd1},
74  .message_big_endian = kDifToggleDisabled,
75  .output_big_endian = kDifToggleDisabled,
76  .sideload = kDifToggleDisabled,
77  .msg_mask = kDifToggleEnabled,
78 };
79 
80 /**
81  * KMAC operation state.
82  */
83 static dif_kmac_operation_state_t kmac_operation_state;
84 
85 /**
86  * SHA3 fixed message.
87  *
88  * Used for caching the fixed key in the 't' (set fixed key) command packet
89  * until it is used when handling a 'b' (batch capture) command.
90  */
91 uint8_t message_fixed[kMessageLength];
92 
93 /**
94  * Fixed-message indicator.
95  *
96  * Used in the 'b' (batch capture) command for indicating whether to use fixed
97  * or random message.
98  */
99 static bool run_fixed = false;
100 
101 /**
102  * An array of messages to be used in a batch
103  */
104 uint8_t sha3_batch_messages[kNumBatchOpsMax][kMessageLength];
105 
106 /**
107  * Blocks until KMAC is idle.
108  */
109 static void kmac_block_until_idle(void) {
110  // TODO(#7842): Remove when `dif_kmac_get_status()` is implemented.
111  uint32_t reg;
112  do {
113  reg = mmio_region_read32(kmac.base_addr, KMAC_STATUS_REG_OFFSET);
114  } while (!bitfield_bit32_read(reg, KMAC_STATUS_SHA3_IDLE_BIT));
115 }
116 
117 /**
118  * Resets KMAC to idle state.
119  */
120 static void kmac_reset(void) {
121  // TODO(#7842): Remove when `dif_kmac_reset()` is implemented.
122  mmio_region_write32(
123  kmac.base_addr, KMAC_CMD_REG_OFFSET,
124  bitfield_field32_write(0, KMAC_CMD_CMD_FIELD, KMAC_CMD_CMD_VALUE_DONE));
125  kmac_block_until_idle();
126 }
127 
128 /**
129  * Report whether the hardware is currently idle.
130  *
131  * If the hardware is not idle then the `CFG` register is locked.
132  *
133  * @param params Hardware parameters.
134  * @returns Whether the hardware is currently idle or not.
135  */
136 static bool is_state_idle(void) {
137  uint32_t reg = mmio_region_read32(kmac.base_addr, KMAC_STATUS_REG_OFFSET);
138  return bitfield_bit32_read(reg, KMAC_STATUS_SHA3_IDLE_BIT);
139 }
140 
141 /**
142  * Calculate the rate (r) in bits from the given security level.
143  *
144  * @param security_level Security level in bits.
145  * @returns Rate in bits.
146  */
147 static uint32_t calculate_rate_bits(uint32_t security_level) {
148  // Formula for the rate in bits is:
149  //
150  // r = 1600 - c
151  //
152  // Where c is the capacity (the security level in bits multiplied by two).
153  return 1600 - 2 * security_level;
154 }
155 
156 /**
157  * Starts KMAC/SHA3 message without sending START command.
158  *
159  * Based on dif_kmac_mode_sha3_start().
160  *
161  * Unlike dif_kmac_mode_sha3_start(), this function doesn't provide the START
162  * command to the hardware.
163  */
164 static dif_result_t sha3_msg_start(dif_kmac_mode_sha3_t mode) {
165  // Set kstrength and calculate rate (r) and digest length (d) in 32-bit
166  // words.
167  uint32_t kstrength;
168  switch (mode) {
170  kstrength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L224;
171  kmac_operation_state.offset = 0;
172  kmac_operation_state.r = calculate_rate_bits(224) / 32;
173  kmac_operation_state.d = 224 / 32;
174  break;
176  kstrength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L256;
177  kmac_operation_state.offset = 0;
178  kmac_operation_state.r = calculate_rate_bits(256) / 32;
179  kmac_operation_state.d = 256 / 32;
180  break;
182  kstrength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L384;
183  kmac_operation_state.offset = 0;
184  kmac_operation_state.r = calculate_rate_bits(384) / 32;
185  kmac_operation_state.d = 384 / 32;
186  break;
188  kstrength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L512;
189  kmac_operation_state.offset = 0;
190  kmac_operation_state.r = calculate_rate_bits(512) / 32;
191  kmac_operation_state.d = 512 / 32;
192  break;
193  default:
194  return kDifBadArg;
195  }
196 
197  // Hardware must be idle to start an operation.
198  if (!is_state_idle()) {
199  return kDifError;
200  }
201 
202  kmac_operation_state.squeezing = false;
203  kmac_operation_state.append_d = false;
204 
205  // Configure SHA-3 mode with the given strength.
206  uint32_t cfg_reg =
207  mmio_region_read32(kmac.base_addr, KMAC_CFG_SHADOWED_REG_OFFSET);
208  cfg_reg = bitfield_field32_write(cfg_reg, KMAC_CFG_SHADOWED_KSTRENGTH_FIELD,
209  kstrength);
210  cfg_reg = bitfield_field32_write(cfg_reg, KMAC_CFG_SHADOWED_MODE_FIELD,
211  KMAC_CFG_SHADOWED_MODE_VALUE_SHA3);
212  mmio_region_write32(kmac.base_addr, KMAC_CFG_SHADOWED_REG_OFFSET, cfg_reg);
213  mmio_region_write32(kmac.base_addr, KMAC_CFG_SHADOWED_REG_OFFSET, cfg_reg);
214 
215  return kDifOk;
216 }
217 
218 /**
219  * Writes the message including its length to the message FIFO.
220  *
221  * Based on dif_kmac_absorb().
222  *
223  * Unlike dif_kmac_absorb(), this function 1) doesn't require the hardware
224  * to enter the 'absorb' state before writing the message into the message
225  * FIFO, and 2) appends the output length afterwards (normally done as
226  * part of dif_kmac_squeeze()).
227  */
228 static dif_result_t sha3_msg_write(const void *msg, size_t msg_len,
229  size_t *processed) {
230  // Set the number of bytes processed to 0.
231  if (processed != NULL) {
232  *processed = 0;
233  }
234 
235  if (msg == NULL && msg_len != 0) {
236  return kDifBadArg;
237  }
238 
239  // Check that an operation has been started.
240  if (kmac_operation_state.r == 0) {
241  return kDifError;
242  }
243 
244  // Copy the message one byte at a time.
245  // This could be sped up copying a word at a time but be careful
246  // about message endianness (e.g. only copy a word at a time when in
247  // little-endian mode).
248  for (size_t i = 0; i < msg_len; ++i) {
249  mmio_region_write8(kmac.base_addr, KMAC_MSG_FIFO_REG_OFFSET,
250  ((const uint8_t *)msg)[i]);
251  }
252 
253  if (processed != NULL) {
254  *processed = msg_len;
255  }
256  kmac_operation_state.squeezing = true;
257 
258  return kDifOk;
259 }
260 
261 /**
262  * Starts actual processing of a previously provided message.
263  *
264  * This function issues a PROCESS command.
265  */
266 static void kmac_process_cmd(void) {
267  // Issue PROCESS command.
268  uint32_t cmd_reg =
269  bitfield_field32_write(0, KMAC_CMD_CMD_FIELD, KMAC_CMD_CMD_VALUE_PROCESS);
270  mmio_region_write32(kmac.base_addr, KMAC_CMD_REG_OFFSET, cmd_reg);
271 }
272 
273 /**
274  * Prepare to receive message via the FIFO.
275  *
276  * This function issues a START command.
277  */
278 static void kmac_start_cmd(void) {
279  // Issue START command.
280  uint32_t cmd_reg =
281  bitfield_field32_write(0, KMAC_CMD_CMD_FIELD, KMAC_CMD_CMD_VALUE_START);
282  mmio_region_write32(kmac.base_addr, KMAC_CMD_REG_OFFSET, cmd_reg);
283 }
284 
285 /**
286  * Starts actual processing of a previously provided message.
287  *
288  * This function issues a START command directly followed by a PROCESS command.
289  */
290 static void kmac_start_process_cmd(void) {
291  // Issue START command.
292  kmac_start_cmd();
293 
294  // Issue PROCESS command.
295  kmac_process_cmd();
296 }
297 
298 /**
299  * Waits until the hardware enters the 'squeeze' state.
300  *
301  * If the hardware enters the `squeeze` state, this means the output state is
302  * valid and can be read by software.
303  */
304 static void kmac_msg_done(void) {
305  // TODO(#7841, #7842): Remove when we finalize the way we capture traces.
306  uint32_t reg;
307  do {
308  reg = mmio_region_read32(kmac.base_addr, KMAC_STATUS_REG_OFFSET);
309  } while (!bitfield_bit32_read(reg, KMAC_STATUS_SHA3_SQUEEZE_BIT));
310 }
311 
312 /**
313  * Reads the digest from the hardware.
314  *
315  * Based on dif_kmac_squeeze().
316  *
317  * Unlike dif_kmac_squeeze(), this function 1) doesn't wait until the hardware
318  * enters the 'squeeze' state, 2) doesn't append the output length, 3) doesn't
319  * support the generation of more state.
320  */
321 static dif_result_t sha3_get_digest(uint32_t *out, size_t len) {
322  if (out == NULL && len != 0) {
323  return kDifBadArg;
324  }
325 
326  while (len > 0) {
327  size_t n = len;
328  size_t remaining = kmac_operation_state.r - kmac_operation_state.offset;
329  if (kmac_operation_state.d != 0 &&
330  kmac_operation_state.d < kmac_operation_state.r) {
331  remaining = kmac_operation_state.d - kmac_operation_state.offset;
332  }
333  if (n > remaining) {
334  n = remaining;
335  }
336  if (n == 0) {
337  // Normally, the hardware would now have to generate more state. But
338  // since at this point, the power measurement is already stopped, we don't
339  // support that here.
340  return kDifError;
341  }
342 
343  ptrdiff_t offset =
344  KMAC_STATE_REG_OFFSET +
345  (ptrdiff_t)kmac_operation_state.offset * (ptrdiff_t)sizeof(uint32_t);
346  for (size_t i = 0; i < n; ++i) {
347  // Read both shares from state register and combine using XOR.
348  uint32_t share0 = mmio_region_read32(kmac.base_addr, offset);
349  uint32_t share1 =
350  mmio_region_read32(kmac.base_addr, offset + kDifKmacStateShareOffset);
351  *out++ = share0 ^ share1;
352  offset += sizeof(uint32_t);
353  }
354  kmac_operation_state.offset += n;
355  len -= n;
356  }
357  return kDifOk;
358 }
359 
360 /**
361  * Disables/Enables masking in the KMAC/SHA3 peripheral.
362  *
363  * This function configures KMAC/SHA3 with the appropriate mask setting.
364  */
365 status_t handle_sha3_sca_disable_masking(ujson_t *uj) {
366  cryptotest_sha3_sca_masks_off_t uj_data;
367  TRY(ujson_deserialize_cryptotest_sha3_sca_masks_off_t(uj, &uj_data));
368 
369  TRY(dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
370 
371  if (uj_data.masks_off == 0x01) {
373  config.msg_mask = kDifToggleDisabled;
374  } else {
376  config.msg_mask = kDifToggleEnabled;
377  }
378  TRY(dif_kmac_configure(&kmac, config));
379 
380  kmac_block_until_idle();
381  // Acknowledge the command. This is crucial to be in sync with the host.
382  cryptotest_sha3_sca_status_t uj_status;
383  uj_status.status = 0;
384  RESP_OK(ujson_serialize_cryptotest_sha3_sca_status_t, uj, &uj_status);
385 
386  return OK_STATUS();
387 }
388 
389 /**
390  * Absorbs a message without a customization string. Arms & disarms the trigger
391  * before and after the PROCESS command is issued.
392  *
393  * @param msg Message.
394  * @param msg_len Message length.
395  */
396 sha3_sca_error_t sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
397  // Start a new message.
398  if (sha3_msg_start(kDifKmacModeSha3Len256) != kDifOk) {
399  return sha3ScaAborted;
400  }
401 
402  if (fpga_mode == false) {
403  // Start command. On the chip, we need to first issue a START command
404  // before writing to the message FIFO.
405  kmac_start_cmd();
406  }
407 
408  // Write data to message FIFO.
409  if (sha3_msg_write(msg, msg_len, NULL) != kDifOk) {
410  return sha3ScaAborted;
411  }
412 
413  if (fpga_mode) {
414  // Start the SHA3 processing (this triggers the capture) and go to sleep.
415  // Using the SecCmdDelay hardware parameter, the KMAC unit is
416  // configured to start operation 320 cycles after receiving the START and
417  // PROC commands. This allows Ibex to go to sleep in order to not disturb
418  // the capture.
419  pentest_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles, true,
420  false);
421  } else {
422  // On the chip, issue a PROCESS command to start operation and put Ibex
423  // into sleep.
424  pentest_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles,
425  true, false);
426  }
427 
428  return sha3ScaOk;
429 }
430 
431 /**
432  * Absorb command handler.
433  *
434  * Absorbs the given message without a customization string,
435  * and sends the digest over UART.
436  *
437  * The uJSON data contains:
438  * - msg: Message.
439  * - msg_length: Message length.
440  * @param uj The received uJSON data.
441  */
442 status_t handle_sha3_sca_single_absorb(ujson_t *uj) {
443  cryptotest_sha3_sca_msg_t uj_msg;
444  TRY(ujson_deserialize_cryptotest_sha3_sca_msg_t(uj, &uj_msg));
445  if (uj_msg.msg_length != kMessageLength) {
446  return OUT_OF_RANGE();
447  }
448 
449  // Start the operation.
450  if (sha3_serial_absorb(uj_msg.msg, uj_msg.msg_length) != sha3ScaOk) {
451  return ABORTED();
452  }
453 
454  // Check KMAC has finished processing the message.
455  kmac_msg_done();
456 
457  // Read the digest and send it to the host for verification.
458  uint32_t out[kDigestLength];
459  if (sha3_get_digest(out, kDigestLength) != kDifOk) {
460  return ABORTED();
461  }
462  cryptotest_sha3_sca_batch_digest_t uj_output;
463  memcpy(uj_output.batch_digest, (uint8_t *)out, kDigestLength * 4);
464  RESP_OK(ujson_serialize_cryptotest_sha3_sca_batch_digest_t, uj, &uj_output);
465 
466  // Reset before the next absorb since KMAC must be idle before starting
467  // another absorb.
468  kmac_reset();
469 
470  return OK_STATUS();
471 }
472 
473 /**
474  * Fixed message set command handler.
475  *
476  * Set the fixed message.
477  *
478  * The uJSON data contains:
479  * - msg: The message to set.
480  * - msg_length: The length of the message.
481  *
482  * @param uj The received uJSON data.
483  */
484 status_t handle_sha3_sca_fixed_message_set(ujson_t *uj) {
485  cryptotest_sha3_sca_msg_t uj_msg;
486  TRY(ujson_deserialize_cryptotest_sha3_sca_msg_t(uj, &uj_msg));
487 
488  if (uj_msg.msg_length != kMessageLength) {
489  return OUT_OF_RANGE();
490  }
491 
492  memcpy(message_fixed, uj_msg.msg, uj_msg.msg_length);
493 
494  return OK_STATUS();
495 }
496 
497 /**
498  * Batch command handler.
499  *
500  * Start batch mode.
501  *
502  * The uJSON data contains:
503  * - data: The number of encryptions.
504  *
505  * @param uj The received uJSON data.
506  */
507 status_t handle_sha3_sca_batch(ujson_t *uj) {
508  penetrationtest_num_enc_t uj_data;
509  TRY(ujson_deserialize_penetrationtest_num_enc_t(uj, &uj_data));
510 
511  uint32_t out[kDigestLength];
512  uint32_t batch_digest[kDigestLength];
513  uint8_t dummy_message[kMessageLength];
514 
515  for (uint32_t j = 0; j < kDigestLength; ++j) {
516  batch_digest[j] = 0;
517  }
518 
519  for (uint32_t i = 0; i < uj_data.num_enc; ++i) {
520  if (run_fixed) {
521  memcpy(sha3_batch_messages[i], message_fixed, kMessageLength);
522  } else {
523  prng_rand_bytes(sha3_batch_messages[i], kMessageLength);
524  }
525  prng_rand_bytes(dummy_message, kMessageLength);
526  run_fixed = dummy_message[0] & 0x1;
527  }
528 
529  for (uint32_t i = 0; i < uj_data.num_enc; ++i) {
530  kmac_reset();
531 
532  if (sha3_serial_absorb(sha3_batch_messages[i], kMessageLength) !=
533  sha3ScaOk) {
534  return ABORTED();
535  }
536 
537  kmac_msg_done();
538  if (sha3_get_digest(out, kDigestLength) != kDifOk) {
539  return ABORTED();
540  }
541 
542  // The correctness of each batch is verified by computing and sending
543  // the batch digest. This digest is computed by XORing all outputs of
544  // the batch.
545  for (uint32_t j = 0; j < kDigestLength; ++j) {
546  batch_digest[j] ^= out[j];
547  }
548  }
549 
550  // Acknowledge the batch command. This is crucial to be in sync with the host
551  cryptotest_sha3_sca_status_t uj_status;
552  uj_status.status = 0;
553  RESP_OK(ujson_serialize_cryptotest_sha3_sca_status_t, uj, &uj_status);
554  // Send the batch digest to the host for verification.
555  cryptotest_sha3_sca_batch_digest_t uj_output;
556  memcpy(uj_output.batch_digest, (uint8_t *)batch_digest, kDigestLength * 4);
557  RESP_OK(ujson_serialize_cryptotest_sha3_sca_batch_digest_t, uj, &uj_output);
558 
559  return OK_STATUS();
560 }
561 
562 /**
563  * Seed lfsr command handler.
564  *
565  * This function only supports 4-byte seeds.
566  *
567  * The uJSON data contains:
568  * - seed: A buffer holding the seed.
569  *
570  * @param uj The received uJSON data.
571  */
572 status_t handle_sha3_pentest_seed_lfsr(ujson_t *uj) {
573  cryptotest_sha3_sca_lfsr_t uj_lfsr_data;
574  TRY(ujson_deserialize_cryptotest_sha3_sca_lfsr_t(uj, &uj_lfsr_data));
575  pentest_seed_lfsr(read_32(uj_lfsr_data.seed), kPentestLfsrMasking);
576 
577  return OK_STATUS();
578 }
579 
580 /**
581  * Init command handler.
582  *
583  * Initializes the KMAC peripheral and setups the trigger. Configures KMAC to
584  * use software entropy.
585  *
586  * @param uj The received uJSON data.
587  */
588 status_t handle_sha3_pentest_init(ujson_t *uj) {
589  // Read mode. FPGA or discrete.
590  cryptotest_sha3_sca_fpga_mode_t uj_data;
591  TRY(ujson_deserialize_cryptotest_sha3_sca_fpga_mode_t(uj, &uj_data));
592  if (uj_data.fpga_mode == 0x01) {
593  fpga_mode = true;
594  }
595 
596  penetrationtest_cpuctrl_t uj_cpuctrl;
597  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_cpuctrl));
598 
599  pentest_init(kPentestTriggerSourceKmac,
600  kPentestPeripheralIoDiv4 | kPentestPeripheralKmac);
601 
602  TRY(dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
603 
604  TRY(dif_kmac_configure(&kmac, config));
605 
606  kmac_block_until_idle();
607 
608  // Configure the CPU for the pentest.
609  penetrationtest_device_info_t uj_output;
610  TRY(pentest_configure_cpu(
611  uj_cpuctrl.icache_disable, uj_cpuctrl.dummy_instr_disable,
612  uj_cpuctrl.enable_jittery_clock, uj_cpuctrl.enable_sram_readback,
613  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
614  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
615  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
616 
617  // Read device ID and return to host.
618  TRY(pentest_read_device_id(uj_output.device_id));
619  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
620 
621  return OK_STATUS();
622 }
623 
624 /**
625  * SHA SCA command handler.
626  *
627  * Command handler for the SHA SCA command.
628  *
629  * @param uj The received uJSON data.
630  */
631 status_t handle_sha3_sca(ujson_t *uj) {
632  sha3_sca_subcommand_t cmd;
633  TRY(ujson_deserialize_sha3_sca_subcommand_t(uj, &cmd));
634  switch (cmd) {
635  case kSha3ScaSubcommandInit:
636  return handle_sha3_pentest_init(uj);
637  case kSha3ScaSubcommandSingleAbsorb:
638  return handle_sha3_sca_single_absorb(uj);
639  case kSha3ScaSubcommandBatch:
640  return handle_sha3_sca_batch(uj);
641  case kSha3ScaSubcommandFixedMessageSet:
642  return handle_sha3_sca_fixed_message_set(uj);
643  case kSha3ScaSubcommandSeedLfsr:
644  return handle_sha3_pentest_seed_lfsr(uj);
645  case kSha3ScaSubcommandDisableMasking:
646  return handle_sha3_sca_disable_masking(uj);
647  default:
648  LOG_ERROR("Unrecognized SHA SCA FI subcommand: %d", cmd);
649  return INVALID_ARGUMENT();
650  }
651  return OK_STATUS();
652 }