1 // Copyright (c) 2017-2021 Linaro LTD
2 // Copyright (c) 2017-2019 JUUL Labs
3 // Copyright (c) 2019-2021 Arm Limited
4 //
5 // SPDX-License-Identifier: Apache-2.0
6 
7 //! Interface wrappers to C API entering to the bootloader
8 
9 use crate::area::AreaDesc;
10 use simflash::SimMultiFlash;
11 use crate::api;
12 
13 /// The result of an invocation of `boot_go`.  This is intentionally opaque so that we can provide
14 /// accessors for everything we need from this.
15 #[derive(Debug)]
16 pub enum BootGoResult {
17     /// This run was stopped by the flash simulation mechanism.
18     Stopped,
19     /// The bootloader ran to completion with the following data.
20     Normal {
21         result: i32,
22         asserts: u8,
23 
24         resp: api::BootRsp,
25     },
26 }
27 
28 impl BootGoResult {
29     /// Was this run interrupted.
interrupted(&self) -> bool30     pub fn interrupted(&self) -> bool {
31         matches!(self, BootGoResult::Stopped)
32     }
33 
34     /// Was this boot run successful (returned 0)
success(&self) -> bool35     pub fn success(&self) -> bool {
36         matches!(self, BootGoResult::Normal { result: 0, .. })
37     }
38 
39     /// Success, but also no asserts.
success_no_asserts(&self) -> bool40     pub fn success_no_asserts(&self) -> bool {
41         matches!(self, BootGoResult::Normal {
42             result: 0,
43             asserts: 0,
44             ..
45         })
46     }
47 
48     /// Get the asserts count.  An interrupted run will be considered to have no asserts.
asserts(&self) -> u849     pub fn asserts(&self) -> u8 {
50         match self {
51             BootGoResult::Normal { asserts, .. } => *asserts,
52             _ => 0,
53         }
54     }
55 
56     /// Retrieve the 'resp' field that is filled in.
resp(&self) -> Option<&api::BootRsp>57     pub fn resp(&self) -> Option<&api::BootRsp> {
58         match self {
59             BootGoResult::Normal { resp, .. } => Some(resp),
60             _ => None,
61         }
62     }
63 }
64 
65 /// Invoke the bootloader on this flash device.
boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc, counter: Option<&mut i32>, image_index: Option<i32>, catch_asserts: bool) -> BootGoResult66 pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
67                counter: Option<&mut i32>, image_index: Option<i32>,
68                catch_asserts: bool) -> BootGoResult {
69     for (&dev_id, flash) in multiflash.iter_mut() {
70         api::set_flash(dev_id, flash);
71     }
72     let mut sim_ctx = api::CSimContext {
73         flash_counter: match counter {
74             None => 0,
75             Some(ref c) => **c as libc::c_int
76         },
77         jumped: 0,
78         c_asserts: 0,
79         c_catch_asserts: if catch_asserts { 1 } else { 0 },
80         boot_jmpbuf: [0; 16],
81     };
82     let mut rsp = api::BootRsp {
83         br_hdr: std::ptr::null(),
84         flash_dev_id: 0,
85         image_off: 0,
86     };
87     let result: i32 = unsafe {
88         match image_index {
89             None => raw::invoke_boot_go(&mut sim_ctx as *mut _,
90                                         &areadesc.get_c() as *const _,
91                                         &mut rsp as *mut _, -1) as i32,
92             Some(i) => raw::invoke_boot_go(&mut sim_ctx as *mut _,
93                                            &areadesc.get_c() as *const _,
94                                            &mut rsp as *mut _,
95                                            i as i32) as i32
96         }
97     };
98     let asserts = sim_ctx.c_asserts;
99     if let Some(c) = counter {
100         *c = sim_ctx.flash_counter;
101     }
102     for &dev_id in multiflash.keys() {
103         api::clear_flash(dev_id);
104     }
105     if result == -0x13579 {
106         BootGoResult::Stopped
107     } else {
108         BootGoResult::Normal { result, asserts, resp: rsp }
109     }
110 }
111 
boot_trailer_sz(align: u32) -> u32112 pub fn boot_trailer_sz(align: u32) -> u32 {
113     unsafe { raw::boot_trailer_sz(align) }
114 }
115 
boot_status_sz(align: u32) -> u32116 pub fn boot_status_sz(align: u32) -> u32 {
117     unsafe { raw::boot_status_sz(align) }
118 }
119 
boot_magic_sz() -> usize120 pub fn boot_magic_sz() -> usize {
121     unsafe { raw::boot_magic_sz() as usize }
122 }
123 
boot_max_align() -> usize124 pub fn boot_max_align() -> usize {
125     unsafe { raw::boot_max_align() as usize }
126 }
127 
rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str>128 pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
129     unsafe {
130         let mut encbuf: [u8; 256] = [0; 256];
131         if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
132                                   seckey.as_ptr(), seckey.len() as u32,
133                                   encbuf.as_mut_ptr()) == 0 {
134             return Ok(encbuf);
135         }
136         Err("Failed to encrypt buffer")
137     }
138 }
139 
kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str>140 pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
141     unsafe {
142         let mut encbuf = vec![0u8; 24];
143         if keylen == 32 {
144             encbuf = vec![0u8; 40];
145         }
146         if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
147             return Ok(encbuf);
148         }
149         Err("Failed to encrypt buffer")
150     }
151 }
152 
153 mod raw {
154     use crate::area::CAreaDesc;
155     use crate::api::{BootRsp, CSimContext};
156 
157     extern "C" {
158         // This generates a warning about `CAreaDesc` not being foreign safe.  There doesn't appear to
159         // be any way to get rid of this warning.  See https://github.com/rust-lang/rust/issues/34798
160         // for information and tracking.
invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc, rsp: *mut BootRsp, image_index: libc::c_int) -> libc::c_int161         pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
162             rsp: *mut BootRsp, image_index: libc::c_int) -> libc::c_int;
163 
boot_trailer_sz(min_write_sz: u32) -> u32164         pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
boot_status_sz(min_write_sz: u32) -> u32165         pub fn boot_status_sz(min_write_sz: u32) -> u32;
166 
boot_magic_sz() -> u32167         pub fn boot_magic_sz() -> u32;
boot_max_align() -> u32168         pub fn boot_max_align() -> u32;
169 
rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint, seckey: *const u8, seckey_len: libc::c_uint, encbuf: *mut u8) -> libc::c_int170         pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
171                                  seckey: *const u8, seckey_len: libc::c_uint,
172                                  encbuf: *mut u8) -> libc::c_int;
173 
kw_encrypt_(kek: *const u8, seckey: *const u8, encbuf: *mut u8) -> libc::c_int174         pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
175                            encbuf: *mut u8) -> libc::c_int;
176     }
177 }
178