yubihsm 0.42.1

Pure Rust client for YubiHSM2 devices with support for HTTP and USB-based access to the device. Supports most HSM functionality including ECDSA, Ed25519, HMAC, and RSA.
Documentation
//! Methods of connecting to a YubiHSM 2:
//!
//! - [HTTP][http-connector]: communicate with YubiHSM via the `yubihsm-connector`
//!   process from the Yubico SDK.
//! - [USB][usb-connector]: communicate directly with the YubiHSM over USB using
//!   the [rusb] crate.
//!
//! Additionally, this crate includes an optional development-only [mockhsm]
//! (gated under a `mockhsm` cargo feature) which can be used as a drop-in
//! replacement in places where you would like a simulated HSM for testing (e.g. CI).
//!
//! [http-connector]: https://docs.rs/yubihsm/latest/yubihsm/connector/struct.Connector.html#method.http
//! [usb-connector]: https://docs.rs/yubihsm/latest/yubihsm/connector/struct.Connector.html#method.usb
//! [rusb]: https://github.com/a1ien/rusb
//! [mockhsm]: https://docs.rs/yubihsm/latest/yubihsm/connector/struct.Connector.html#method.mockhsm

#[macro_use]
mod error;

mod connectable;
mod connection;
#[cfg(feature = "http")]
pub mod http;
mod message;
#[cfg(feature = "usb")]
pub mod usb;

pub use self::connection::Connection;
pub use self::error::*;

pub(crate) use self::{connectable::Connectable, message::Message};
use std::sync::{Arc, Mutex};
use uuid::Uuid;

#[cfg(feature = "http")]
pub use self::http::HttpConfig;

#[cfg(feature = "http")]
use self::http::HttpConnector;

#[cfg(feature = "usb")]
pub use self::usb::UsbConfig;
#[cfg(feature = "usb")]
use self::usb::UsbConnector;

#[cfg(feature = "mockhsm")]
use crate::mockhsm::MockHsm;

/// Abstract interface to multiple types of YubiHSM 2 connections
pub struct Connector {
    /// Currently active connection (if any)
    connection: Arc<Mutex<Option<Box<dyn Connection>>>>,

    /// Backend connector driver
    driver: Box<dyn Connectable>,
}

impl Connector {
    /// Create a new HTTP connector
    #[cfg(feature = "http")]
    pub fn http(config: &HttpConfig) -> Self {
        Self::from(HttpConnector::create(config))
    }

    /// Create a new USB connector. For more advanced usage including
    /// connecting to multiple YubiHSMs over USB which are plugged into
    /// the same computer, please see the [yubihsm::connector::usb] module.
    ///
    /// [yubihsm::connector::usb]: https://docs.rs/yubihsm/latest/yubihsm/connector/usb/index.html
    #[cfg(feature = "usb")]
    pub fn usb(config: &UsbConfig) -> Self {
        Self::from(UsbConnector::create(config))
    }

    /// Create a mock HSM connector (useful for testing)
    #[cfg(feature = "mockhsm")]
    pub fn mockhsm() -> Self {
        let mockhsm: Box<dyn Connectable> = MockHsm::new().into();
        Self::from(mockhsm)
    }

    /// Send a command message to the HSM, then read and return the response
    pub fn send_message(&self, uuid: Uuid, msg: Message) -> Result<Message, Error> {
        let mut connection = self.connection.lock().unwrap();

        if connection.is_none() {
            *connection = Some(self.driver.connect()?);
        }

        connection
            .as_ref()
            .unwrap()
            .send_message(uuid, msg)
            .map_err(|e| {
                // In the event of an error, mark this connection as invalid
                *connection = None;
                e
            })
    }
}

impl Clone for Connector {
    fn clone(&self) -> Self {
        Connector {
            connection: self.connection.clone(),
            driver: self.driver.box_clone(),
        }
    }
}

impl From<Box<dyn Connectable>> for Connector {
    fn from(driver: Box<dyn Connectable>) -> Connector {
        Connector {
            connection: Arc::new(Mutex::new(None)),
            driver,
        }
    }
}