Software APIs
rsa_verify.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/silicon_creator/lib/sigverify/rsa_verify.h"
6 
7 #include "sw/device/silicon_creator/lib/drivers/otp.h"
8 #include "sw/device/silicon_creator/lib/sigverify/mod_exp_ibex.h"
9 
10 #include "otp_ctrl_regs.h"
11 
12 /*
13  * Shares for producing the `flash_exec` value in encoded message check. First
14  * 95 shares are generated using the `sparse-fsm-encode` script while the last
15  * share is `kSigverifySpxSuccess ^ kSigverifyFlashExec ^ kShares[0] ^ ... ^
16  * kShares[94]` so that xor'ing all shares and `kSigverifySpxSuccess` produces
17  * `kSigverifyFlashExec`, i.e. the value that unlocks flash execution.
18  *
19  * Encoding generated with
20  * $ ./util/design/sparse-fsm-encode.py -d 6 -m 95 -n 32 \
21  * -s 3118901143 --language=c
22  *
23  * Minimum Hamming distance: 7
24  * Maximum Hamming distance: 26
25  * Minimum Hamming weight: 9
26  * Maximum Hamming weight: 23
27  */
28 static const uint32_t kSigverifyShares[kSigVerifyRsaNumWords] = {
29  0xaf28073b, 0x5eb7dcfb, 0x177240b5, 0xa8469df3, 0x2e92e9c0, 0x83ed133b,
30  0x0c9e99f0, 0x25611bd9, 0x411a9d85, 0x5c52b3df, 0x4347a537, 0x1e78e574,
31  0x273e33af, 0x6f363bba, 0x11e4ee52, 0xd29ad9aa, 0x4fc2ac85, 0x52490c66,
32  0x59c2528c, 0xef8d3ab2, 0xe74d7eb8, 0x2822259c, 0xe58efaa3, 0xe702fa04,
33  0x82c670f6, 0x42be0a77, 0x3b021ea0, 0x09bd2a22, 0x26d656a4, 0x2f8e008f,
34  0xefca5842, 0xfbc3a713, 0x4ce07aa1, 0xc1826ecc, 0xc697d53f, 0xf6a69161,
35  0x4a7d7628, 0x87f2e957, 0x84db848d, 0xe05e01c5, 0x6188ff27, 0xbf1a2b31,
36  0xb51d4166, 0x85fd6e7c, 0x59c5d2d5, 0x13c6e4e6, 0xff83c944, 0xc78cd4bb,
37  0x8710d989, 0x7608c41e, 0x1061b036, 0x9c2fb244, 0x34a26844, 0x2bdc22a2,
38  0xfd1d95f3, 0x94ac4e84, 0x1a99ce21, 0xd54eb8f7, 0x54c2cd9f, 0x70a967c8,
39  0xde39d471, 0x652563cd, 0x3d4adea1, 0x1cf6631c, 0xb27d16ee, 0x3a18bafa,
40  0xd8a86a86, 0xd839cd7b, 0xda2ab05a, 0x37fc1d99, 0xbc702308, 0x01d57596,
41  0x480d3091, 0x51420446, 0xcc56d97c, 0x7aa57434, 0x7b6097ae, 0x45bca8ae,
42  0xb0b1e322, 0x5487b90f, 0x1045e6ef, 0x87ad10f0, 0x4c72b7f0, 0xc527c9a3,
43  0x29ed4350, 0xe345625b, 0x57063d83, 0xbb56900a, 0xbfb1be4c, 0x1c454e8f,
44  0xdb27c1b7, 0xbe02c694, 0x2604d74a, 0x4d6516dd, 0x322918ab, 0x5f320b43,
45 };
46 
47 /**
48  * Checks the padding and the digest of an EMSA-PKCS1-v1_5 encoded message.
49  *
50  * EMSA-PKCS1-v1_5 is described in Section 9.2 of PKCS #1: RSA Cryptography
51  * Specifications Version 2.2 (https://tools.ietf.org/html/rfc8017#section-9.2).
52  * In PKCS#1, sequences are indexed from the leftmost byte and the first byte is
53  * the most significant byte. An encoded message EM is an octet string of the
54  * form:
55  * EM = 0x00 || 0x01 || PS || 0x00 || T, where
56  * PS is a byte string of `0xff`s, T is the DER encoding of ASN.1 value of type
57  * DigestInfo that contains the digest algorithm and the digest, and || denotes
58  * concatenation. For SHA-256:
59  * T = (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H,
60  * where H is the digest.
61  *
62  * This function checks the padding and the digest of an encoded message as
63  * described in PKCS#1 but works on little-endian buffers.
64  *
65  * @param enc_msg An encoded message, little-endian.
66  * @param act_digest Actual digest of the message being verified, little-endian.
67  * @param[out] flash_exec Value to write to the flash_ctrl EXEC register.
68  * @return Result of the operation.
69  */
71 static rom_error_t sigverify_encoded_message_check(
72  sigverify_rsa_buffer_t *enc_msg, const hmac_digest_t *act_digest,
73  uint32_t *flash_exec) {
74  // The algorithm below uses shares, i.e. trivial secret sharing, to check an
75  // encoded message and produce two values: `flash_exec` and `result`.
76  // `flash_exec` is the value to write to the flash_ctrl EXEC register to
77  // unlock flash execution and `result` is the return value. We produce
78  // `result` in addition to `flash_exec` to avoid having the unlock value in
79  // registers or memory just for checking the result of signature verification.
80  // The algorithm consists of two steps:
81  //
82  // 1. First, we xor each word of `enc_msg` with the corresponding expected
83  // value and share (`kSigverifyShares[i]`). At the end of this step, `enc_msg`
84  // becomes `kSigverifyShares` if it's correct and garbage otherwise. Note
85  // that this step of the algorithm is implemented using separate loops to
86  // reduce stack usage.
87  //
88  // 2. Next, we produce `flash_exec` and `result`. `flash_exec` is produced by
89  // xor'ing all words of `enc_msg` with each other. If `enc_msg` is correct,
90  // `flash_exec` will be `kSigverifyFlashExec` due to the way
91  // `kSigverifyShares` is defined. To make sure that we don't produce this
92  // value otherwise, we compare each word of `enc_msg` with the corresponding
93  // expected value and set `flash_exec` to `UINT32_MAX` at each iteration if
94  // there is a mismatch. Finally, we produce the return value `result` from
95  // `flash_exec` by xor'ing parts of it together. Note that the hardware
96  // constant `kSigverifyFlashExec` is chosen such that this operation results
97  // in `kErrorOk`.
98 
99  // Step 1: Process `enc_msg` so that it becomes `kSigverifyShares` if it's
100  // correct, garbage otherwise.
101  uint32_t *enc_msg_ptr = enc_msg->data;
102  size_t i = 0;
103  for (size_t j = 0; launder32(j) < kHmacDigestNumWords; ++j, ++i) {
104  enc_msg_ptr[i] ^= act_digest->digest[j] ^ kSigverifyShares[i];
105  }
106  // Note: This also includes the zero byte right before PS.
107  static const uint32_t kEncodedSha256[] = {
108  0x05000420, 0x03040201, 0x86480165, 0x0d060960, 0x00303130,
109  };
110  for (size_t j = 0; launder32(j) < ARRAYSIZE(kEncodedSha256); ++j, ++i) {
111  enc_msg_ptr[i] ^= kEncodedSha256[j] ^ kSigverifyShares[i];
112  }
113  // Note: `kPsLen` excludes the last word of `enc_msg`, which is 0x0001ffff.
114  static const size_t kPsLen = ARRAYSIZE(enc_msg->data) -
115  ARRAYSIZE(kEncodedSha256) -
116  ARRAYSIZE(act_digest->digest) - /*last word*/ 1;
117  // PS up to the last word.
118  for (size_t j = 0; launder32(j) < kPsLen; ++j, ++i) {
119  enc_msg_ptr[i] ^= 0xffffffff ^ kSigverifyShares[i];
120  }
121  // Last word.
122  enc_msg_ptr[i] ^= 0x0001ffff ^ kSigverifyShares[i];
123  HARDENED_CHECK_EQ(i, kSigVerifyRsaNumWords - 1);
124 
125  // Step 2: Reduce `enc_msg` to produce the value to write to flash_ctrl EXEC
126  // register (`flash_exec`) and the return value (`result`).
127  uint32_t flash_exec_rsa = 0;
128  uint32_t diff = 0;
129  for (i = 0; launder32(i) < kSigVerifyRsaNumWords; ++i) {
130  // Following three statements set `diff` to `UINT32_MAX` if `enc_msg[i]` is
131  // incorrect, no change otherwise.
132  diff |= enc_msg_ptr[i] ^ kSigverifyShares[i];
133  diff |= ~diff + 1; // Set upper bits to 1 if not 0, no change o/w.
134  diff |= ~(diff >> 31) + 1; // Set to all 1s if MSB is set, no change o/w.
135 
136  flash_exec_rsa ^= enc_msg_ptr[i];
137  // Set `flash_exec_rsa` to `UINT32_MAX` if `enc_msg` is incorrect.
138  flash_exec_rsa |= diff;
139  }
140  HARDENED_CHECK_EQ(i, kSigVerifyRsaNumWords);
141 
142  // Note: `kSigverifyRsaSuccess` is defined such that the following operation
143  // produces `kErrorOk`.
144  rom_error_t result = sigverify_rsa_success_to_ok(flash_exec_rsa);
145  *flash_exec ^= flash_exec_rsa;
146  if (launder32(result) == kErrorOk) {
147  HARDENED_CHECK_EQ(result, kErrorOk);
148  return result;
149  }
150 
151  return kErrorSigverifyBadRsaSignature;
152 }
153 
154 rom_error_t sigverify_rsa_verify(const sigverify_rsa_buffer_t *signature,
155  const sigverify_rsa_key_t *key,
156  const hmac_digest_t *act_digest,
157  lifecycle_state_t lc_state,
158  uint32_t *flash_exec) {
159  sigverify_rsa_buffer_t enc_msg;
160  rom_error_t error = sigverify_mod_exp_ibex(key, signature, &enc_msg);
161  if (launder32(error) != kErrorOk) {
162  *flash_exec ^= UINT32_MAX;
163  return error;
164  }
165  HARDENED_CHECK_EQ(error, kErrorOk);
166  return sigverify_encoded_message_check(&enc_msg, act_digest, flash_exec);
167 }
168 
169 // Extern declarations for the inline functions in the header.
170 extern uint32_t sigverify_rsa_success_to_ok(uint32_t v);