blob: 483ca8fb06f7c5b38eb38f7d263aeb49b5d731e0 [file] [log] [blame]
David Brownc8d62012021-10-27 15:03:48 -06001// Copyright (c) 2017-2021 Linaro LTD
David Browne2acfae2020-01-21 16:45:01 -07002// Copyright (c) 2017-2019 JUUL Labs
Roland Mikheld6703522023-04-27 14:24:30 +02003// Copyright (c) 2019-2023 Arm Limited
David Browne2acfae2020-01-21 16:45:01 -07004//
5// SPDX-License-Identifier: Apache-2.0
6
7//! Interface wrappers to C API entering to the bootloader
David Brownde7729e2017-01-09 10:41:35 -07008
David Brown65de6d12019-01-02 11:38:38 -07009use crate::area::AreaDesc;
David Brown76101572019-02-28 11:29:03 -070010use simflash::SimMultiFlash;
David Brown65de6d12019-01-02 11:38:38 -070011use crate::api;
David Brownde7729e2017-01-09 10:41:35 -070012
Antonio de Angelis65eb35c2022-11-22 14:11:47 +000013#[allow(unused)]
14use std::sync::Once;
15
David Brownc423ac42021-06-04 13:47:34 -060016/// The result of an invocation of `boot_go`. This is intentionally opaque so that we can provide
17/// accessors for everything we need from this.
18#[derive(Debug)]
David Brown6d47d422021-06-04 14:41:33 -060019pub enum BootGoResult {
20 /// This run was stopped by the flash simulation mechanism.
21 Stopped,
22 /// The bootloader ran to completion with the following data.
23 Normal {
24 result: i32,
25 asserts: u8,
David Brownd82de8c2021-06-04 15:08:25 -060026
27 resp: api::BootRsp,
David Brown6d47d422021-06-04 14:41:33 -060028 },
David Brownc423ac42021-06-04 13:47:34 -060029}
30
31impl BootGoResult {
32 /// Was this run interrupted.
33 pub fn interrupted(&self) -> bool {
David Brown6d47d422021-06-04 14:41:33 -060034 matches!(self, BootGoResult::Stopped)
David Brownc423ac42021-06-04 13:47:34 -060035 }
36
37 /// Was this boot run successful (returned 0)
38 pub fn success(&self) -> bool {
David Brown6d47d422021-06-04 14:41:33 -060039 matches!(self, BootGoResult::Normal { result: 0, .. })
David Brownc423ac42021-06-04 13:47:34 -060040 }
41
42 /// Success, but also no asserts.
43 pub fn success_no_asserts(&self) -> bool {
David Brown6d47d422021-06-04 14:41:33 -060044 matches!(self, BootGoResult::Normal {
45 result: 0,
46 asserts: 0,
David Brownd82de8c2021-06-04 15:08:25 -060047 ..
David Brown6d47d422021-06-04 14:41:33 -060048 })
David Brownc423ac42021-06-04 13:47:34 -060049 }
50
David Brown6d47d422021-06-04 14:41:33 -060051 /// Get the asserts count. An interrupted run will be considered to have no asserts.
David Brownc423ac42021-06-04 13:47:34 -060052 pub fn asserts(&self) -> u8 {
David Brown6d47d422021-06-04 14:41:33 -060053 match self {
54 BootGoResult::Normal { asserts, .. } => *asserts,
55 _ => 0,
56 }
David Brownc423ac42021-06-04 13:47:34 -060057 }
David Brownd82de8c2021-06-04 15:08:25 -060058
59 /// Retrieve the 'resp' field that is filled in.
60 pub fn resp(&self) -> Option<&api::BootRsp> {
61 match self {
62 BootGoResult::Normal { resp, .. } => Some(resp),
63 _ => None,
64 }
65 }
David Brownc423ac42021-06-04 13:47:34 -060066}
67
David Brownde7729e2017-01-09 10:41:35 -070068/// Invoke the bootloader on this flash device.
David Brown76101572019-02-28 11:29:03 -070069pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
Raef Coles3fd3ecc2021-10-15 11:14:12 +010070 counter: Option<&mut i32>, image_index: Option<i32>,
71 catch_asserts: bool) -> BootGoResult {
Antonio de Angelis65eb35c2022-11-22 14:11:47 +000072 init_crypto();
73
David Brown7cc45262021-03-10 05:13:44 -070074 for (&dev_id, flash) in multiflash.iter_mut() {
75 api::set_flash(dev_id, flash);
Fabio Utzig8000e322019-08-05 08:14:32 -030076 }
77 let mut sim_ctx = api::CSimContext {
78 flash_counter: match counter {
David Brownee61c832017-11-06 11:13:25 -070079 None => 0,
80 Some(ref c) => **c as libc::c_int
Fabio Utzig8000e322019-08-05 08:14:32 -030081 },
82 jumped: 0,
83 c_asserts: 0,
84 c_catch_asserts: if catch_asserts { 1 } else { 0 },
85 boot_jmpbuf: [0; 16],
86 };
David Brownd216b202021-06-04 10:14:33 -060087 let mut rsp = api::BootRsp {
88 br_hdr: std::ptr::null(),
89 flash_dev_id: 0,
90 image_off: 0,
91 };
Raef Coles3fd3ecc2021-10-15 11:14:12 +010092 let result: i32 = unsafe {
93 match image_index {
94 None => raw::invoke_boot_go(&mut sim_ctx as *mut _,
95 &areadesc.get_c() as *const _,
96 &mut rsp as *mut _, -1) as i32,
97 Some(i) => raw::invoke_boot_go(&mut sim_ctx as *mut _,
98 &areadesc.get_c() as *const _,
99 &mut rsp as *mut _,
100 i as i32) as i32
101 }
Fabio Utzig8000e322019-08-05 08:14:32 -0300102 };
103 let asserts = sim_ctx.c_asserts;
David Brown8608c532021-03-10 05:18:11 -0700104 if let Some(c) = counter {
105 *c = sim_ctx.flash_counter;
106 }
David Brown7cc45262021-03-10 05:13:44 -0700107 for &dev_id in multiflash.keys() {
108 api::clear_flash(dev_id);
109 }
David Brown6d47d422021-06-04 14:41:33 -0600110 if result == -0x13579 {
111 BootGoResult::Stopped
112 } else {
David Brownd82de8c2021-06-04 15:08:25 -0600113 BootGoResult::Normal { result, asserts, resp: rsp }
David Brown6d47d422021-06-04 14:41:33 -0600114 }
David Brownde7729e2017-01-09 10:41:35 -0700115}
116
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300117pub fn boot_trailer_sz(align: u32) -> u32 {
Christopher Collins2adef702019-05-22 14:37:31 -0700118 unsafe { raw::boot_trailer_sz(align) }
David Brownde7729e2017-01-09 10:41:35 -0700119}
120
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300121pub fn boot_status_sz(align: u32) -> u32 {
122 unsafe { raw::boot_status_sz(align) }
123}
124
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300125pub fn boot_magic_sz() -> usize {
David Brown2b8a6952019-10-01 16:14:53 -0600126 unsafe { raw::boot_magic_sz() as usize }
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300127}
128
129pub fn boot_max_align() -> usize {
David Browne0bb1f92019-10-01 15:57:01 -0600130 unsafe { raw::boot_max_align() as usize }
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300131}
132
Fabio Utzig1e48b912018-09-18 09:04:18 -0300133pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
134 unsafe {
135 let mut encbuf: [u8; 256] = [0; 256];
136 if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
137 seckey.as_ptr(), seckey.len() as u32,
138 encbuf.as_mut_ptr()) == 0 {
139 return Ok(encbuf);
140 }
David Brownc20bbb22021-03-10 05:19:14 -0700141 Err("Failed to encrypt buffer")
Fabio Utzig1e48b912018-09-18 09:04:18 -0300142 }
143}
144
Salome Thirot6fdbf552021-05-14 16:46:14 +0100145pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300146 unsafe {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100147 let mut encbuf = vec![0u8; 24];
148 if keylen == 32 {
149 encbuf = vec![0u8; 40];
150 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300151 if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
152 return Ok(encbuf);
153 }
David Brownc20bbb22021-03-10 05:19:14 -0700154 Err("Failed to encrypt buffer")
Fabio Utzig1e48b912018-09-18 09:04:18 -0300155 }
156}
157
Roland Mikheld6703522023-04-27 14:24:30 +0200158pub fn set_security_counter(image_index: u32, security_counter_value: u32) {
159 api::sim_set_nv_counter_for_image(image_index, security_counter_value);
160}
161
162pub fn get_security_counter(image_index: u32) -> u32 {
163 let mut counter_val: u32 = 0;
164 api::sim_get_nv_counter_for_image(image_index, &mut counter_val as *mut u32);
165 return counter_val;
166}
167
David Brownde7729e2017-01-09 10:41:35 -0700168mod raw {
David Brown65de6d12019-01-02 11:38:38 -0700169 use crate::area::CAreaDesc;
David Brownd216b202021-06-04 10:14:33 -0600170 use crate::api::{BootRsp, CSimContext};
David Brownde7729e2017-01-09 10:41:35 -0700171
172 extern "C" {
173 // This generates a warning about `CAreaDesc` not being foreign safe. There doesn't appear to
174 // be any way to get rid of this warning. See https://github.com/rust-lang/rust/issues/34798
175 // for information and tracking.
David Brownd216b202021-06-04 10:14:33 -0600176 pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
Raef Coles3fd3ecc2021-10-15 11:14:12 +0100177 rsp: *mut BootRsp, image_index: libc::c_int) -> libc::c_int;
David Brownde7729e2017-01-09 10:41:35 -0700178
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300179 pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
180 pub fn boot_status_sz(min_write_sz: u32) -> u32;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300181
David Brown2b8a6952019-10-01 16:14:53 -0600182 pub fn boot_magic_sz() -> u32;
David Browne0bb1f92019-10-01 15:57:01 -0600183 pub fn boot_max_align() -> u32;
Fabio Utzig92be3fb2017-12-05 08:52:53 -0200184
Fabio Utzig1e48b912018-09-18 09:04:18 -0300185 pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
186 seckey: *const u8, seckey_len: libc::c_uint,
187 encbuf: *mut u8) -> libc::c_int;
188
189 pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
190 encbuf: *mut u8) -> libc::c_int;
Antonio de Angelis65eb35c2022-11-22 14:11:47 +0000191
192 #[allow(unused)]
193 pub fn psa_crypto_init() -> u32;
194
195 #[allow(unused)]
196 pub fn mbedtls_test_enable_insecure_external_rng();
David Brownde7729e2017-01-09 10:41:35 -0700197 }
198}
Antonio de Angelis65eb35c2022-11-22 14:11:47 +0000199
200#[allow(unused)]
201static PSA_INIT_SYNC: Once = Once::new();
202
203#[allow(unused)]
204static MBEDTLS_EXTERNAL_RNG_ENABLE_SYNC: Once = Once::new();
205
206#[cfg(feature = "psa-crypto-api")]
207fn init_crypto() {
208 PSA_INIT_SYNC.call_once(|| {
209 assert_eq!(unsafe { raw::psa_crypto_init() }, 0);
210 });
211
212 /* The PSA APIs require properly initialisation of the entropy subsystem
213 * The configuration adds the option MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG when the
214 * psa-crypto-api feature is enabled. As a result the tests use the implementation
215 * of the test external rng that needs to be initialised before being able to use it
216 */
217 MBEDTLS_EXTERNAL_RNG_ENABLE_SYNC.call_once(|| {
218 unsafe { raw::mbedtls_test_enable_insecure_external_rng() }
219 });
220}
221
222#[cfg(not(feature = "psa-crypto-api"))]
223fn init_crypto() {
224 // When the feature is not enabled, the init is just empty
225}