Software APIs
sphincsplus.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 
6 #include "sw/device/lib/base/status.h"
7 #include "sw/device/lib/crypto/impl/integrity.h"
8 #include "sw/device/lib/crypto/impl/keyblob.h"
11 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
12 #include "sw/device/lib/ujson/ujson.h"
13 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/verify.h"
14 #include "sw/device/tests/crypto/cryptotest/json/sphincsplus_commands.h"
15 
16 status_t handle_sphincsplus_verify(ujson_t *uj) {
17  // Declare SPHINCS+ parameter ujson deserializer types
18  cryptotest_sphincsplus_hash_alg_t uj_hash_alg;
19  cryptotest_sphincsplus_public_key_t uj_public_key;
20  cryptotest_sphincsplus_message_t uj_message;
21  cryptotest_sphincsplus_signature_t uj_signature;
22 
23  // Deserialize ujson byte stream into SPHINCS+ parameters
24  TRY(ujson_deserialize_cryptotest_sphincsplus_hash_alg_t(uj, &uj_hash_alg));
25  TRY(ujson_deserialize_cryptotest_sphincsplus_public_key_t(uj,
26  &uj_public_key));
27  TRY(ujson_deserialize_cryptotest_sphincsplus_message_t(uj, &uj_message));
28  TRY(ujson_deserialize_cryptotest_sphincsplus_signature_t(uj, &uj_signature));
29 
30  if (uj_public_key.public_len != kSpxVerifyPkBytes) {
31  LOG_ERROR("Incorrect public key length: (expected = %d, got = %d)",
32  kSpxVerifyPkBytes, uj_public_key.public_len);
33  return INVALID_ARGUMENT();
34  }
35  if (uj_signature.signature_len != kSpxVerifySigBytes) {
36  LOG_ERROR("Incorrect signature length: (expected = %d, got = %d)",
37  kSpxVerifySigBytes, uj_signature.signature_len);
38  return INVALID_ARGUMENT();
39  }
40 
41  switch (uj_hash_alg) {
42  case kCryptotestSphincsPlusHashAlgSha256:
43  break;
44  case kCryptotestSphincsPlusHashAlgShake256:
45  LOG_ERROR("SPHINCS+ SHAKE-256 is currently unsupported.");
46  return INVALID_ARGUMENT();
47  default:
48  LOG_ERROR("Unrecognized SPHINCS+ hash mode: %d", uj_hash_alg);
49  return INVALID_ARGUMENT();
50  }
51  uint32_t exp_root[kSpxVerifyRootNumWords];
52  spx_public_key_root((uint32_t *)uj_public_key.public, exp_root);
53  uint32_t act_root[kSpxVerifyRootNumWords];
54  rom_error_t error =
55  spx_verify((uint32_t *)uj_signature.signature, NULL, 0, NULL, 0, NULL, 0,
56  (uint8_t *)uj_message.message, uj_message.message_len,
57  (uint32_t *)uj_public_key.public, act_root);
58  cryptotest_sphincsplus_verify_output_t uj_output;
59  switch (error) {
60  case kErrorOk:
61  uj_output = kCryptotestSphincsPlusVerifyOutputSuccess;
62  for (size_t i = 0; i < kSpxVerifyRootNumWords; i++) {
63  if (exp_root[i] != act_root[i]) {
64  uj_output = kCryptotestSphincsPlusVerifyOutputFailure;
65  break;
66  }
67  }
68  RESP_OK(ujson_serialize_cryptotest_sphincsplus_verify_output_t, uj,
69  &uj_output);
70  break;
71  case kErrorSigverifyBadSpxSignature:
73  case kErrorSigverifyBadSpxKey:
74  uj_output = kCryptotestSphincsPlusVerifyOutputFailure;
75  // Respond "failure" if the IUT reports an invalid argument
76  RESP_OK(ujson_serialize_cryptotest_sphincsplus_verify_output_t, uj,
77  &uj_output);
78  break;
79  default:
80  LOG_ERROR(
81  "Unexpected error value returned from spx_verify: "
82  "0x%x",
83  error);
84  return INTERNAL();
85  }
86  return OK_STATUS(0);
87 }
88 
89 status_t handle_sphincsplus(ujson_t *uj) {
90  cryptotest_sphincsplus_operation_t uj_op;
91  TRY(ujson_deserialize_cryptotest_sphincsplus_operation_t(uj, &uj_op));
92  switch (uj_op) {
93  case kCryptotestSphincsPlusOperationVerify:
94  return handle_sphincsplus_verify(uj);
95  default:
96  LOG_ERROR("Unsupported SPHINCS+ operation: %d", uj_op);
97  return INVALID_ARGUMENT();
98  }
99 }