Commit 0b6d0338 authored by Tom Leavy's avatar Tom Leavy
Browse files

Add support for secure and const time flags on BigNum

parent f9a1f5b1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -7,14 +7,31 @@ pub type BN_ULONG = c_ulonglong;
#[cfg(target_pointer_width = "32")]
pub type BN_ULONG = c_uint;

#[cfg(ossl110)]
pub const BN_FLG_MALLOCED: c_int = 0x01;
#[cfg(ossl110)]
pub const BN_FLG_STATIC_DATA: c_int = 0x02;
#[cfg(ossl110)]
pub const BN_FLG_CONSTTIME: c_int = 0x04;
#[cfg(ossl110)]
pub const BN_FLG_SECURE: c_int = 0x08;

extern "C" {
    pub fn BN_CTX_new() -> *mut BN_CTX;
    #[cfg(ossl110)]
    pub fn BN_CTX_secure_new() -> *mut BN_CTX;
    pub fn BN_CTX_free(ctx: *mut BN_CTX);
    pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int;
    pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int;
    pub fn BN_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int;
    pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int;
    pub fn BN_new() -> *mut BIGNUM;
    #[cfg(ossl110)]
    pub fn BN_secure_new() -> *mut BIGNUM;
    #[cfg(ossl110)]
    pub fn BN_set_flags(b: *mut BIGNUM, n: c_int);
    #[cfg(ossl110)]
    pub fn BN_get_flags(b: *const BIGNUM, n: c_int) -> c_int;
    pub fn BN_num_bits(bn: *const BIGNUM) -> c_int;
    pub fn BN_clear_free(bn: *mut BIGNUM);
    pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM;
+85 −0
Original line number Diff line number Diff line
@@ -108,6 +108,19 @@ impl BigNumContext {
            cvt_p(ffi::BN_CTX_new()).map(BigNumContext)
        }
    }

    /// Returns a new secure `BigNumContext`.
    ///
    /// See OpenSSL documentation at [`BN_CTX_secure_new`].
    ///
    /// [`BN_CTX_secure_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_secure_new.html
    #[cfg(ossl110)]
    pub fn new_secure() -> Result<BigNumContext, ErrorStack> {
        unsafe {
            ffi::init();
            cvt_p(ffi::BN_CTX_secure_new()).map(BigNumContext)
        }
    }
}

foreign_type_and_impl_send_sync! {
@@ -953,6 +966,30 @@ impl BigNumRef {
                .map(|p| Asn1Integer::from_ptr(p))
        }
    }

    /// Force constant time computation on this value.
    #[cfg(ossl110)]
    pub fn set_const_time(&mut self) {
        unsafe { ffi::BN_set_flags(self.as_ptr(), ffi::BN_FLG_CONSTTIME) }
    }

    /// Returns true if `self` is in const time mode.
    #[cfg(ossl110)]
    pub fn is_const_time(&self) -> bool {
        unsafe {
            let ret = ffi::BN_get_flags(self.as_ptr(), ffi::BN_FLG_CONSTTIME);
            ret == ffi::BN_FLG_CONSTTIME
        }
    }

    /// Returns true if `self` was created with [`BigNum::new_secure`].
    #[cfg(ossl110)]
    pub fn is_secure(&self) -> bool {
        unsafe {
            let ret = ffi::BN_get_flags(self.as_ptr(), ffi::BN_FLG_SECURE);
            ret == ffi::BN_FLG_SECURE
        }
    }
}

impl BigNum {
@@ -965,6 +1002,20 @@ impl BigNum {
        }
    }

    /// Returns a new secure `BigNum`.
    ///
    /// See OpenSSL documentation at [`BN_secure_new`].
    ///
    /// [`BN_secure_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_secure_new.html
    #[cfg(ossl110)]
    pub fn new_secure() -> Result<BigNum, ErrorStack> {
        unsafe {
            ffi::init();
            let v = cvt_p(ffi::BN_secure_new())?;
            Ok(BigNum::from_ptr(v))
        }
    }

    /// Creates a new `BigNum` with the given value.
    ///
    /// OpenSSL documentation at [`BN_set_word`]
@@ -1459,4 +1510,38 @@ mod tests {
        assert!(p.is_prime(100, &mut ctx).unwrap());
        assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap());
    }

    #[cfg(ossl110)]
    #[test]
    fn test_secure_bn_ctx() {
        let mut cxt = BigNumContext::new_secure().unwrap();
        let a = BigNum::from_u32(8).unwrap();
        let b = BigNum::from_u32(3).unwrap();

        let mut remainder = BigNum::new().unwrap();
        remainder.nnmod(&a, &b, &mut cxt).unwrap();

        assert!(remainder.eq(&BigNum::from_u32(2).unwrap()));
    }

    #[cfg(ossl110)]
    #[test]
    fn test_secure_bn() {
        let a = BigNum::new().unwrap();
        assert!(!a.is_secure());

        let b = BigNum::new_secure().unwrap();
        assert!(b.is_secure())
    }

    #[cfg(ossl110)]
    #[test]
    fn test_const_time_bn() {
        let a = BigNum::new().unwrap();
        assert!(!a.is_const_time());

        let mut b = BigNum::new().unwrap();
        b.set_const_time();
        assert!(b.is_const_time())
    }
}