wasi-crypto 0.1.9

Experimental implementation of the WASI cryptography APIs
Documentation
use std::convert::TryFrom;
use std::sync::{Arc, Mutex, MutexGuard};

use subtle::ConstantTimeEq;

use super::ecdsa::*;
use super::eddsa::*;
use super::keypair::*;
use super::publickey::*;
use super::rsa_impl::*;
use super::*;
use crate::array_output::*;
use crate::error::*;
use crate::handles::*;
use crate::{CryptoCtx, HandleManagers};

#[derive(Clone)]
pub struct Signature {
    inner: Arc<Mutex<Box<dyn SignatureLike>>>,
}

impl PartialEq for Signature {
    fn eq(&self, other: &Self) -> bool {
        let v1 = self.inner();
        let v1 = v1.as_ref();
        let v2 = other.inner();
        let v2 = v2.as_ref();
        v1.as_ref().ct_eq(v2.as_ref()).unwrap_u8() == 1
    }
}

impl Eq for Signature {}

impl Signature {
    pub fn new(signature_like: Box<dyn SignatureLike>) -> Self {
        Signature {
            inner: Arc::new(Mutex::new(signature_like)),
        }
    }

    fn from_raw(alg: SignatureAlgorithm, encoded: &[u8]) -> Result<Self, CryptoError> {
        let signature = match alg.family() {
            SignatureAlgorithmFamily::ECDSA => {
                Signature::new(Box::new(EcdsaSignature::from_raw(alg, encoded)?))
            }
            SignatureAlgorithmFamily::EdDSA => {
                Signature::new(Box::new(EddsaSignature::from_raw(alg, encoded)?))
            }
            SignatureAlgorithmFamily::RSA => {
                Signature::new(Box::new(RsaSignature::from_raw(alg, encoded)?))
            }
        };
        Ok(signature)
    }

    pub fn inner(&self) -> MutexGuard<'_, Box<dyn SignatureLike>> {
        self.inner.lock().unwrap()
    }

    pub fn locked<T, U>(&self, mut f: T) -> U
    where
        T: FnMut(MutexGuard<'_, Box<dyn SignatureLike>>) -> U,
    {
        f(self.inner())
    }
}

pub trait SignatureLike: Sync + Send {
    fn as_any(&self) -> &dyn Any;
    fn as_ref(&self) -> &[u8];
}

#[derive(Clone)]
pub struct SignatureState {
    inner: Arc<Mutex<Box<dyn SignatureStateLike>>>,
}

impl SignatureState {
    fn new(signature_state_like: Box<dyn SignatureStateLike>) -> Self {
        SignatureState {
            inner: Arc::new(Mutex::new(signature_state_like)),
        }
    }

    fn inner(&self) -> MutexGuard<'_, Box<dyn SignatureStateLike>> {
        self.inner.lock().unwrap()
    }

    fn locked<T, U>(&self, mut f: T) -> U
    where
        T: FnMut(MutexGuard<'_, Box<dyn SignatureStateLike>>) -> U,
    {
        f(self.inner())
    }

    fn open(handles: &HandleManagers, kp_handle: Handle) -> Result<Handle, CryptoError> {
        let kp = handles.keypair.get(kp_handle)?.into_signature_keypair()?;
        let signature_state = match kp {
            SignatureKeyPair::Ecdsa(kp) => {
                SignatureState::new(Box::new(EcdsaSignatureState::new(kp)))
            }
            SignatureKeyPair::Eddsa(kp) => {
                SignatureState::new(Box::new(EddsaSignatureState::new(kp)))
            }
            SignatureKeyPair::Rsa(kp) => SignatureState::new(Box::new(RsaSignatureState::new(kp))),
        };
        let handle = handles.signature_state.register(signature_state)?;
        Ok(handle)
    }
}

pub trait SignatureStateLike: Sync + Send {
    fn update(&mut self, input: &[u8]) -> Result<(), CryptoError>;
    fn sign(&mut self) -> Result<Signature, CryptoError>;
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignatureEncoding {
    Raw,
    Der,
}

#[derive(Clone)]
pub struct SignatureVerificationState {
    inner: Arc<Mutex<Box<dyn SignatureVerificationStateLike>>>,
}

impl SignatureVerificationState {
    fn new(signature_verification_state_like: Box<dyn SignatureVerificationStateLike>) -> Self {
        SignatureVerificationState {
            inner: Arc::new(Mutex::new(signature_verification_state_like)),
        }
    }

    fn inner(&self) -> MutexGuard<'_, Box<dyn SignatureVerificationStateLike>> {
        self.inner.lock().unwrap()
    }

    fn locked<T, U>(&self, mut f: T) -> U
    where
        T: FnMut(MutexGuard<'_, Box<dyn SignatureVerificationStateLike>>) -> U,
    {
        f(self.inner())
    }

    fn open(handles: &HandleManagers, pk_handle: Handle) -> Result<Handle, CryptoError> {
        let pk = handles
            .publickey
            .get(pk_handle)?
            .into_signature_public_key()?;
        let signature_verification_state = match pk {
            SignaturePublicKey::Ecdsa(pk) => {
                SignatureVerificationState::new(Box::new(EcdsaSignatureVerificationState::new(pk)))
            }
            SignaturePublicKey::Eddsa(pk) => {
                SignatureVerificationState::new(Box::new(EddsaSignatureVerificationState::new(pk)))
            }
            SignaturePublicKey::Rsa(pk) => {
                SignatureVerificationState::new(Box::new(RsaSignatureVerificationState::new(pk)))
            }
        };
        let handle = handles
            .signature_verification_state
            .register(signature_verification_state)?;
        Ok(handle)
    }
}

pub trait SignatureVerificationStateLike: Sync + Send {
    fn update(&mut self, input: &[u8]) -> Result<(), CryptoError>;
    fn verify(&self, signature: &Signature) -> Result<(), CryptoError>;
}

impl CryptoCtx {
    pub fn signature_export(
        &self,
        signature_handle: Handle,
        encoding: SignatureEncoding,
    ) -> Result<Handle, CryptoError> {
        match encoding {
            SignatureEncoding::Raw => {}
            _ => bail!(CryptoError::UnsupportedEncoding),
        }
        let signature = self.handles.signature.get(signature_handle)?;
        let array_output_handle =
            ArrayOutput::register(&self.handles, signature.inner().as_ref().as_ref().to_vec())?;
        Ok(array_output_handle)
    }

    pub fn signature_import(
        &self,
        alg_str: &str,
        encoded: &[u8],
        encoding: SignatureEncoding,
    ) -> Result<Handle, CryptoError> {
        let alg = SignatureAlgorithm::try_from(alg_str)?;
        let signature = match encoding {
            SignatureEncoding::Raw => Signature::from_raw(alg, encoded)?,
            _ => bail!(CryptoError::UnsupportedEncoding),
        };
        let handle = self.handles.signature.register(signature)?;
        Ok(handle)
    }

    pub fn signature_state_open(&self, kp_handle: Handle) -> Result<Handle, CryptoError> {
        SignatureState::open(&self.handles, kp_handle)
    }

    pub fn signature_state_update(
        &self,
        state_handle: Handle,
        input: &[u8],
    ) -> Result<(), CryptoError> {
        let state = self.handles.signature_state.get(state_handle)?;
        state.locked(|mut state| state.update(input))
    }

    pub fn signature_state_sign(&self, state_handle: Handle) -> Result<Handle, CryptoError> {
        let state = self.handles.signature_state.get(state_handle)?;
        let signature = state.locked(|mut state| state.sign())?;
        let handle = self.handles.signature.register(signature)?;
        Ok(handle)
    }

    pub fn signature_state_close(&self, handle: Handle) -> Result<(), CryptoError> {
        self.handles.signature_state.close(handle)
    }

    pub fn signature_verification_state_open(
        &self,
        pk_handle: Handle,
    ) -> Result<Handle, CryptoError> {
        SignatureVerificationState::open(&self.handles, pk_handle)
    }

    pub fn signature_verification_state_update(
        &self,
        verification_state_handle: Handle,
        input: &[u8],
    ) -> Result<(), CryptoError> {
        let state = self
            .handles
            .signature_verification_state
            .get(verification_state_handle)?;
        state.locked(|mut state| state.update(input))
    }

    pub fn signature_verification_state_verify(
        &self,
        verification_state_handle: Handle,
        signature_handle: Handle,
    ) -> Result<(), CryptoError> {
        let state = self
            .handles
            .signature_verification_state
            .get(verification_state_handle)?;
        let signature = self.handles.signature.get(signature_handle)?;
        state.locked(|state| state.verify(&signature))
    }

    pub fn signature_verification_state_close(
        &self,
        verification_state_handle: Handle,
    ) -> Result<(), CryptoError> {
        self.handles
            .signature_verification_state
            .close(verification_state_handle)
    }

    pub fn signature_close(&self, signature_handle: Handle) -> Result<(), CryptoError> {
        self.handles.signature.close(signature_handle)
    }
}