bs_gl_plugin/
hsm.rs

1//! Service used to talk to the `hsmd` that is passing us the signer
2//! requests.
3
4use crate::config::NodeInfo;
5use crate::pb::{hsm_server::Hsm, Empty, HsmRequest, HsmResponse, NodeConfig};
6use crate::stager;
7use anyhow::{Context, Result};
8use futures::TryFutureExt;
9use log::{debug, info, trace, warn};
10use std::path::PathBuf;
11use std::sync::Arc;
12use tonic::{Request, Response, Status};
13
14/// The StagingHsmServer is used by the plugin to receive incoming requests
15/// from the hsmproxy and stages the requests for clients of the Node
16/// interface to stream and reply to.
17#[derive(Clone)]
18pub struct StagingHsmServer {
19    stage: Arc<stager::Stage>,
20    hsmd_sock_path: PathBuf,
21    node_info: NodeInfo,
22    node_config: NodeConfig,
23}
24
25impl StagingHsmServer {
26    pub fn new(
27        hsmd_sock_path: PathBuf,
28        stage: Arc<stager::Stage>,
29        node_info: NodeInfo,
30        node_config: NodeConfig,
31    ) -> StagingHsmServer {
32        StagingHsmServer {
33            stage,
34            hsmd_sock_path,
35            node_info,
36            node_config,
37        }
38    }
39
40    /// We have some canned responses from the signer, this gives us access.
41    fn find_canned_response(&self, msg: &Vec<u8>) -> Option<Vec<u8>> {
42        self.node_config
43            .startupmsgs
44            .iter()
45            .find(|m| &m.request == msg)
46            .map(|m| m.response.clone())
47    }
48}
49
50#[tonic::async_trait]
51impl Hsm for StagingHsmServer {
52    async fn request(&self, request: Request<HsmRequest>) -> Result<Response<HsmResponse>, Status> {
53        let req = request.into_inner();
54        debug!("Received request from hsmproxy: {:?}", req);
55
56        // Start by looking in the canned responses and return it if it is known
57        if let Some(response) = self.find_canned_response(&req.raw) {
58            debug!(
59                "Returning canned response={:?} for request={:?}",
60                response, req.raw
61            );
62            return Ok(Response::new(HsmResponse {
63                request_id: req.request_id,
64                raw: response,
65                signer_state: Vec::new(),
66            }));
67        } else if req.get_type() == 11 {
68            debug!("Returning stashed init msg: {:?}", self.node_info.initmsg);
69            return Ok(Response::new(HsmResponse {
70                request_id: req.request_id,
71                raw: self.node_info.initmsg.clone(),
72                signer_state: Vec::new(), // the signerproxy doesn't care about state
73            }));
74        } else if req.get_type() == 33 {
75            debug!("Returning stashed dev-memleak response");
76            return Ok(Response::new(HsmResponse {
77                request_id: req.request_id,
78                raw: vec![0, 133, 0],
79                signer_state: Vec::new(), // the signerproxy doesn't care about state
80            }));
81        }
82
83        let mut chan = match self.stage.send(req).await {
84            Err(e) => {
85                return Err(Status::unknown(format!(
86                    "Error while queing request from node: {:?}",
87                    e
88                )))
89            }
90            Ok(c) => c,
91        };
92
93        let res = match chan.recv().await {
94            None => {
95                return Err(Status::unknown(format!(
96                    "Channel closed while waiting for response",
97                )))
98            }
99            Some(r) => r,
100        };
101
102        Ok(Response::new(res))
103    }
104
105    async fn ping(&self, _request: Request<Empty>) -> Result<Response<Empty>, Status> {
106        trace!("Got a ping");
107        Ok(Response::new(Empty::default()))
108    }
109}
110
111impl StagingHsmServer {
112    pub async fn run(self) -> Result<()> {
113        let mut path = std::path::PathBuf::new();
114        path.push(std::env::current_dir().unwrap());
115        path.push(&self.hsmd_sock_path);
116        info!(
117            "Configuring hsmd interface to listen on {}",
118            path.to_str().unwrap()
119        );
120        std::fs::create_dir_all(std::path::Path::new(&path).parent().unwrap())?;
121
122        if path.exists() {
123            warn!(
124                "Socket path {} already exists, deleting",
125                path.to_string_lossy()
126            );
127            std::fs::remove_file(&path).context("removing stale hsmd socket")?;
128        }
129        let incoming = {
130            let uds = tokio::net::UnixListener::bind(path)?;
131
132            async_stream::stream! {
133                loop {
134            yield  uds.accept().map_ok(|(st, _)| crate::unix::UnixStream(st)).await;
135                }
136            }
137        };
138
139        info!("HSM server interface starting.");
140        tonic::transport::Server::builder()
141            .add_service(crate::pb::hsm_server::HsmServer::new(self))
142            .serve_with_incoming(incoming)
143            .await
144            .context("serving HsmServer interface")
145    }
146}