mbedtls 0.13.5

Idiomatic Rust wrapper for MbedTLS, allowing you to use MbedTLS with only safe code while being able to use such great Rust features like error handling and closures. Building on MbedTLS's focus on embedded use, this crate can be used in a no_std environment.
Documentation
/* Copyright (c) Fortanix, Inc.
 *
 * Licensed under the GNU General Public License, version 2 <LICENSE-GPL or
 * https://www.gnu.org/licenses/gpl-2.0.html> or the Apache License, Version
 * 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>, at your
 * option. This file may not be copied, modified, or distributed except
 * according to those terms. */

use mbedtls_sys::ECDSA_MAX_LEN as MBEDTLS_ECDSA_MAX_LEN;
use mbedtls_sys::*;

use crate::error::{codes, IntoResult, Result};

define!(
    #[c_ty(ecp_group_id)]
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    enum EcGroupId {
        None = ECP_DP_NONE,
        SecP192R1 = ECP_DP_SECP192R1,
        SecP224R1 = ECP_DP_SECP224R1,
        SecP256R1 = ECP_DP_SECP256R1,
        SecP384R1 = ECP_DP_SECP384R1,
        SecP521R1 = ECP_DP_SECP521R1,
        Bp256R1 = ECP_DP_BP256R1,
        Bp384R1 = ECP_DP_BP384R1,
        Bp512R1 = ECP_DP_BP512R1,
        Curve25519 = ECP_DP_CURVE25519,
        SecP192K1 = ECP_DP_SECP192K1,
        SecP224K1 = ECP_DP_SECP224K1,
        SecP256K1 = ECP_DP_SECP256K1,
        Curve448 = ECP_DP_CURVE448,
    }
);

impl From<ecp_group_id> for EcGroupId {
    fn from(inner: ecp_group_id) -> EcGroupId {
        match inner {
            ECP_DP_NONE => EcGroupId::None,
            ECP_DP_SECP192R1 => EcGroupId::SecP192R1,
            ECP_DP_SECP224R1 => EcGroupId::SecP224R1,
            ECP_DP_SECP256R1 => EcGroupId::SecP256R1,
            ECP_DP_SECP384R1 => EcGroupId::SecP384R1,
            ECP_DP_SECP521R1 => EcGroupId::SecP521R1,
            ECP_DP_BP256R1 => EcGroupId::Bp256R1,
            ECP_DP_BP384R1 => EcGroupId::Bp384R1,
            ECP_DP_BP512R1 => EcGroupId::Bp512R1,
            ECP_DP_CURVE25519 => EcGroupId::Curve25519,
            ECP_DP_SECP192K1 => EcGroupId::SecP192K1,
            ECP_DP_SECP224K1 => EcGroupId::SecP224K1,
            ECP_DP_SECP256K1 => EcGroupId::SecP256K1,
            ECP_DP_CURVE448 => EcGroupId::Curve448,
            _ => panic!("Invalid EC group ID"),
        }
    }
}

/// Maximum size of an elliptic curve signature generated by `sign`, and the
/// minimum buffer size input to `sign`.
pub const ECDSA_MAX_LEN: usize = MBEDTLS_ECDSA_MAX_LEN as usize;

define!(
    #[c_ty(ecp_keypair)]
    #[repr(C)]
    struct EcpKeypair;
    const init: fn() -> Self = ecp_keypair_init;
    const drop: fn(&mut Self) = ecp_keypair_free;
    impl<'a> Into<ptr> {}
    impl<'a> UnsafeFrom<ptr> {}
);

define!(
    #[c_ty(ecdh_context)]
    #[repr(C)]
    struct Ecdh;
    const init: fn() -> Self = ecdh_init;
    const drop: fn(&mut Self) = ecdh_free;
    impl<'a> Into<ptr> {}
);

impl Ecdh {
    pub fn from_keys(private: &EcpKeypair, public: &EcpKeypair) -> Result<Ecdh> {
        if public.inner.grp.id == ECP_DP_NONE || public.inner.grp.id != private.inner.grp.id {
            return Err(codes::EcpBadInputData.into());
        }

        let mut ret = Self::init();
        unsafe {
            ecp_group_copy(&mut ret.inner.grp, &private.inner.grp).into_result()?;
            mpi_copy(&mut ret.inner.d, &private.inner.d).into_result()?;
            ecp_copy(&mut ret.inner.Qp, &public.inner.Q).into_result()?;
        }
        Ok(ret)
    }

    pub fn calc_secret<F: crate::rng::Random>(&mut self, shared: &mut [u8], rng: &mut F) -> Result<usize> {
        let mut olen = 0;
        unsafe {
            ecdh_calc_secret(
                &mut self.inner,
                &mut olen,
                shared.as_mut_ptr(),
                shared.len(),
                Some(F::call),
                rng.data_ptr(),
            )
            .into_result()?
        };
        Ok(olen)
    }
}

#[cfg(test)]
mod tests {
    use crate::pk::Pk;

    #[test]
    fn p192_dh() {
        // From NIST CAVS 14.1, ECC CDH Primitive (SP800-56A Section 5.7.1.2),
        // Generated on Mon Nov 19 10:52:17 2012. Curve P-192, test vector
        // number 0.
        const PRIVATE_P192: &'static [u8] = b"-----BEGIN PRIVATE KEY-----
MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBjxfT/qNnt000CFHKQn
DcskwnH0Rb7Z1SehNAMyAASxUFNAH1coVjfsMkwc0hOeOmfeNzkjSzfyacFYY3SC
qtZEzWkt0dPvLIp8SeOJ9/Y=
-----END PRIVATE KEY-----\0";

        const PUBLIC_P192: &'static [u8] = b"-----BEGIN PUBLIC KEY-----
MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEQupt2Zad0qYf6hqsf46Y7cyJbG5V
hXzA375dfGH6yIsRgRveMo6KDRK/AanSBLUj
-----END PUBLIC KEY-----\0";

        const DH_P192: &'static [u8] = &[
            0x80, 0x3d, 0x8a, 0xb2, 0xe5, 0xb6, 0xe6, 0xfc, 0xa7, 0x15, 0x73, 0x7c, 0x3a, 0x82, 0xf7, 0xce, 0x3c, 0x78, 0x31,
            0x24, 0xf6, 0xd5, 0x1c, 0xd0,
        ];

        let mut k_pr = Pk::from_private_key(PRIVATE_P192, None).unwrap();
        let k_pb = Pk::from_public_key(PUBLIC_P192).unwrap();
        let mut out = [0; 192 / 8];
        let len = k_pr
            .agree(&k_pb, &mut out, &mut crate::test_support::rand::test_rng())
            .unwrap();
        assert_eq!(len, DH_P192.len());
        assert_eq!(out, DH_P192);
    }
}