capsules_extra/
hmac.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! HMAC (Hash-based Message Authentication Code).
6//!
7//! Usage
8//! -----
9//!
10//! ```rust,ignore
11//! let hmac = &earlgrey::hmac::HMAC;
12//!
13//! let mux_hmac = static_init!(MuxHmac<'static, lowrisc::hmac::Hmac>, MuxHmac::new(hmac));
14//! digest::Digest::set_client(&earlgrey::hmac::HMAC, mux_hmac);
15//!
16//! let virtual_hmac_user = static_init!(
17//!     VirtualMuxHmac<'static, lowrisc::hmac::Hmac>,
18//!     VirtualMuxHmac::new(mux_hmac)
19//! );
20//! let hmac = static_init!(
21//!     capsules::hmac::HmacDriver<'static, VirtualMuxHmac<'static, lowrisc::hmac::Hmac>>,
22//!     capsules::hmac::HmacDriver::new(
23//!         virtual_hmac_user,
24//!         board_kernel.create_grant(&memory_allocation_cap),
25//!     )
26//! );
27//! digest::Digest::set_client(virtual_hmac_user, hmac);
28//! ```
29
30use capsules_core::driver;
31use kernel::errorcode::into_statuscode;
32/// Syscall driver number.
33pub const DRIVER_NUM: usize = driver::NUM::Hmac as usize;
34
35/// Ids for read-only allow buffers
36mod ro_allow {
37    pub const KEY: usize = 0;
38    pub const DATA: usize = 1;
39    pub const COMPARE: usize = 2;
40    /// The number of allow buffers the kernel stores for this grant
41    pub const COUNT: u8 = 3;
42}
43
44/// Ids for read-write allow buffers
45mod rw_allow {
46    pub const DEST: usize = 2;
47    /// The number of allow buffers the kernel stores for this grant
48    pub const COUNT: u8 = 3;
49}
50
51use core::cell::Cell;
52
53use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
54use kernel::hil::digest;
55use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
56use kernel::syscall::{CommandReturn, SyscallDriver};
57use kernel::utilities::cells::{OptionalCell, TakeCell};
58use kernel::utilities::leasable_buffer::SubSlice;
59use kernel::utilities::leasable_buffer::SubSliceMut;
60use kernel::{ErrorCode, ProcessId};
61
62enum ShaOperation {
63    Sha256,
64    Sha384,
65    Sha512,
66}
67
68// Temporary buffer to copy the keys from userspace into
69//
70// Needs to be able to accommodate the largest key sizes, e.g. 512
71const TMP_KEY_BUFFER_SIZE: usize = 512 / 8;
72
73pub struct HmacDriver<'a, H: digest::Digest<'a, DIGEST_LEN>, const DIGEST_LEN: usize> {
74    hmac: &'a H,
75
76    active: Cell<bool>,
77
78    apps: Grant<
79        App,
80        UpcallCount<1>,
81        AllowRoCount<{ ro_allow::COUNT }>,
82        AllowRwCount<{ rw_allow::COUNT }>,
83    >,
84    processid: OptionalCell<ProcessId>,
85
86    data_buffer: TakeCell<'static, [u8]>,
87    data_copied: Cell<usize>,
88    dest_buffer: TakeCell<'static, [u8; DIGEST_LEN]>,
89}
90
91impl<
92        'a,
93        H: digest::Digest<'a, DIGEST_LEN>
94            + digest::HmacSha256
95            + digest::HmacSha384
96            + digest::HmacSha512,
97        const DIGEST_LEN: usize,
98    > HmacDriver<'a, H, DIGEST_LEN>
99{
100    pub fn new(
101        hmac: &'a H,
102        data_buffer: &'static mut [u8],
103        dest_buffer: &'static mut [u8; DIGEST_LEN],
104        grant: Grant<
105            App,
106            UpcallCount<1>,
107            AllowRoCount<{ ro_allow::COUNT }>,
108            AllowRwCount<{ rw_allow::COUNT }>,
109        >,
110    ) -> HmacDriver<'a, H, DIGEST_LEN> {
111        HmacDriver {
112            hmac,
113            active: Cell::new(false),
114            apps: grant,
115            processid: OptionalCell::empty(),
116            data_buffer: TakeCell::new(data_buffer),
117            data_copied: Cell::new(0),
118            dest_buffer: TakeCell::new(dest_buffer),
119        }
120    }
121
122    fn run(&self) -> Result<(), ErrorCode> {
123        self.processid.map_or(Err(ErrorCode::RESERVE), |processid| {
124            self.apps
125                .enter(processid, |app, kernel_data| {
126                    kernel_data
127                        .get_readonly_processbuffer(ro_allow::KEY)
128                        .and_then(|key| {
129                            key.enter(|k| {
130                                if let Some(op) = &app.sha_operation {
131                                    let mut tmp_key_buffer: [u8; TMP_KEY_BUFFER_SIZE] =
132                                        [0; TMP_KEY_BUFFER_SIZE];
133                                    let key_len = core::cmp::min(k.len(), TMP_KEY_BUFFER_SIZE);
134                                    k[..key_len].copy_to_slice(&mut tmp_key_buffer[..key_len]);
135
136                                    match op {
137                                        ShaOperation::Sha256 => self
138                                            .hmac
139                                            .set_mode_hmacsha256(&tmp_key_buffer[..key_len]),
140                                        ShaOperation::Sha384 => self
141                                            .hmac
142                                            .set_mode_hmacsha384(&tmp_key_buffer[..key_len]),
143                                        ShaOperation::Sha512 => self
144                                            .hmac
145                                            .set_mode_hmacsha512(&tmp_key_buffer[..key_len]),
146                                    }
147                                } else {
148                                    Err(ErrorCode::INVAL)
149                                }
150                            })
151                        })
152                        .unwrap_or(Err(ErrorCode::RESERVE))?;
153
154                    kernel_data
155                        .get_readonly_processbuffer(ro_allow::DATA)
156                        .and_then(|data| {
157                            data.enter(|data| {
158                                let mut static_buffer_len = 0;
159                                self.data_buffer.map(|buf| {
160                                    // Determine the size of the static buffer we have
161                                    static_buffer_len = buf.len();
162
163                                    if static_buffer_len > data.len() {
164                                        static_buffer_len = data.len()
165                                    }
166
167                                    self.data_copied.set(static_buffer_len);
168
169                                    // Copy the data into the static buffer
170                                    data[..static_buffer_len]
171                                        .copy_to_slice(&mut buf[..static_buffer_len]);
172                                });
173
174                                // Add the data from the static buffer to the HMAC
175                                let mut lease_buf = SubSliceMut::new(
176                                    self.data_buffer.take().ok_or(ErrorCode::RESERVE)?,
177                                );
178                                lease_buf.slice(0..static_buffer_len);
179                                if let Err(e) = self.hmac.add_mut_data(lease_buf) {
180                                    self.data_buffer.replace(e.1.take());
181                                    return Err(e.0);
182                                }
183                                Ok(())
184                            })
185                        })
186                        .unwrap_or(Err(ErrorCode::RESERVE))
187                })
188                .unwrap_or_else(|err| Err(err.into()))
189        })
190    }
191
192    fn calculate_digest(&self) -> Result<(), ErrorCode> {
193        self.data_copied.set(0);
194
195        if let Err(e) = self
196            .hmac
197            .run(self.dest_buffer.take().ok_or(ErrorCode::RESERVE)?)
198        {
199            // Error, clear the processid and data
200            self.hmac.clear_data();
201            self.processid.clear();
202            self.dest_buffer.replace(e.1);
203
204            return Err(e.0);
205        }
206
207        Ok(())
208    }
209
210    fn verify_digest(&self) -> Result<(), ErrorCode> {
211        self.data_copied.set(0);
212
213        if let Err(e) = self
214            .hmac
215            .verify(self.dest_buffer.take().ok_or(ErrorCode::RESERVE)?)
216        {
217            // Error, clear the processid and data
218            self.hmac.clear_data();
219            self.processid.clear();
220            self.dest_buffer.replace(e.1);
221
222            return Err(e.0);
223        }
224
225        Ok(())
226    }
227
228    fn check_queue(&self) {
229        for appiter in self.apps.iter() {
230            let started_command = appiter.enter(|app, _| {
231                // If an app is already running let it complete
232                if self.processid.is_some() {
233                    return true;
234                }
235
236                // If this app has a pending command let's use it.
237                app.pending_run_app.take().is_some_and(|processid| {
238                    // Mark this driver as being in use.
239                    self.processid.set(processid);
240                    // Actually make the buzz happen.
241                    self.run() == Ok(())
242                })
243            });
244            if started_command {
245                break;
246            }
247        }
248    }
249}
250
251impl<
252        'a,
253        H: digest::Digest<'a, DIGEST_LEN>
254            + digest::HmacSha256
255            + digest::HmacSha384
256            + digest::HmacSha512,
257        const DIGEST_LEN: usize,
258    > digest::ClientData<DIGEST_LEN> for HmacDriver<'a, H, DIGEST_LEN>
259{
260    // Because data needs to be copied from a userspace buffer into a kernel (RAM) one,
261    // we always pass mut data; this callback should never be invoked.
262    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {}
263
264    fn add_mut_data_done(&self, _result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>) {
265        self.processid.map(move |id| {
266            self.apps
267                .enter(id, move |app, kernel_data| {
268                    let mut data_len = 0;
269                    let mut exit = false;
270                    let mut static_buffer_len = 0;
271
272                    self.data_buffer.replace(data.take());
273
274                    self.data_buffer.map(|buf| {
275                        let ret = kernel_data
276                            .get_readonly_processbuffer(ro_allow::DATA)
277                            .and_then(|data| {
278                                data.enter(|data| {
279                                    // Determine the size of the static buffer we have
280                                    static_buffer_len = buf.len();
281                                    // Determine how much data we have already copied
282                                    let copied_data = self.data_copied.get();
283
284                                    data_len = data.len();
285
286                                    if data_len > copied_data {
287                                        let remaining_data = &data[copied_data..];
288                                        let remaining_len = data_len - copied_data;
289
290                                        if remaining_len < static_buffer_len {
291                                            remaining_data.copy_to_slice(&mut buf[..remaining_len]);
292                                        } else {
293                                            remaining_data[..static_buffer_len].copy_to_slice(buf);
294                                        }
295                                    }
296                                    Ok(())
297                                })
298                            })
299                            .unwrap_or(Err(ErrorCode::RESERVE));
300
301                        if ret == Err(ErrorCode::RESERVE) {
302                            // No data buffer, clear the processid and data
303                            self.hmac.clear_data();
304                            self.processid.clear();
305                            exit = true;
306                        }
307                    });
308
309                    if exit {
310                        return;
311                    }
312
313                    if static_buffer_len > 0 {
314                        let copied_data = self.data_copied.get();
315
316                        if data_len > copied_data {
317                            // Update the amount of data copied
318                            self.data_copied.set(copied_data + static_buffer_len);
319
320                            let mut lease_buf = SubSliceMut::new(self.data_buffer.take().unwrap());
321
322                            // Add the data from the static buffer to the HMAC
323                            if data_len < (copied_data + static_buffer_len) {
324                                lease_buf.slice(..(data_len - copied_data))
325                            }
326
327                            if self.hmac.add_mut_data(lease_buf).is_err() {
328                                // Error, clear the processid and data
329                                self.hmac.clear_data();
330                                self.processid.clear();
331                                return;
332                            }
333
334                            // Return as we don't want to run the digest yet
335                            return;
336                        }
337                    }
338
339                    // If we get here we are ready to run the digest, reset the copied data
340                    if app.op.get().unwrap() == UserSpaceOp::Run {
341                        if let Err(e) = self.calculate_digest() {
342                            let _ =
343                                kernel_data.schedule_upcall(0, (into_statuscode(e.into()), 0, 0));
344                        }
345                    } else if app.op.get().unwrap() == UserSpaceOp::Verify {
346                        let _ = kernel_data
347                            .get_readonly_processbuffer(ro_allow::COMPARE)
348                            .and_then(|compare| {
349                                compare.enter(|compare| {
350                                    let mut static_buffer_len = 0;
351                                    self.dest_buffer.map(|buf| {
352                                        // Determine the size of the static buffer we have
353                                        static_buffer_len = buf.len();
354
355                                        if static_buffer_len > compare.len() {
356                                            static_buffer_len = compare.len()
357                                        }
358
359                                        self.data_copied.set(static_buffer_len);
360
361                                        // Copy the data into the static buffer
362                                        compare[..static_buffer_len]
363                                            .copy_to_slice(&mut buf[..static_buffer_len]);
364                                    });
365                                })
366                            });
367
368                        if let Err(e) = self.verify_digest() {
369                            let _ =
370                                kernel_data.schedule_upcall(1, (into_statuscode(e.into()), 0, 0));
371                        }
372                    } else {
373                        let _ = kernel_data.schedule_upcall(0, (0, 0, 0));
374                    }
375                })
376                .map_err(|err| {
377                    if err == kernel::process::Error::NoSuchApp
378                        || err == kernel::process::Error::InactiveApp
379                    {
380                        self.processid.clear();
381                    }
382                })
383        });
384
385        self.check_queue();
386    }
387}
388
389impl<
390        'a,
391        H: digest::Digest<'a, DIGEST_LEN>
392            + digest::HmacSha256
393            + digest::HmacSha384
394            + digest::HmacSha512,
395        const DIGEST_LEN: usize,
396    > digest::ClientHash<DIGEST_LEN> for HmacDriver<'a, H, DIGEST_LEN>
397{
398    fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; DIGEST_LEN]) {
399        self.processid.map(|id| {
400            self.apps
401                .enter(id, |_, kernel_data| {
402                    self.hmac.clear_data();
403
404                    let pointer = digest[0] as *mut u8;
405
406                    let _ = kernel_data
407                        .get_readwrite_processbuffer(rw_allow::DEST)
408                        .and_then(|dest| {
409                            dest.mut_enter(|dest| {
410                                let len = dest.len();
411
412                                if len < DIGEST_LEN {
413                                    dest.copy_from_slice(&digest[0..len]);
414                                } else {
415                                    dest[0..DIGEST_LEN].copy_from_slice(digest);
416                                }
417                            })
418                        });
419
420                    let _ = match result {
421                        Ok(()) => kernel_data.schedule_upcall(0, (0, pointer as usize, 0)),
422                        Err(e) => kernel_data
423                            .schedule_upcall(0, (into_statuscode(e.into()), pointer as usize, 0)),
424                    };
425
426                    // Clear the current processid as it has finished running
427                    self.processid.clear();
428                })
429                .map_err(|err| {
430                    if err == kernel::process::Error::NoSuchApp
431                        || err == kernel::process::Error::InactiveApp
432                    {
433                        self.processid.clear();
434                    }
435                })
436        });
437
438        self.check_queue();
439        self.dest_buffer.replace(digest);
440    }
441}
442
443impl<
444        'a,
445        H: digest::Digest<'a, DIGEST_LEN>
446            + digest::HmacSha256
447            + digest::HmacSha384
448            + digest::HmacSha512,
449        const DIGEST_LEN: usize,
450    > digest::ClientVerify<DIGEST_LEN> for HmacDriver<'a, H, DIGEST_LEN>
451{
452    fn verification_done(
453        &self,
454        result: Result<bool, ErrorCode>,
455        compare: &'static mut [u8; DIGEST_LEN],
456    ) {
457        self.processid.map(|id| {
458            self.apps
459                .enter(id, |_app, kernel_data| {
460                    self.hmac.clear_data();
461
462                    let _ = match result {
463                        Ok(equal) => kernel_data.schedule_upcall(1, (0, equal as usize, 0)),
464                        Err(e) => kernel_data.schedule_upcall(1, (into_statuscode(e.into()), 0, 0)),
465                    };
466
467                    // Clear the current processid as it has finished running
468                    self.processid.clear();
469                })
470                .map_err(|err| {
471                    if err == kernel::process::Error::NoSuchApp
472                        || err == kernel::process::Error::InactiveApp
473                    {
474                        self.processid.clear();
475                    }
476                })
477        });
478
479        self.check_queue();
480        self.dest_buffer.replace(compare);
481    }
482}
483
484/// Specify memory regions to be used.
485///
486/// ### `allow_num`
487///
488/// - `0`: Allow a buffer for storing the key. The kernel will read from this
489///   when running This should not be changed after running `run` until the HMAC
490///   has completed
491/// - `1`: Allow a buffer for storing the buffer. The kernel will read from this
492///   when running This should not be changed after running `run` until the HMAC
493///   has completed
494/// - `2`: Allow a buffer for storing the digest. The kernel will fill this with
495///   the HMAC digest before calling the `hash_done` callback.
496impl<
497        'a,
498        H: digest::Digest<'a, DIGEST_LEN>
499            + digest::HmacSha256
500            + digest::HmacSha384
501            + digest::HmacSha512,
502        const DIGEST_LEN: usize,
503    > SyscallDriver for HmacDriver<'a, H, DIGEST_LEN>
504{
505    // Subscribe to HmacDriver events.
506    //
507    // ### `subscribe_num`
508    //
509    // - `0`: Subscribe to interrupts from HMAC events. The callback signature
510    //   is `fn(result: u32)`
511
512    /// Setup and run the HMAC hardware
513    ///
514    /// We expect userspace to setup buffers for the key, data and digest.
515    /// These buffers must be allocated and specified to the kernel from the
516    /// above allow calls.
517    ///
518    /// We expect userspace not to change the value while running. If userspace
519    /// changes the value we have no guarantee of what is passed to the
520    /// hardware. This isn't a security issue, it will just prove the requesting
521    /// app with invalid data.
522    ///
523    /// The driver will take care of clearing data from the underlying implementation
524    /// by calling the `clear_data()` function when the `hash_complete()` callback
525    /// is called or if an error is encountered.
526    ///
527    /// ### `command_num`
528    ///
529    /// - `0`: set_algorithm
530    /// - `1`: run
531    /// - `2`: update
532    /// - `3`: finish
533    fn command(
534        &self,
535        command_num: usize,
536        data1: usize,
537        _data2: usize,
538        processid: ProcessId,
539    ) -> CommandReturn {
540        let match_or_empty_or_nonexistant = self.processid.map_or(true, |owning_app| {
541            // We have recorded that an app has ownership of the HMAC.
542
543            // If the HMAC is still active, then we need to wait for the operation
544            // to finish and the app, whether it exists or not (it may have crashed),
545            // still owns this capsule. If the HMAC is not active, then
546            // we need to verify that that application still exists, and remove
547            // it as owner if not.
548            if self.active.get() {
549                owning_app == processid
550            } else {
551                // Check the app still exists.
552                //
553                // If the `.enter()` succeeds, then the app is still valid, and
554                // we can check if the owning app matches the one that called
555                // the command. If the `.enter()` fails, then the owning app no
556                // longer exists and we return `true` to signify the
557                // "or_nonexistant" case.
558                self.apps
559                    .enter(owning_app, |_, _| owning_app == processid)
560                    .unwrap_or(true)
561            }
562        });
563
564        let app_match = self.processid.map_or(false, |owning_app| {
565            // We have recorded that an app has ownership of the HMAC.
566
567            // If the HMAC is still active, then we need to wait for the operation
568            // to finish and the app, whether it exists or not (it may have crashed),
569            // still owns this capsule. If the HMAC is not active, then
570            // we need to verify that that application still exists, and remove
571            // it as owner if not.
572            if self.active.get() {
573                owning_app == processid
574            } else {
575                // Check the app still exists.
576                //
577                // If the `.enter()` succeeds, then the app is still valid, and
578                // we can check if the owning app matches the one that called
579                // the command. If the `.enter()` fails, then the owning app no
580                // longer exists and we return `true` to signify the
581                // "or_nonexistant" case.
582                self.apps
583                    .enter(owning_app, |_, _| owning_app == processid)
584                    .unwrap_or(true)
585            }
586        });
587
588        // Try the commands where we want to start an operation *not* entered in
589        // an app grant first.
590        if match_or_empty_or_nonexistant
591            && (command_num == 1 || command_num == 2 || command_num == 4)
592        {
593            self.processid.set(processid);
594
595            let _ = self.apps.enter(processid, |app, _| {
596                if command_num == 1 {
597                    // run
598                    // Use key and data to compute hash
599                    // This will trigger a callback once the digest is generated
600                    app.op.set(Some(UserSpaceOp::Run));
601                } else if command_num == 2 {
602                    // update
603                    // Input key and data, don't compute final hash yet
604                    // This will trigger a callback once the data has been added.
605                    app.op.set(Some(UserSpaceOp::Update));
606                } else if command_num == 4 {
607                    // verify
608                    // Use key and data to compute hash and comapre it against
609                    // the digest
610                    app.op.set(Some(UserSpaceOp::Verify));
611                }
612            });
613
614            return if let Err(e) = self.run() {
615                self.hmac.clear_data();
616                self.processid.clear();
617                self.check_queue();
618                CommandReturn::failure(e)
619            } else {
620                CommandReturn::success()
621            };
622        }
623
624        self.apps
625            .enter(processid, |app, kernel_data| {
626                match command_num {
627                    // set_algorithm
628                    0 => {
629                        match data1 {
630                            // SHA256
631                            0 => {
632                                app.sha_operation = Some(ShaOperation::Sha256);
633                                CommandReturn::success()
634                            }
635                            // SHA384
636                            1 => {
637                                app.sha_operation = Some(ShaOperation::Sha384);
638                                CommandReturn::success()
639                            }
640                            // SHA512
641                            2 => {
642                                app.sha_operation = Some(ShaOperation::Sha512);
643                                CommandReturn::success()
644                            }
645                            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
646                        }
647                    }
648
649                    // run
650                    1 => {
651                        // There is an active app, so queue this request (if possible).
652                        if app.pending_run_app.is_some() {
653                            // No more room in the queue, nowhere to store this
654                            // request.
655                            CommandReturn::failure(ErrorCode::NOMEM)
656                        } else {
657                            // We can store this, so lets do it.
658                            app.pending_run_app = Some(processid);
659                            app.op.set(Some(UserSpaceOp::Run));
660                            CommandReturn::success()
661                        }
662                    }
663
664                    // update
665                    2 => {
666                        // There is an active app, so queue this request (if possible).
667                        if app.pending_run_app.is_some() {
668                            // No more room in the queue, nowhere to store this
669                            // request.
670                            CommandReturn::failure(ErrorCode::NOMEM)
671                        } else {
672                            // We can store this, so lets do it.
673                            app.pending_run_app = Some(processid);
674                            app.op.set(Some(UserSpaceOp::Update));
675                            CommandReturn::success()
676                        }
677                    }
678
679                    // finish
680                    // Compute final hash yet, useful after a update command
681                    3 => {
682                        if app_match {
683                            if let Err(e) = self.calculate_digest() {
684                                let _ = kernel_data.schedule_upcall(
685                                    0,
686                                    (kernel::errorcode::into_statuscode(e.into()), 0, 0),
687                                );
688                            }
689                            CommandReturn::success()
690                        } else {
691                            // We don't queue this request, the user has to call
692                            // `update` first.
693                            CommandReturn::failure(ErrorCode::OFF)
694                        }
695                    }
696
697                    // verify
698                    4 => {
699                        // There is an active app, so queue this request (if possible).
700                        if app.pending_run_app.is_some() {
701                            // No more room in the queue, nowhere to store this
702                            // request.
703                            CommandReturn::failure(ErrorCode::NOMEM)
704                        } else {
705                            // We can store this, so lets do it.
706                            app.pending_run_app = Some(processid);
707                            app.op.set(Some(UserSpaceOp::Verify));
708                            CommandReturn::success()
709                        }
710                    }
711
712                    // verify_finish
713                    // Use key and data to compute hash and compare it against
714                    // the digest, useful after a update command
715                    5 => {
716                        if app_match {
717                            let _ = kernel_data
718                                .get_readonly_processbuffer(ro_allow::COMPARE)
719                                .and_then(|compare| {
720                                    compare.enter(|compare| {
721                                        let mut static_buffer_len = 0;
722                                        self.dest_buffer.map(|buf| {
723                                            // Determine the size of the static buffer we have
724                                            static_buffer_len = buf.len();
725
726                                            if static_buffer_len > compare.len() {
727                                                static_buffer_len = compare.len()
728                                            }
729
730                                            self.data_copied.set(static_buffer_len);
731
732                                            // Copy the data into the static buffer
733                                            compare[..static_buffer_len]
734                                                .copy_to_slice(&mut buf[..static_buffer_len]);
735                                        });
736                                    })
737                                });
738
739                            if let Err(e) = self.verify_digest() {
740                                let _ = kernel_data
741                                    .schedule_upcall(1, (into_statuscode(e.into()), 0, 0));
742                            }
743                            CommandReturn::success()
744                        } else {
745                            // We don't queue this request, the user has to call
746                            // `update` first.
747                            CommandReturn::failure(ErrorCode::OFF)
748                        }
749                    }
750
751                    // default
752                    _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
753                }
754            })
755            .unwrap_or_else(|err| err.into())
756    }
757
758    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
759        self.apps.enter(processid, |_, _| {})
760    }
761}
762
763#[derive(Copy, Clone, PartialEq)]
764enum UserSpaceOp {
765    Run,
766    Update,
767    Verify,
768}
769
770#[derive(Default)]
771pub struct App {
772    pending_run_app: Option<ProcessId>,
773    sha_operation: Option<ShaOperation>,
774    op: Cell<Option<UserSpaceOp>>,
775}