firmware_uefi/service/
crypto.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Crypto types defined in `BiosInterface.h`
5
6use crate::UefiDevice;
7use guestmem::GuestMemoryError;
8use uefi_specs::hyperv::crypto::CryptoCommandDescriptor;
9use uefi_specs::uefi::common::EfiStatus;
10
11impl UefiDevice {
12    pub(crate) fn crypto_handle_command(&mut self, desc_addr: u64) {
13        let mut desc: CryptoCommandDescriptor = match self.gm.read_plain(desc_addr) {
14            Ok(desc) => desc,
15            Err(err) => {
16                tracelimit::warn_ratelimited!(
17                    error = &err as &dyn std::error::Error,
18                    "Could not read CryptoCommandDescriptor from guest memory",
19                );
20                return;
21            }
22        };
23
24        let status = match self.crypto_handle_command_inner(desc_addr, desc) {
25            Ok(status) => status,
26            Err(err) => {
27                tracelimit::warn_ratelimited!(
28                    error = &err as &dyn std::error::Error,
29                    "Guest memory error while handling crypto command",
30                );
31                EfiStatus::DEVICE_ERROR
32            }
33        };
34        desc.status = status.into();
35
36        if let Err(err) = self.gm.write_plain(desc_addr, &desc) {
37            tracelimit::warn_ratelimited!(
38                error = &err as &dyn std::error::Error,
39                "Could not write CryptoCommandDescriptor into guest memory",
40            );
41        }
42    }
43
44    fn crypto_handle_command_inner(
45        &mut self,
46        desc_addr: u64,
47        desc: CryptoCommandDescriptor,
48    ) -> Result<EfiStatus, GuestMemoryError> {
49        use uefi_specs::hyperv::crypto::CryptoCommand;
50
51        let command_addr = desc_addr + size_of_val(&desc) as u64;
52
53        match desc.command {
54            CryptoCommand::GET_RANDOM_NUMBER => {
55                use uefi_specs::hyperv::crypto::CryptoGetRandomNumberParams;
56                // Our current UEFI implementation should never ask for more than 64 bits (8 bytes) at a time
57                // Larger guest requests will be divided into 8-byte chunks by the firmware.
58                const MAXIMUM_RNG_SIZE: usize = 8;
59
60                let command: CryptoGetRandomNumberParams = self.gm.read_plain(command_addr)?;
61                let buffer_size = command.buffer_size as usize;
62
63                if buffer_size > MAXIMUM_RNG_SIZE {
64                    return Ok(EfiStatus::INVALID_PARAMETER);
65                }
66
67                let random_number = &mut [0; MAXIMUM_RNG_SIZE][..buffer_size];
68                getrandom::fill(random_number).expect("rng failure");
69
70                self.gm
71                    .write_at(command.buffer_address.into(), random_number)?;
72
73                Ok(EfiStatus::SUCCESS)
74            }
75            command => {
76                tracelimit::warn_ratelimited!(?command, "unknown or unhandled crypto command");
77                Ok(EfiStatus::DEVICE_ERROR)
78            }
79        }
80    }
81}