Software APIs
ecdsa_p256_functest.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/lib/crypto/drivers/otbn.h"
6 #include "sw/device/lib/crypto/impl/integrity.h"
7 #include "sw/device/lib/crypto/impl/keyblob.h"
12 #include "sw/device/lib/testing/entropy_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
16 enum {
17  /* Number of 32-bit words in a P-256 public key. */
18  kP256PublicKeyWords = 512 / 32,
19  /* Number of 32-bit words in a P-256 signature. */
20  kP256SignatureWords = 512 / 32,
21  /* Number of bytes in a P-256 private key. */
22  kP256PrivateKeyBytes = 256 / 8,
23 };
24 
25 // Message
26 static const char kMessage[] = "test message";
27 
28 static const otcrypto_key_config_t kPrivateKeyConfig = {
29  .version = kOtcryptoLibVersion1,
30  .key_mode = kOtcryptoKeyModeEcdsaP256,
31  .key_length = kP256PrivateKeyBytes,
32  .hw_backed = kHardenedBoolFalse,
33  .security_level = kOtcryptoKeySecurityLevelLow,
34 };
35 
36 status_t sign_then_verify_test(hardened_bool_t *verification_result) {
37  // Allocate space for a masked private key.
38  uint32_t keyblob[keyblob_num_words(kPrivateKeyConfig)];
39  otcrypto_blinded_key_t private_key = {
40  .config = kPrivateKeyConfig,
41  .keyblob_length = sizeof(keyblob),
42  .keyblob = keyblob,
43  };
44 
45  // Allocate space for a public key.
46  uint32_t pk[kP256PublicKeyWords] = {0};
47  otcrypto_unblinded_key_t public_key = {
48  .key_mode = kOtcryptoKeyModeEcdsaP256,
49  .key_length = sizeof(pk),
50  .key = pk,
51  };
52 
53  // Generate a keypair.
54  LOG_INFO("Generating keypair...");
55  CHECK_STATUS_OK(otcrypto_ecdsa_p256_keygen(&private_key, &public_key));
56 
57  // Hash the message.
59  .len = sizeof(kMessage) - 1,
60  .data = (unsigned char *)&kMessage,
61  };
62  uint32_t msg_digest_data[kSha256DigestWords];
63  otcrypto_hash_digest_t msg_digest = {
64  .data = msg_digest_data,
65  .len = ARRAYSIZE(msg_digest_data),
66  .mode = kOtcryptoHashModeSha256,
67  };
68  TRY(otcrypto_hash(msg, msg_digest));
69 
70  // Allocate space for the signature.
71  uint32_t sig[kP256SignatureWords] = {0};
72 
73  // Generate a signature for the message.
74  LOG_INFO("Signing...");
75  CHECK_STATUS_OK(otcrypto_ecdsa_p256_sign(
76  &private_key, msg_digest,
77  (otcrypto_word32_buf_t){.data = sig, .len = ARRAYSIZE(sig)}));
78 
79  // Verify the signature.
80  LOG_INFO("Verifying...");
81  CHECK_STATUS_OK(otcrypto_ecdsa_p256_verify(
82  &public_key, msg_digest,
83  (otcrypto_const_word32_buf_t){.data = sig, .len = ARRAYSIZE(sig)},
84  verification_result));
85 
86  return OTCRYPTO_OK;
87 }
88 
89 OTTF_DEFINE_TEST_CONFIG();
90 
91 bool test_main(void) {
92  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
93 
94  hardened_bool_t verificationResult;
95  status_t err = sign_then_verify_test(&verificationResult);
96  if (!status_ok(err)) {
97  // If there was an error, print the OTBN error bits and instruction count.
98  LOG_INFO("OTBN error bits: 0x%08x", otbn_err_bits_get());
99  LOG_INFO("OTBN instruction count: 0x%08x", otbn_instruction_count_get());
100  // Print the error.
101  CHECK_STATUS_OK(err);
102  return false;
103  }
104 
105  // Signature verification is expected to succeed.
106  if (verificationResult != kHardenedBoolTrue) {
107  LOG_ERROR("Signature failed to pass verification!");
108  return false;
109  }
110 
111  return true;
112 }