blob: a9f2393625b7432216a31e3d2a674fe3b7adecab [file] [log] [blame]
Tamas Banf70ef8c2017-12-19 15:35:09 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
David Vincze39e78552018-10-10 17:10:01 +020020/*
21 * Original code taken from mcuboot project at:
22 * https://github.com/JuulLabs-OSS/mcuboot
23 * Git SHA of the original version: 178be54bd6e5f035cc60e98205535682acd26e64
24 * Modifications are Copyright (c) 2018-2019 Arm Limited.
25 */
26
Tamas Banf70ef8c2017-12-19 15:35:09 +000027#include <string.h>
28
Tamas Banf70ef8c2017-12-19 15:35:09 +000029#ifdef MCUBOOT_SIGN_RSA
30#include "bootutil/sign_key.h"
31#include "bootutil/sha256.h"
32
33#include "mbedtls/rsa.h"
34#include "mbedtls/asn1.h"
Jamie Foxa079ede2019-01-30 15:15:28 +000035#include "mbedtls/version.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000036
37#include "bootutil_priv.h"
38
39/*
40 * Constants for this particular constrained implementation of
Tamas Ban81daed02019-05-20 15:05:22 +010041 * RSA-PSS. In particular, we support RSA 2048 and RSA 3072, with a SHA256
42 * hash, and a 32-byte salt. A signature with different parameters will be
Tamas Banf70ef8c2017-12-19 15:35:09 +000043 * rejected as invalid.
44 */
45
46/* The size, in octets, of the message. */
Tamas Ban81daed02019-05-20 15:05:22 +010047#define PSS_EMLEN (MCUBOOT_SIGN_RSA_LEN / 8)
Tamas Banf70ef8c2017-12-19 15:35:09 +000048
49/* The size of the hash function. For SHA256, this is 32 bytes. */
50#define PSS_HLEN 32
51
52/* Size of the salt, should be fixed. */
53#define PSS_SLEN 32
54
55/* The length of the mask: emLen - hLen - 1. */
Tamas Ban81daed02019-05-20 15:05:22 +010056#define PSS_MASK_LEN (PSS_EMLEN - PSS_HLEN - 1)
Tamas Banf70ef8c2017-12-19 15:35:09 +000057
58#define PSS_HASH_OFFSET PSS_MASK_LEN
59
60/* For the mask itself, how many bytes should be all zeros. */
61#define PSS_MASK_ZERO_COUNT (PSS_MASK_LEN - PSS_SLEN - 1)
62#define PSS_MASK_ONE_POS PSS_MASK_ZERO_COUNT
63
64/* Where the salt starts. */
65#define PSS_MASK_SALT_POS (PSS_MASK_ONE_POS + 1)
66
67static const uint8_t pss_zeros[8] = {0};
68
69/*
70 * Parse the public key used for signing. Simple RSA format.
71 */
72static int
73bootutil_parse_rsakey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
74{
Tamas Ban581034a2017-12-19 19:54:37 +000075 int rc, rc2;
Tamas Banf70ef8c2017-12-19 15:35:09 +000076 size_t len;
77
Tamas Ban581034a2017-12-19 19:54:37 +000078 rc = mbedtls_asn1_get_tag(p, end, &len,
79 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
80 if (rc != 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +000081 return -1;
82 }
83
84 if (*p + len != end) {
85 return -2;
86 }
87
Tamas Ban581034a2017-12-19 19:54:37 +000088 rc = mbedtls_asn1_get_mpi(p, end, &ctx->N);
89 rc2 = mbedtls_asn1_get_mpi(p, end, &ctx->E);
90 if ((rc != 0) || (rc2 != 0)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +000091 return -3;
92 }
93
Jamie Foxa079ede2019-01-30 15:15:28 +000094 ctx->len = mbedtls_mpi_size(&ctx->N);
95
Tamas Banf70ef8c2017-12-19 15:35:09 +000096 if (*p != end) {
97 return -4;
98 }
99
Jamie Foxa079ede2019-01-30 15:15:28 +0000100 /* The mbedtls version is more than 2.6.1 */
101#if MBEDTLS_VERSION_NUMBER > 0x02060100
102 rc = mbedtls_rsa_import(ctx, &ctx->N, NULL, NULL, NULL, &ctx->E);
Tamas Ban581034a2017-12-19 19:54:37 +0000103 if (rc != 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000104 return -5;
105 }
Jamie Foxa079ede2019-01-30 15:15:28 +0000106#endif
107
108 rc = mbedtls_rsa_check_pubkey(ctx);
109 if (rc != 0) {
110 return -6;
111 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000112
113 ctx->len = mbedtls_mpi_size(&ctx->N);
114
115 return 0;
116}
117
118/*
119 * Compute the RSA-PSS mask-generation function, MGF1. Assumptions
120 * are that the mask length will be less than 256 * PSS_HLEN, and
121 * therefore we never need to increment anything other than the low
122 * byte of the counter.
123 *
124 * This is described in PKCS#1, B.2.1.
125 */
126static void
127pss_mgf1(uint8_t *mask, const uint8_t *hash)
128{
129 bootutil_sha256_context ctx;
130 uint8_t counter[4] = { 0, 0, 0, 0 };
131 uint8_t htmp[PSS_HLEN];
132 int count = PSS_MASK_LEN;
133 int bytes;
134
135 while (count > 0) {
136 bootutil_sha256_init(&ctx);
137 bootutil_sha256_update(&ctx, hash, PSS_HLEN);
138 bootutil_sha256_update(&ctx, counter, 4);
139 bootutil_sha256_finish(&ctx, htmp);
140
141 counter[3]++;
142
143 bytes = PSS_HLEN;
144 if (bytes > count)
145 bytes = count;
146
147 memcpy(mask, htmp, bytes);
148 mask += bytes;
149 count -= bytes;
150 }
151}
152
153/*
154 * Validate an RSA signature, using RSA-PSS, as described in PKCS #1
155 * v2.2, section 9.1.2, with many parameters required to have fixed
156 * values.
157 */
158static int
159bootutil_cmp_rsasig(mbedtls_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
160 uint8_t *sig)
161{
162 bootutil_sha256_context shactx;
163 uint8_t em[MBEDTLS_MPI_MAX_SIZE];
164 uint8_t db_mask[PSS_MASK_LEN];
165 uint8_t h2[PSS_HLEN];
166 int i;
167
168 if (ctx->len != PSS_EMLEN || PSS_EMLEN > MBEDTLS_MPI_MAX_SIZE) {
169 return -1;
170 }
171
172 if (hlen != PSS_HLEN) {
173 return -1;
174 }
175
176 if (mbedtls_rsa_public(ctx, sig, em)) {
177 return -1;
178 }
179
180 /*
181 * PKCS #1 v2.2, 9.1.2 EMSA-PSS-Verify
182 *
183 * emBits is 2048
184 * emLen = ceil(emBits/8) = 256
185 *
186 * The salt length is not known at the beginning.
187 */
188
189 /* Step 1. The message is constrained by the address space of a
190 * 32-bit processor, which is far less than the 2^61-1 limit of
191 * SHA-256.
192 */
193
194 /* Step 2. mHash is passed in as 'hash', with hLen the hlen
195 * argument. */
196
197 /* Step 3. if emLen < hLen + sLen + 2, inconsistent and stop.
198 * The salt length is not known at this point.
199 */
200
201 /* Step 4. If the rightmost octect of EM does have the value
202 * 0xbc, output inconsistent and stop.
203 */
204 if (em[PSS_EMLEN - 1] != 0xbc) {
205 return -1;
206 }
207
208 /* Step 5. Let maskedDB be the leftmost emLen - hLen - 1 octets
209 * of EM, and H be the next hLen octets.
210 *
211 * maskedDB is then the first 256 - 32 - 1 = 0-222
212 * H is 32 bytes 223-254
213 */
214
215 /* Step 6. If the leftmost 8emLen - emBits bits of the leftmost
216 * octet in maskedDB are not all equal to zero, output
217 * inconsistent and stop.
218 *
219 * 8emLen - emBits is zero, so there is nothing to test here.
220 */
221
222 /* Step 7. let dbMask = MGF(H, emLen - hLen - 1). */
223 pss_mgf1(db_mask, &em[PSS_HASH_OFFSET]);
224
225 /* Step 8. let DB = maskedDB xor dbMask.
226 * To avoid needing an additional buffer, store the 'db' in the
227 * same buffer as db_mask. From now, to the end of this function,
228 * db_mask refers to the unmasked 'db'. */
229 for (i = 0; i < PSS_MASK_LEN; i++) {
230 db_mask[i] ^= em[i];
231 }
232
233 /* Step 9. Set the leftmost 8emLen - emBits bits of the leftmost
234 * octet in DB to zero.
235 * pycrypto seems to always make the emBits 2047, so we need to
236 * clear the top bit. */
237 db_mask[0] &= 0x7F;
238
239 /* Step 10. If the emLen - hLen - sLen - 2 leftmost octets of DB
240 * are not zero or if the octet at position emLen - hLen - sLen -
241 * 1 (the leftmost position is "position 1") does not have
242 * hexadecimal value 0x01, output "inconsistent" and stop. */
243 for (i = 0; i < PSS_MASK_ZERO_COUNT; i++) {
244 if (db_mask[i] != 0) {
245 return -1;
246 }
247 }
248
249 if (db_mask[PSS_MASK_ONE_POS] != 1) {
250 return -1;
251 }
252
253 /* Step 11. Let salt be the last sLen octets of DB */
254
255 /* Step 12. Let M' = 0x00 00 00 00 00 00 00 00 || mHash || salt; */
256
257 /* Step 13. Let H' = Hash(M') */
258 bootutil_sha256_init(&shactx);
259 bootutil_sha256_update(&shactx, pss_zeros, 8);
260 bootutil_sha256_update(&shactx, hash, PSS_HLEN);
261 bootutil_sha256_update(&shactx, &db_mask[PSS_MASK_SALT_POS], PSS_SLEN);
262 bootutil_sha256_finish(&shactx, h2);
263
264 /* Step 14. If H = H', output "consistent". Otherwise, output
265 * "inconsistent". */
266 if (memcmp(h2, &em[PSS_HASH_OFFSET], PSS_HLEN) != 0) {
267 return -1;
268 }
269
270 return 0;
271}
272
273int
David Vincze39e78552018-10-10 17:10:01 +0200274bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000275 uint8_t key_id)
276{
277 mbedtls_rsa_context ctx;
278 int rc;
279 uint8_t *cp;
280 uint8_t *end;
281
282 mbedtls_rsa_init(&ctx, 0, 0);
283
284 cp = (uint8_t *)bootutil_keys[key_id].key;
285 end = cp + *bootutil_keys[key_id].len;
286
287 rc = bootutil_parse_rsakey(&ctx, &cp, end);
288 if (rc || slen != ctx.len) {
289 mbedtls_rsa_free(&ctx);
290 return rc;
291 }
292 rc = bootutil_cmp_rsasig(&ctx, hash, hlen, sig);
293 mbedtls_rsa_free(&ctx);
294
295 return rc;
296}
297#endif /* MCUBOOT_SIGN_RSA */