blob: 5c19b0a69584e5618d8c49e9cd85f90f7e749f93 [file] [log] [blame]
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -04001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
Alphan Ulusoyb344ed72021-06-14 12:38:22 -04005#include "sw/device/silicon_creator/mask_rom/sigverify.h"
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -04006
7#include "sw/device/lib/base/memory.h"
8#include "sw/device/lib/base/mmio.h"
9#include "sw/device/silicon_creator/lib/drivers/hmac.h"
Alphan Ulusoyb344ed72021-06-14 12:38:22 -040010#include "sw/device/silicon_creator/mask_rom/sigverify_mod_exp.h"
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -040011
12#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
13
14/**
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -040015 * Checks the padding and the digest of an EMSA-PKCS1-v1_5 encoded message.
16 *
17 * EMSA-PKCS1-v1_5 is described in Section 9.2 of PKCS #1: RSA Cryptography
18 * Specifications Version 2.2 (https://tools.ietf.org/html/rfc8017#section-9.2).
19 * In PKCS#1, sequences are indexed from the leftmost byte and the first byte is
20 * the most significant byte. An encoded message EM is an octet string of the
21 * form:
22 * EM = 0x00 || 0x01 || PS || 0x00 || T, where
23 * PS is a byte string of `0xff`s, T is the DER encoding of ASN.1 value of type
24 * DigestInfo that contains the digest algorithm and the digest, and || denotes
25 * concatenation. For SHA-256:
26 * T = (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H,
27 * where H is the digest.
28 *
29 * This function checks the padding and the digest of an encoded message as
30 * described in PKCS#1 but works on little-endian buffers.
31 *
32 * @param enc_msg An encoded message, little-endian.
33 * @param act_digest Actual digest of the message being verified, little-endian.
34 * @return Result of the operation.
35 */
36static rom_error_t sigverify_padding_and_digest_check(
37 const sigverify_rsa_buffer_t *enc_msg, const hmac_digest_t *act_digest) {
38 const uint32_t *enc_msg_ptr = enc_msg->data;
39
40 if (memcmp(enc_msg_ptr, act_digest->digest, sizeof(act_digest->digest)) !=
41 0) {
42 return kErrorSigverifyInvalidArgument;
43 }
44 enc_msg_ptr += ARRAYSIZE(act_digest->digest);
45
46 // Note: This also includes the zero byte right before PS.
47 static const uint32_t kEncodedSha256[] = {
48 0x05000420, 0x03040201, 0x86480165, 0x0d060960, 0x00303130,
49 };
50 if (memcmp(enc_msg_ptr, kEncodedSha256, sizeof(kEncodedSha256)) != 0) {
51 return kErrorSigverifyInvalidArgument;
52 }
53 enc_msg_ptr += ARRAYSIZE(kEncodedSha256);
54
55 // Note: `kPsLen` excludes the last word of `enc_msg`, which is 0x0001ffff.
56 static const size_t kPsLen = ARRAYSIZE(enc_msg->data) -
57 ARRAYSIZE(kEncodedSha256) -
58 ARRAYSIZE(act_digest->digest) - /*last word*/ 1;
59 uint32_t padding = UINT32_MAX;
60 for (size_t i = 0; i < kPsLen; ++i) {
61 padding &= *enc_msg_ptr++;
62 }
63 uint32_t res = ~padding;
64 res |= *enc_msg_ptr ^ 0x0001ffff;
65 if (res != 0) {
66 return kErrorSigverifyInvalidArgument;
67 }
68
69 return kErrorOk;
70}
71
Alphan Ulusoy83b8a582021-06-14 20:33:18 -040072rom_error_t sigverify_rsa_verify(const void *signed_message,
73 size_t signed_message_len,
74 const sigverify_rsa_buffer_t *signature,
75 const sigverify_rsa_key_t *key) {
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -040076 hmac_digest_t act_digest;
Miguel Osorio98ca8db2021-05-07 15:40:27 -070077 hmac_sha256_init();
Alphan Ulusoy83b8a582021-06-14 20:33:18 -040078 RETURN_IF_ERROR(hmac_sha256_update(signed_message, signed_message_len));
Miguel Osorio98ca8db2021-05-07 15:40:27 -070079 RETURN_IF_ERROR(hmac_sha256_final(&act_digest));
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -040080
Alphan Ulusoy06428b32021-06-14 20:15:11 -040081 // FIXME: Choose between Ibex and OTBN using OTP.
82 // FIXME: OTBN modular exponentiation.
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -040083 sigverify_rsa_buffer_t enc_msg;
Alphan Ulusoy080f0472021-06-14 16:07:51 -040084 RETURN_IF_ERROR(sigverify_mod_exp_ibex(key, signature, &enc_msg));
Alphan Ulusoy6e9a3c42021-04-14 18:17:46 -040085 RETURN_IF_ERROR(sigverify_padding_and_digest_check(&enc_msg, &act_digest));
86
87 return kErrorOk;
88}
Alphan Ulusoy5d347652021-06-14 14:43:02 -040089
90// `extern` declarations for `inline` functions in the header.
91extern uint32_t sigverify_rsa_key_id_get(const sigverify_rsa_buffer_t *modulus);