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                            kernel_data
343                                .schedule_upcall(0, (into_statuscode(e.into()), 0, 0))
344                                .ok();
345                        }
346                    } else if app.op.get().unwrap() == UserSpaceOp::Verify {
347                        let _ = kernel_data
348                            .get_readonly_processbuffer(ro_allow::COMPARE)
349                            .and_then(|compare| {
350                                compare.enter(|compare| {
351                                    let mut static_buffer_len = 0;
352                                    self.dest_buffer.map(|buf| {
353                                        // Determine the size of the static buffer we have
354                                        static_buffer_len = buf.len();
355
356                                        if static_buffer_len > compare.len() {
357                                            static_buffer_len = compare.len()
358                                        }
359
360                                        self.data_copied.set(static_buffer_len);
361
362                                        // Copy the data into the static buffer
363                                        compare[..static_buffer_len]
364                                            .copy_to_slice(&mut buf[..static_buffer_len]);
365                                    });
366                                })
367                            });
368
369                        if let Err(e) = self.verify_digest() {
370                            kernel_data
371                                .schedule_upcall(1, (into_statuscode(e.into()), 0, 0))
372                                .ok();
373                        }
374                    } else {
375                        kernel_data.schedule_upcall(0, (0, 0, 0)).ok();
376                    }
377                })
378                .map_err(|err| {
379                    if err == kernel::process::Error::NoSuchApp
380                        || err == kernel::process::Error::InactiveApp
381                    {
382                        self.processid.clear();
383                    }
384                })
385        });
386
387        self.check_queue();
388    }
389}
390
391impl<
392        'a,
393        H: digest::Digest<'a, DIGEST_LEN>
394            + digest::HmacSha256
395            + digest::HmacSha384
396            + digest::HmacSha512,
397        const DIGEST_LEN: usize,
398    > digest::ClientHash<DIGEST_LEN> for HmacDriver<'a, H, DIGEST_LEN>
399{
400    fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; DIGEST_LEN]) {
401        self.processid.map(|id| {
402            self.apps
403                .enter(id, |_, kernel_data| {
404                    self.hmac.clear_data();
405
406                    let pointer = digest[0] as *mut u8;
407
408                    let _ = kernel_data
409                        .get_readwrite_processbuffer(rw_allow::DEST)
410                        .and_then(|dest| {
411                            dest.mut_enter(|dest| {
412                                let len = dest.len();
413
414                                if len < DIGEST_LEN {
415                                    dest.copy_from_slice(&digest[0..len]);
416                                } else {
417                                    dest[0..DIGEST_LEN].copy_from_slice(digest);
418                                }
419                            })
420                        });
421
422                    match result {
423                        Ok(()) => kernel_data.schedule_upcall(0, (0, pointer as usize, 0)),
424                        Err(e) => kernel_data
425                            .schedule_upcall(0, (into_statuscode(e.into()), pointer as usize, 0)),
426                    }
427                    .ok();
428
429                    // Clear the current processid as it has finished running
430                    self.processid.clear();
431                })
432                .map_err(|err| {
433                    if err == kernel::process::Error::NoSuchApp
434                        || err == kernel::process::Error::InactiveApp
435                    {
436                        self.processid.clear();
437                    }
438                })
439        });
440
441        self.check_queue();
442        self.dest_buffer.replace(digest);
443    }
444}
445
446impl<
447        'a,
448        H: digest::Digest<'a, DIGEST_LEN>
449            + digest::HmacSha256
450            + digest::HmacSha384
451            + digest::HmacSha512,
452        const DIGEST_LEN: usize,
453    > digest::ClientVerify<DIGEST_LEN> for HmacDriver<'a, H, DIGEST_LEN>
454{
455    fn verification_done(
456        &self,
457        result: Result<bool, ErrorCode>,
458        compare: &'static mut [u8; DIGEST_LEN],
459    ) {
460        self.processid.map(|id| {
461            self.apps
462                .enter(id, |_app, kernel_data| {
463                    self.hmac.clear_data();
464
465                    match result {
466                        Ok(equal) => kernel_data.schedule_upcall(1, (0, equal as usize, 0)),
467                        Err(e) => kernel_data.schedule_upcall(1, (into_statuscode(e.into()), 0, 0)),
468                    }
469                    .ok();
470
471                    // Clear the current processid as it has finished running
472                    self.processid.clear();
473                })
474                .map_err(|err| {
475                    if err == kernel::process::Error::NoSuchApp
476                        || err == kernel::process::Error::InactiveApp
477                    {
478                        self.processid.clear();
479                    }
480                })
481        });
482
483        self.check_queue();
484        self.dest_buffer.replace(compare);
485    }
486}
487
488/// Specify memory regions to be used.
489///
490/// ### `allow_num`
491///
492/// - `0`: Allow a buffer for storing the key. The kernel will read from this
493///   when running This should not be changed after running `run` until the HMAC
494///   has completed
495/// - `1`: Allow a buffer for storing the buffer. The kernel will read from this
496///   when running This should not be changed after running `run` until the HMAC
497///   has completed
498/// - `2`: Allow a buffer for storing the digest. The kernel will fill this with
499///   the HMAC digest before calling the `hash_done` callback.
500impl<
501        'a,
502        H: digest::Digest<'a, DIGEST_LEN>
503            + digest::HmacSha256
504            + digest::HmacSha384
505            + digest::HmacSha512,
506        const DIGEST_LEN: usize,
507    > SyscallDriver for HmacDriver<'a, H, DIGEST_LEN>
508{
509    // Subscribe to HmacDriver events.
510    //
511    // ### `subscribe_num`
512    //
513    // - `0`: Subscribe to interrupts from HMAC events. The callback signature
514    //   is `fn(result: u32)`
515
516    /// Setup and run the HMAC hardware
517    ///
518    /// We expect userspace to setup buffers for the key, data and digest.
519    /// These buffers must be allocated and specified to the kernel from the
520    /// above allow calls.
521    ///
522    /// We expect userspace not to change the value while running. If userspace
523    /// changes the value we have no guarantee of what is passed to the
524    /// hardware. This isn't a security issue, it will just prove the requesting
525    /// app with invalid data.
526    ///
527    /// The driver will take care of clearing data from the underlying implementation
528    /// by calling the `clear_data()` function when the `hash_complete()` callback
529    /// is called or if an error is encountered.
530    ///
531    /// ### `command_num`
532    ///
533    /// - `0`: set_algorithm
534    /// - `1`: run
535    /// - `2`: update
536    /// - `3`: finish
537    fn command(
538        &self,
539        command_num: usize,
540        data1: usize,
541        _data2: usize,
542        processid: ProcessId,
543    ) -> CommandReturn {
544        let match_or_empty_or_nonexistant = self.processid.map_or(true, |owning_app| {
545            // We have recorded that an app has ownership of the HMAC.
546
547            // If the HMAC is still active, then we need to wait for the operation
548            // to finish and the app, whether it exists or not (it may have crashed),
549            // still owns this capsule. If the HMAC is not active, then
550            // we need to verify that that application still exists, and remove
551            // it as owner if not.
552            if self.active.get() {
553                owning_app == processid
554            } else {
555                // Check the app still exists.
556                //
557                // If the `.enter()` succeeds, then the app is still valid, and
558                // we can check if the owning app matches the one that called
559                // the command. If the `.enter()` fails, then the owning app no
560                // longer exists and we return `true` to signify the
561                // "or_nonexistant" case.
562                self.apps
563                    .enter(owning_app, |_, _| owning_app == processid)
564                    .unwrap_or(true)
565            }
566        });
567
568        let app_match = self.processid.map_or(false, |owning_app| {
569            // We have recorded that an app has ownership of the HMAC.
570
571            // If the HMAC is still active, then we need to wait for the operation
572            // to finish and the app, whether it exists or not (it may have crashed),
573            // still owns this capsule. If the HMAC is not active, then
574            // we need to verify that that application still exists, and remove
575            // it as owner if not.
576            if self.active.get() {
577                owning_app == processid
578            } else {
579                // Check the app still exists.
580                //
581                // If the `.enter()` succeeds, then the app is still valid, and
582                // we can check if the owning app matches the one that called
583                // the command. If the `.enter()` fails, then the owning app no
584                // longer exists and we return `true` to signify the
585                // "or_nonexistant" case.
586                self.apps
587                    .enter(owning_app, |_, _| owning_app == processid)
588                    .unwrap_or(true)
589            }
590        });
591
592        // Try the commands where we want to start an operation *not* entered in
593        // an app grant first.
594        if match_or_empty_or_nonexistant
595            && (command_num == 1 || command_num == 2 || command_num == 4)
596        {
597            self.processid.set(processid);
598
599            let _ = self.apps.enter(processid, |app, _| {
600                if command_num == 1 {
601                    // run
602                    // Use key and data to compute hash
603                    // This will trigger a callback once the digest is generated
604                    app.op.set(Some(UserSpaceOp::Run));
605                } else if command_num == 2 {
606                    // update
607                    // Input key and data, don't compute final hash yet
608                    // This will trigger a callback once the data has been added.
609                    app.op.set(Some(UserSpaceOp::Update));
610                } else if command_num == 4 {
611                    // verify
612                    // Use key and data to compute hash and comapre it against
613                    // the digest
614                    app.op.set(Some(UserSpaceOp::Verify));
615                }
616            });
617
618            return if let Err(e) = self.run() {
619                self.hmac.clear_data();
620                self.processid.clear();
621                self.check_queue();
622                CommandReturn::failure(e)
623            } else {
624                CommandReturn::success()
625            };
626        }
627
628        self.apps
629            .enter(processid, |app, kernel_data| {
630                match command_num {
631                    // set_algorithm
632                    0 => {
633                        match data1 {
634                            // SHA256
635                            0 => {
636                                app.sha_operation = Some(ShaOperation::Sha256);
637                                CommandReturn::success()
638                            }
639                            // SHA384
640                            1 => {
641                                app.sha_operation = Some(ShaOperation::Sha384);
642                                CommandReturn::success()
643                            }
644                            // SHA512
645                            2 => {
646                                app.sha_operation = Some(ShaOperation::Sha512);
647                                CommandReturn::success()
648                            }
649                            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
650                        }
651                    }
652
653                    // run
654                    1 => {
655                        // There is an active app, so queue this request (if possible).
656                        if app.pending_run_app.is_some() {
657                            // No more room in the queue, nowhere to store this
658                            // request.
659                            CommandReturn::failure(ErrorCode::NOMEM)
660                        } else {
661                            // We can store this, so lets do it.
662                            app.pending_run_app = Some(processid);
663                            app.op.set(Some(UserSpaceOp::Run));
664                            CommandReturn::success()
665                        }
666                    }
667
668                    // update
669                    2 => {
670                        // There is an active app, so queue this request (if possible).
671                        if app.pending_run_app.is_some() {
672                            // No more room in the queue, nowhere to store this
673                            // request.
674                            CommandReturn::failure(ErrorCode::NOMEM)
675                        } else {
676                            // We can store this, so lets do it.
677                            app.pending_run_app = Some(processid);
678                            app.op.set(Some(UserSpaceOp::Update));
679                            CommandReturn::success()
680                        }
681                    }
682
683                    // finish
684                    // Compute final hash yet, useful after a update command
685                    3 => {
686                        if app_match {
687                            if let Err(e) = self.calculate_digest() {
688                                kernel_data
689                                    .schedule_upcall(
690                                        0,
691                                        (kernel::errorcode::into_statuscode(e.into()), 0, 0),
692                                    )
693                                    .ok();
694                            }
695                            CommandReturn::success()
696                        } else {
697                            // We don't queue this request, the user has to call
698                            // `update` first.
699                            CommandReturn::failure(ErrorCode::OFF)
700                        }
701                    }
702
703                    // verify
704                    4 => {
705                        // There is an active app, so queue this request (if possible).
706                        if app.pending_run_app.is_some() {
707                            // No more room in the queue, nowhere to store this
708                            // request.
709                            CommandReturn::failure(ErrorCode::NOMEM)
710                        } else {
711                            // We can store this, so lets do it.
712                            app.pending_run_app = Some(processid);
713                            app.op.set(Some(UserSpaceOp::Verify));
714                            CommandReturn::success()
715                        }
716                    }
717
718                    // verify_finish
719                    // Use key and data to compute hash and compare it against
720                    // the digest, useful after a update command
721                    5 => {
722                        if app_match {
723                            let _ = kernel_data
724                                .get_readonly_processbuffer(ro_allow::COMPARE)
725                                .and_then(|compare| {
726                                    compare.enter(|compare| {
727                                        let mut static_buffer_len = 0;
728                                        self.dest_buffer.map(|buf| {
729                                            // Determine the size of the static buffer we have
730                                            static_buffer_len = buf.len();
731
732                                            if static_buffer_len > compare.len() {
733                                                static_buffer_len = compare.len()
734                                            }
735
736                                            self.data_copied.set(static_buffer_len);
737
738                                            // Copy the data into the static buffer
739                                            compare[..static_buffer_len]
740                                                .copy_to_slice(&mut buf[..static_buffer_len]);
741                                        });
742                                    })
743                                });
744
745                            if let Err(e) = self.verify_digest() {
746                                kernel_data
747                                    .schedule_upcall(1, (into_statuscode(e.into()), 0, 0))
748                                    .ok();
749                            }
750                            CommandReturn::success()
751                        } else {
752                            // We don't queue this request, the user has to call
753                            // `update` first.
754                            CommandReturn::failure(ErrorCode::OFF)
755                        }
756                    }
757
758                    // default
759                    _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
760                }
761            })
762            .unwrap_or_else(|err| err.into())
763    }
764
765    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
766        self.apps.enter(processid, |_, _| {})
767    }
768}
769
770#[derive(Copy, Clone, PartialEq)]
771enum UserSpaceOp {
772    Run,
773    Update,
774    Verify,
775}
776
777#[derive(Default)]
778pub struct App {
779    pending_run_app: Option<ProcessId>,
780    sha_operation: Option<ShaOperation>,
781    op: Cell<Option<UserSpaceOp>>,
782}