Software APIs
sigverify_cryptotest.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 #include <stdbool.h>
5 
6 #include "sw/device/lib/base/status.h"
7 #include "sw/device/lib/testing/test_framework/check.h"
9 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
10 #include "sw/device/lib/ujson/ujson.h"
11 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
12 #include "sw/device/silicon_creator/lib/otbn_boot_services.h"
13 #include "sw/device/silicon_creator/lib/sigverify/ecdsa_p256_key.h"
14 #include "sw/device/silicon_creator/lib/sigverify/ecdsa_p256_verify.h"
15 #include "sw/device/tests/crypto/cryptotest/json/ecdsa_commands.h"
16 
17 // Include commands
18 #include "sw/device/tests/crypto/cryptotest/json/commands.h"
19 #include "sw/device/tests/crypto/cryptotest/json/ecdsa_commands.h"
20 
22 
23 OTTF_DEFINE_TEST_CONFIG(.console.type = kOttfConsoleSpiDevice,
24  .console.base_addr = TOP_EARLGREY_SPI_DEVICE_BASE_ADDR,
25  .console.test_may_clobber = false, );
26 
27 bool ecdsa_p256_params_set(cryptotest_ecdsa_coordinate_t uj_qx,
28  cryptotest_ecdsa_coordinate_t uj_qy,
29  cryptotest_ecdsa_signature_t uj_signature,
30  ecdsa_p256_public_key_t *public_key,
31  ecdsa_p256_signature_t *signature_p256) {
32  if (uj_qx.coordinate_len > kEcdsaP256SignatureComponentBytes) {
33  LOG_ERROR(
34  "Coordinate value qx too large for P256 (have = %d bytes, max = %d "
35  "bytes)",
36  uj_qx.coordinate_len, kEcdsaP256SignatureComponentBytes);
37  return false;
38  }
39  if (uj_qy.coordinate_len > kEcdsaP256SignatureComponentBytes) {
40  LOG_ERROR(
41  "Coordinate value qy too large for P256 (have = %d bytes, max = %d "
42  "bytes)",
43  uj_qy.coordinate_len, kEcdsaP256SignatureComponentBytes);
44  return false;
45  }
46  memset(public_key->x, 0, kEcdsaP256SignatureComponentBytes);
47  memcpy(public_key->x, uj_qx.coordinate, uj_qx.coordinate_len);
48  memset(public_key->y, 0, kEcdsaP256SignatureComponentBytes);
49  memcpy(public_key->y, uj_qy.coordinate, uj_qy.coordinate_len);
50 
51  if (uj_signature.r_len > kEcdsaP256SignatureComponentBytes) {
52  LOG_ERROR(
53  "Signature r value too large for P256 (have = %d bytes, max = %d "
54  "bytes)",
55  uj_signature.r_len, kEcdsaP256SignatureComponentBytes);
56  return false;
57  }
58  if (uj_signature.s_len > kEcdsaP256SignatureComponentBytes) {
59  LOG_ERROR(
60  "Signature s value too large for P256 (have = %d bytes, max = %d "
61  "bytes)",
62  uj_signature.s_len, kEcdsaP256SignatureComponentBytes);
63  return false;
64  }
65  memset(signature_p256->r, 0, kEcdsaP256SignatureComponentBytes);
66  memcpy(signature_p256->r, uj_signature.r, uj_signature.r_len);
67  memset(signature_p256->s, 0, kEcdsaP256SignatureComponentBytes);
68  memcpy(signature_p256->s, uj_signature.s, uj_signature.s_len);
69  return true;
70 }
71 
72 status_t sigverify_p256_to_status(ujson_t *uj,
73  const ecdsa_p256_signature_t *signature,
74  const ecdsa_p256_public_key_t *public_key,
75  hmac_digest_t *digest) {
76  uint32_t flash_exec = 0;
77  rom_error_t result =
78  sigverify_ecdsa_p256_verify(signature, public_key, digest, &flash_exec);
79 
80  hardened_bool_t verification_result = kHardenedBoolFalse;
81  if (result == kErrorOk && flash_exec == kSigverifyEcdsaSuccess) {
82  verification_result = kHardenedBoolTrue;
83  }
84 
85  cryptotest_ecdsa_verify_output_t uj_output;
86  switch (verification_result) {
87  case kHardenedBoolFalse:
88  uj_output = kCryptotestEcdsaVerifyOutputFailure;
89  break;
90  case kHardenedBoolTrue:
91  uj_output = kCryptotestEcdsaVerifyOutputSuccess;
92  break;
93  default:
94  LOG_ERROR("Unexpected result value from otcrypto_ecdsa_verify: %d",
95  verification_result);
96  return INTERNAL();
97  }
98  RESP_OK(ujson_serialize_cryptotest_ecdsa_verify_output_t, uj, &uj_output);
99  return OK_STATUS(0);
100 }
101 
102 status_t sigverify_ecdsa_process_command(ujson_t *uj) {
103  // Declare ECDSA parameter ujson deserializer types
104  cryptotest_ecdsa_operation_t uj_op;
105  cryptotest_ecdsa_hash_alg_t uj_hash_alg;
106  cryptotest_ecdsa_curve_t uj_curve;
107  cryptotest_ecdsa_message_t uj_message;
108  cryptotest_ecdsa_signature_t uj_signature;
109  cryptotest_ecdsa_coordinate_t uj_qx;
110  cryptotest_ecdsa_coordinate_t uj_qy;
111  cryptotest_ecdsa_private_key_t uj_private_key;
112 
113  // Deserialize ujson byte stream into ECDSA parameters
114  TRY(ujson_deserialize_cryptotest_ecdsa_operation_t(uj, &uj_op));
115  TRY(ujson_deserialize_cryptotest_ecdsa_hash_alg_t(uj, &uj_hash_alg));
116  TRY(ujson_deserialize_cryptotest_ecdsa_curve_t(uj, &uj_curve));
117  TRY(ujson_deserialize_cryptotest_ecdsa_message_t(uj, &uj_message));
118  TRY(ujson_deserialize_cryptotest_ecdsa_signature_t(uj, &uj_signature));
119  TRY(ujson_deserialize_cryptotest_ecdsa_coordinate_t(uj, &uj_qx));
120  TRY(ujson_deserialize_cryptotest_ecdsa_coordinate_t(uj, &uj_qy));
121  TRY(ujson_deserialize_cryptotest_ecdsa_private_key_t(uj, &uj_private_key));
122 
123  ecdsa_p256_public_key_t public_key;
124  ecdsa_p256_signature_t signature_p256;
125  switch (uj_curve) {
126  case kCryptotestEcdsaCurveP256:
127  if (!ecdsa_p256_params_set(uj_qx, uj_qy, uj_signature, &public_key,
128  &signature_p256)) {
129  return INVALID_ARGUMENT();
130  }
131  break;
132  default:
133  LOG_ERROR("Unsupported ECC curve: %d", uj_curve);
134  return INVALID_ARGUMENT();
135  }
136 
137  switch (uj_hash_alg) {
138  case kCryptotestEcdsaHashAlgSha256:
139  break;
140  default:
141  LOG_ERROR("Unsupported ECDSA hash mode: %d", uj_hash_alg);
142  return INVALID_ARGUMENT();
143  }
144 
145  hmac_digest_t digest_be;
146  memset(digest_be.digest, 0, kHmacDigestNumWords * sizeof(uint32_t));
147  memcpy(digest_be.digest, uj_message.input, uj_message.input_len);
148 
149  hmac_digest_t digest;
150  for (size_t i = 0; launder32(i) < kHmacDigestNumWords; i++) {
151  digest.digest[i] =
152  __builtin_bswap32(digest_be.digest[kHmacDigestNumWords - 1 - i]);
153  }
154 
155  switch (uj_op) {
156  case kCryptotestEcdsaOperationVerify: {
157  return sigverify_p256_to_status(uj, &signature_p256, &public_key,
158  &digest);
159  }
160  default:
161  LOG_ERROR("Usupported ECDSA operation: %d", uj_op);
162  return INVALID_ARGUMENT();
163  }
164  return OK_STATUS(0);
165 }
166 
167 status_t process_cmd(ujson_t *uj) {
168  while (true) {
169  cryptotest_cmd_t cmd;
170  TRY(ujson_deserialize_cryptotest_cmd_t(uj, &cmd));
171  switch (cmd) {
172  case kCryptotestCommandEcdsa:
173  RESP_ERR(uj, sigverify_ecdsa_process_command(uj));
174  break;
175  default:
176  LOG_ERROR("Unsupported command: %d", cmd);
177  RESP_ERR(uj, INVALID_ARGUMENT());
178  }
179  }
180 
181  return OK_STATUS(0);
182 }
183 
184 bool test_main(void) {
185  CHECK(otbn_boot_app_load() == kErrorOk);
186 
187  ujson_t uj = ujson_ottf_console();
188  return status_ok(process_cmd(&uj));
189 }