xref: /aosp_15_r20/system/security/prng_seeder/src/main.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker // Copyright (C) 2022 The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker 
15*e1997b9aSAndroid Build Coastguard Worker //! FIPS compliant random number conditioner. Reads from /dev/hw_random
16*e1997b9aSAndroid Build Coastguard Worker //! and applies the NIST SP 800-90A CTR DRBG strategy to provide
17*e1997b9aSAndroid Build Coastguard Worker //! pseudorandom bytes to clients which connect to a socket provided
18*e1997b9aSAndroid Build Coastguard Worker //! by init.
19*e1997b9aSAndroid Build Coastguard Worker 
20*e1997b9aSAndroid Build Coastguard Worker mod conditioner;
21*e1997b9aSAndroid Build Coastguard Worker mod drbg;
22*e1997b9aSAndroid Build Coastguard Worker 
23*e1997b9aSAndroid Build Coastguard Worker use std::{
24*e1997b9aSAndroid Build Coastguard Worker     convert::Infallible,
25*e1997b9aSAndroid Build Coastguard Worker     fs::remove_file,
26*e1997b9aSAndroid Build Coastguard Worker     io::ErrorKind,
27*e1997b9aSAndroid Build Coastguard Worker     os::unix::net::UnixListener,
28*e1997b9aSAndroid Build Coastguard Worker     path::{Path, PathBuf},
29*e1997b9aSAndroid Build Coastguard Worker };
30*e1997b9aSAndroid Build Coastguard Worker 
31*e1997b9aSAndroid Build Coastguard Worker use anyhow::{ensure, Context, Result};
32*e1997b9aSAndroid Build Coastguard Worker use clap::Parser;
33*e1997b9aSAndroid Build Coastguard Worker use log::{error, info, LevelFilter};
34*e1997b9aSAndroid Build Coastguard Worker use nix::sys::signal;
35*e1997b9aSAndroid Build Coastguard Worker use tokio::{io::AsyncWriteExt, net::UnixListener as TokioUnixListener};
36*e1997b9aSAndroid Build Coastguard Worker 
37*e1997b9aSAndroid Build Coastguard Worker use crate::conditioner::ConditionerBuilder;
38*e1997b9aSAndroid Build Coastguard Worker 
39*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Parser)]
40*e1997b9aSAndroid Build Coastguard Worker struct Cli {
41*e1997b9aSAndroid Build Coastguard Worker     #[clap(long, default_value = "/dev/hw_random")]
42*e1997b9aSAndroid Build Coastguard Worker     source: PathBuf,
43*e1997b9aSAndroid Build Coastguard Worker     #[clap(long)]
44*e1997b9aSAndroid Build Coastguard Worker     socket: Option<PathBuf>,
45*e1997b9aSAndroid Build Coastguard Worker }
46*e1997b9aSAndroid Build Coastguard Worker 
configure_logging() -> Result<()>47*e1997b9aSAndroid Build Coastguard Worker fn configure_logging() -> Result<()> {
48*e1997b9aSAndroid Build Coastguard Worker     ensure!(
49*e1997b9aSAndroid Build Coastguard Worker         logger::init(
50*e1997b9aSAndroid Build Coastguard Worker             logger::Config::default()
51*e1997b9aSAndroid Build Coastguard Worker                 .with_tag_on_device("prng_seeder")
52*e1997b9aSAndroid Build Coastguard Worker                 .with_max_level(LevelFilter::Info)
53*e1997b9aSAndroid Build Coastguard Worker         ),
54*e1997b9aSAndroid Build Coastguard Worker         "log configuration failed"
55*e1997b9aSAndroid Build Coastguard Worker     );
56*e1997b9aSAndroid Build Coastguard Worker     Ok(())
57*e1997b9aSAndroid Build Coastguard Worker }
58*e1997b9aSAndroid Build Coastguard Worker 
get_socket(path: &Path) -> Result<UnixListener>59*e1997b9aSAndroid Build Coastguard Worker fn get_socket(path: &Path) -> Result<UnixListener> {
60*e1997b9aSAndroid Build Coastguard Worker     if let Err(e) = remove_file(path) {
61*e1997b9aSAndroid Build Coastguard Worker         if e.kind() != ErrorKind::NotFound {
62*e1997b9aSAndroid Build Coastguard Worker             return Err(e).context(format!("Removing old socket: {}", path.display()));
63*e1997b9aSAndroid Build Coastguard Worker         }
64*e1997b9aSAndroid Build Coastguard Worker     } else {
65*e1997b9aSAndroid Build Coastguard Worker         info!("Deleted old {}", path.display());
66*e1997b9aSAndroid Build Coastguard Worker     }
67*e1997b9aSAndroid Build Coastguard Worker     UnixListener::bind(path)
68*e1997b9aSAndroid Build Coastguard Worker         .with_context(|| format!("In get_socket: binding socket to {}", path.display()))
69*e1997b9aSAndroid Build Coastguard Worker }
70*e1997b9aSAndroid Build Coastguard Worker 
setup() -> Result<(ConditionerBuilder, UnixListener)>71*e1997b9aSAndroid Build Coastguard Worker fn setup() -> Result<(ConditionerBuilder, UnixListener)> {
72*e1997b9aSAndroid Build Coastguard Worker     // SAFETY: nobody has taken ownership of the inherited FDs yet.
73*e1997b9aSAndroid Build Coastguard Worker     unsafe { rustutils::inherited_fd::init_once() }
74*e1997b9aSAndroid Build Coastguard Worker         .context("In setup, failed to own inherited FDs")?;
75*e1997b9aSAndroid Build Coastguard Worker     configure_logging()?;
76*e1997b9aSAndroid Build Coastguard Worker     let cli = Cli::try_parse()?;
77*e1997b9aSAndroid Build Coastguard Worker     // SAFETY: Nothing else sets the signal handler, so either it was set here or it is the default.
78*e1997b9aSAndroid Build Coastguard Worker     unsafe { signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigIgn) }
79*e1997b9aSAndroid Build Coastguard Worker         .context("In setup, setting SIGPIPE to SIG_IGN")?;
80*e1997b9aSAndroid Build Coastguard Worker 
81*e1997b9aSAndroid Build Coastguard Worker     let listener = match cli.socket {
82*e1997b9aSAndroid Build Coastguard Worker         Some(path) => get_socket(path.as_path())?,
83*e1997b9aSAndroid Build Coastguard Worker         None => rustutils::sockets::android_get_control_socket("prng_seeder")
84*e1997b9aSAndroid Build Coastguard Worker             .context("In setup, calling android_get_control_socket")?
85*e1997b9aSAndroid Build Coastguard Worker             .into(),
86*e1997b9aSAndroid Build Coastguard Worker     };
87*e1997b9aSAndroid Build Coastguard Worker     let hwrng = std::fs::File::open(&cli.source)
88*e1997b9aSAndroid Build Coastguard Worker         .with_context(|| format!("Unable to open hwrng {}", cli.source.display()))?;
89*e1997b9aSAndroid Build Coastguard Worker     let cb = ConditionerBuilder::new(hwrng)?;
90*e1997b9aSAndroid Build Coastguard Worker     Ok((cb, listener))
91*e1997b9aSAndroid Build Coastguard Worker }
92*e1997b9aSAndroid Build Coastguard Worker 
listen_loop(cb: ConditionerBuilder, listener: UnixListener) -> Result<Infallible>93*e1997b9aSAndroid Build Coastguard Worker async fn listen_loop(cb: ConditionerBuilder, listener: UnixListener) -> Result<Infallible> {
94*e1997b9aSAndroid Build Coastguard Worker     let mut conditioner = cb.build();
95*e1997b9aSAndroid Build Coastguard Worker     listener.set_nonblocking(true).context("In listen_loop, on set_nonblocking")?;
96*e1997b9aSAndroid Build Coastguard Worker     let listener = TokioUnixListener::from_std(listener).context("In listen_loop, on from_std")?;
97*e1997b9aSAndroid Build Coastguard Worker     info!("Starting listen loop");
98*e1997b9aSAndroid Build Coastguard Worker     loop {
99*e1997b9aSAndroid Build Coastguard Worker         match listener.accept().await {
100*e1997b9aSAndroid Build Coastguard Worker             Ok((mut stream, _)) => {
101*e1997b9aSAndroid Build Coastguard Worker                 let new_bytes = conditioner.request()?;
102*e1997b9aSAndroid Build Coastguard Worker                 tokio::spawn(async move {
103*e1997b9aSAndroid Build Coastguard Worker                     if let Err(e) = stream.write_all(&new_bytes).await {
104*e1997b9aSAndroid Build Coastguard Worker                         error!("Request failed: {}", e);
105*e1997b9aSAndroid Build Coastguard Worker                     }
106*e1997b9aSAndroid Build Coastguard Worker                 });
107*e1997b9aSAndroid Build Coastguard Worker                 conditioner.reseed_if_necessary().await?;
108*e1997b9aSAndroid Build Coastguard Worker             }
109*e1997b9aSAndroid Build Coastguard Worker             Err(e) if e.kind() == ErrorKind::Interrupted => {}
110*e1997b9aSAndroid Build Coastguard Worker             Err(e) => return Err(e).context("accept on socket failed"),
111*e1997b9aSAndroid Build Coastguard Worker         }
112*e1997b9aSAndroid Build Coastguard Worker     }
113*e1997b9aSAndroid Build Coastguard Worker }
114*e1997b9aSAndroid Build Coastguard Worker 
run() -> Result<Infallible>115*e1997b9aSAndroid Build Coastguard Worker fn run() -> Result<Infallible> {
116*e1997b9aSAndroid Build Coastguard Worker     let (cb, listener) = match setup() {
117*e1997b9aSAndroid Build Coastguard Worker         Ok(t) => t,
118*e1997b9aSAndroid Build Coastguard Worker         Err(e) => {
119*e1997b9aSAndroid Build Coastguard Worker             // If setup fails, just hang forever. That way init doesn't respawn us.
120*e1997b9aSAndroid Build Coastguard Worker             error!("Hanging forever because setup failed: {:?}", e);
121*e1997b9aSAndroid Build Coastguard Worker             // Logs are sometimes mysteriously not being logged, so print too
122*e1997b9aSAndroid Build Coastguard Worker             println!("prng_seeder: Hanging forever because setup failed: {:?}", e);
123*e1997b9aSAndroid Build Coastguard Worker             loop {
124*e1997b9aSAndroid Build Coastguard Worker                 std::thread::park();
125*e1997b9aSAndroid Build Coastguard Worker                 error!("std::thread::park() finished unexpectedly, re-parking thread");
126*e1997b9aSAndroid Build Coastguard Worker             }
127*e1997b9aSAndroid Build Coastguard Worker         }
128*e1997b9aSAndroid Build Coastguard Worker     };
129*e1997b9aSAndroid Build Coastguard Worker 
130*e1997b9aSAndroid Build Coastguard Worker     tokio::runtime::Builder::new_current_thread()
131*e1997b9aSAndroid Build Coastguard Worker         .enable_all()
132*e1997b9aSAndroid Build Coastguard Worker         .build()
133*e1997b9aSAndroid Build Coastguard Worker         .context("In run, building reactor")?
134*e1997b9aSAndroid Build Coastguard Worker         .block_on(async { listen_loop(cb, listener).await })
135*e1997b9aSAndroid Build Coastguard Worker }
136*e1997b9aSAndroid Build Coastguard Worker 
main()137*e1997b9aSAndroid Build Coastguard Worker fn main() {
138*e1997b9aSAndroid Build Coastguard Worker     let e = run();
139*e1997b9aSAndroid Build Coastguard Worker     error!("Launch terminated: {:?}", e);
140*e1997b9aSAndroid Build Coastguard Worker     // Logs are sometimes mysteriously not being logged, so print too
141*e1997b9aSAndroid Build Coastguard Worker     println!("prng_seeder: launch terminated: {:?}", e);
142*e1997b9aSAndroid Build Coastguard Worker     std::process::exit(-1);
143*e1997b9aSAndroid Build Coastguard Worker }
144*e1997b9aSAndroid Build Coastguard Worker 
145*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
146*e1997b9aSAndroid Build Coastguard Worker mod tests {
147*e1997b9aSAndroid Build Coastguard Worker     use super::*;
148*e1997b9aSAndroid Build Coastguard Worker     use clap::CommandFactory;
149*e1997b9aSAndroid Build Coastguard Worker 
150*e1997b9aSAndroid Build Coastguard Worker     #[test]
verify_cli()151*e1997b9aSAndroid Build Coastguard Worker     fn verify_cli() {
152*e1997b9aSAndroid Build Coastguard Worker         Cli::command().debug_assert();
153*e1997b9aSAndroid Build Coastguard Worker     }
154*e1997b9aSAndroid Build Coastguard Worker }
155