pub use bssl_sys::{
CBB_len, CBS_init, CBS_len, CRYPTO_memcmp, EC_GROUP_get_curve_name, ED25519_keypair,
ED25519_keypair_from_seed, ERR_print_errors_cb, HMAC_CTX_init, HMAC_size, RC4_set_key,
RSA_bits, RC4,
};
use std::convert::TryInto;
use std::num::NonZeroUsize;
use std::os::raw::{c_char, c_int, c_uint, c_void};
use std::ptr::{self, NonNull};
use bssl_sys::{
self as ffi, BIGNUM, BN_GENCB, CBB, CBS, EC_GROUP, EC_KEY, EVP_MD, EVP_PKEY, HMAC_CTX, RSA,
SHA512_CTX,
};
use boringssl::abort::UnwrapAbort;
use boringssl::wrapper::CInit;
use boringssl::BoringError;
macro_rules! impl_hash_context {
($ctx:ident, $update:ident, $final:ident) => {
#[allow(non_snake_case)]
pub unsafe fn $update(ctx: *mut ffi::$ctx, data: *const c_void, len: usize) {
assert_abort_eq!(ffi::$update(ctx, data, len), 1);
}
#[allow(non_snake_case)]
pub unsafe fn $final(md: *mut u8, ctx: *mut ffi::$ctx) -> Result<(), BoringError> {
one_or_err(stringify!($final), ffi::$final(md, ctx))
}
};
}
impl_traits!(BIGNUM, CInit => BN_init, CDestruct => BN_free);
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn BN_set_u64(bn: *mut BIGNUM, value: u64) -> Result<(), BoringError> {
one_or_err("BN_set_u64", ffi::BN_set_u64(bn, value))
}
impl_traits!(CBB, CDestruct => CBB_cleanup);
impl_traits!(CBS, CDestruct => _);
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn CBB_init(cbb: *mut CBB, initial_capacity: usize) -> Result<(), BoringError> {
one_or_err("CBB_init", ffi::CBB_init(cbb, initial_capacity))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn CBB_data(cbb: *const CBB) -> Result<NonNull<u8>, BoringError> {
ptr_or_err("CBB_init", ffi::CBB_data(cbb) as *mut _)
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn ED25519_sign(
out: *mut [u8; 64],
message: *const u8,
message_len: usize,
private_key: *const [u8; 64],
) -> Result<(), BoringError> {
one_or_err(
"ED25519_sign",
ffi::ED25519_sign(out as *mut u8, message, message_len, private_key as *const u8),
)
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn ED25519_verify(
message: *const u8,
message_len: usize,
signature: *const [u8; 64],
public_key: *const [u8; 32],
) -> bool {
match ffi::ED25519_verify(message, message_len, signature as *const u8, public_key as *const u8)
{
0 => false,
1 => true,
_ => unreachable_abort!(),
}
}
macro_rules! evp_digest {
($name:ident) => {
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn $name() -> NonNull<EVP_MD> {
use boringssl::abort::UnwrapAbort;
ptr_or_err(stringify!($name), ffi::$name() as *mut _).unwrap_abort()
}
};
}
evp_digest!(EVP_md5);
evp_digest!(EVP_sha1);
evp_digest!(EVP_sha256);
evp_digest!(EVP_sha384);
evp_digest!(EVP_sha512);
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_GROUP_new_by_curve_name(nid: c_int) -> Result<NonNull<EC_GROUP>, BoringError> {
ptr_or_err("EC_GROUP_new_by_curve_name", ffi::EC_GROUP_new_by_curve_name(nid))
}
impl_traits!(EC_KEY, CNew => EC_KEY_new, CUpRef => EC_KEY_up_ref, CFree => EC_KEY_free);
impl_traits!(EVP_PKEY, CNew => EVP_PKEY_new, CUpRef => EVP_PKEY_up_ref, CFree => EVP_PKEY_free);
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_curve_nid2nist(nid: c_int) -> Result<NonNull<c_char>, BoringError> {
ptr_or_err("EC_curve_nid2nist", ffi::EC_curve_nid2nist(nid) as *mut _)
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_KEY_generate_key(key: *mut EC_KEY) -> Result<(), BoringError> {
one_or_err("EC_KEY_generate_key", ffi::EC_KEY_generate_key(key))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_KEY_get0_group(key: *const EC_KEY) -> Result<NonNull<EC_GROUP>, BoringError> {
ptr_or_err("EC_KEY_get0_group", ffi::EC_KEY_get0_group(key) as *mut _)
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_KEY_marshal_private_key(
cbb: *mut CBB,
key: *const EC_KEY,
enc_flags: c_uint,
) -> Result<(), BoringError> {
one_or_err("EC_KEY_marshal_private_key", ffi::EC_KEY_marshal_private_key(cbb, key, enc_flags))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_KEY_parse_private_key(
cbs: *mut CBS,
group: *const EC_GROUP,
) -> Result<NonNull<EC_KEY>, BoringError> {
ptr_or_err("EC_KEY_parse_private_key", ffi::EC_KEY_parse_private_key(cbs, group))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EC_KEY_set_group(
key: *mut EC_KEY,
group: *const EC_GROUP,
) -> Result<(), BoringError> {
one_or_err("EC_KEY_set_group", ffi::EC_KEY_set_group(key, group))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn ECDSA_sign(
type_: c_int,
digest: *const u8,
digest_len: usize,
sig: *mut u8,
sig_len: *mut c_uint,
key: *const EC_KEY,
) -> Result<(), BoringError> {
one_or_err("ECDSA_sign", ffi::ECDSA_sign(type_, digest, digest_len, sig, sig_len, key))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn ECDSA_size(key: *const EC_KEY) -> Result<NonZeroUsize, BoringError> {
NonZeroUsize::new(ffi::ECDSA_size(key)).ok_or_else(|| BoringError::consume_stack("ECDSA_size"))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn ECDSA_verify(
type_: c_int,
digest: *const u8,
digest_len: usize,
sig: *const u8,
sig_len: usize,
key: *const EC_KEY,
) -> bool {
match ffi::ECDSA_verify(type_, digest, digest_len, sig, sig_len, key) {
1 => true,
0 => false,
_ => unreachable_abort!(),
}
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EVP_marshal_public_key(
cbb: *mut CBB,
key: *const EVP_PKEY,
) -> Result<(), BoringError> {
one_or_err("EVP_marshal_public_key", ffi::EVP_marshal_public_key(cbb, key))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EVP_parse_public_key(cbs: *mut CBS) -> Result<NonNull<EVP_PKEY>, BoringError> {
ptr_or_err("EVP_parse_public_key", ffi::EVP_parse_public_key(cbs))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EVP_PKEY_assign_EC_KEY(
pkey: *mut EVP_PKEY,
key: *mut EC_KEY,
) -> Result<(), BoringError> {
one_or_err("EVP_PKEY_assign_EC_KEY", ffi::EVP_PKEY_assign_EC_KEY(pkey, key))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EVP_PKEY_assign_RSA(pkey: *mut EVP_PKEY, key: *mut RSA) -> Result<(), BoringError> {
one_or_err("EVP_PKEY_assign_RSA", ffi::EVP_PKEY_assign_RSA(pkey, key))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EVP_PKEY_get1_EC_KEY(pkey: *mut EVP_PKEY) -> Result<NonNull<EC_KEY>, BoringError> {
ptr_or_err("EVP_PKEY_get1_EC_KEY", ffi::EVP_PKEY_get1_EC_KEY(pkey))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn EVP_PKEY_get1_RSA(pkey: *mut EVP_PKEY) -> Result<NonNull<RSA>, BoringError> {
ptr_or_err("EVP_PKEY_get1_RSA", ffi::EVP_PKEY_get1_RSA(pkey))
}
#[allow(non_snake_case)]
#[allow(clippy::too_many_arguments)]
#[must_use]
pub unsafe fn EVP_PBE_scrypt(
password: *const c_char,
password_len: usize,
salt: *const u8,
salt_len: usize,
N: u64,
r: u64,
p: u64,
max_mem: usize,
out_key: *mut u8,
key_len: usize,
) -> Result<(), BoringError> {
one_or_err(
"EVP_PBE_scrypt",
ffi::EVP_PBE_scrypt(
password,
password_len,
salt,
salt_len,
N,
r,
p,
max_mem,
out_key,
key_len,
),
)
}
#[cfg(feature = "kdf")]
#[allow(non_snake_case)]
#[allow(clippy::too_many_arguments)]
#[must_use]
pub unsafe fn PKCS5_PBKDF2_HMAC(
password: *const c_char,
password_len: usize,
salt: *const u8,
salt_len: usize,
iterations: c_uint,
digest: *const EVP_MD,
key_len: usize,
out_key: *mut u8,
) -> Result<(), BoringError> {
one_or_err(
"PKCS5_PBKDF2_HMAC",
ffi::PKCS5_PBKDF2_HMAC(
password,
password_len,
salt,
salt_len,
iterations,
digest,
key_len,
out_key,
),
)
}
impl_traits!(HMAC_CTX, CDestruct => HMAC_CTX_cleanup);
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn HMAC_Init_ex(
ctx: *mut HMAC_CTX,
key: *const c_void,
key_len: usize,
md: *const EVP_MD,
) -> Result<(), BoringError> {
one_or_err("HMAC_Init_ex", ffi::HMAC_Init_ex(ctx, key, key_len, md, ptr::null_mut()))
}
#[allow(non_snake_case)]
pub unsafe fn HMAC_Update(ctx: *mut HMAC_CTX, data: *const u8, data_len: usize) {
assert_abort_eq!(ffi::HMAC_Update(ctx, data, data_len), 1);
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn HMAC_Final(
ctx: *mut HMAC_CTX,
out: *mut u8,
out_len: *mut c_uint,
) -> Result<(), BoringError> {
one_or_err("HMAC_Final", ffi::HMAC_Final(ctx, out, out_len))
}
#[allow(non_snake_case)]
pub unsafe fn HMAC_CTX_copy(dest: *mut HMAC_CTX, src: *const HMAC_CTX) -> Result<(), BoringError> {
one_or_err("HMAC_CTX_copy", ffi::HMAC_CTX_copy(dest, src))
}
#[allow(non_snake_case)]
pub unsafe fn RAND_bytes(buf: *mut u8, len: usize) {
assert_abort_eq!(ffi::RAND_bytes(buf, len), 1);
}
impl_traits!(RSA, CNew => RSA_new, CUpRef => RSA_up_ref, CFree => RSA_free);
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_generate_key_ex(
rsa: *mut RSA,
bits: c_int,
e: *const BIGNUM,
cb: *mut BN_GENCB,
) -> Result<(), BoringError> {
one_or_err("RSA_generate_key_ex", ffi::RSA_generate_key_ex(rsa, bits, e, cb))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_marshal_private_key(cbb: *mut CBB, rsa: *const RSA) -> Result<(), BoringError> {
one_or_err("RSA_marshal_private_key", ffi::RSA_marshal_private_key(cbb, rsa))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_parse_private_key(cbs: *mut CBS) -> Result<NonNull<RSA>, BoringError> {
ptr_or_err("RSA_parse_private_key", ffi::RSA_parse_private_key(cbs))
}
#[cfg(feature = "rsa-pkcs1v15")]
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_sign(
hash_nid: c_int,
in_: *const u8,
in_len: usize,
out: *mut u8,
out_len: *mut c_uint,
key: *mut RSA,
) -> Result<(), BoringError> {
one_or_err("RSA_sign", ffi::RSA_sign(hash_nid, in_, in_len, out, out_len, key))
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_sign_pss_mgf1(
rsa: *mut RSA,
out_len: *mut usize,
out: *mut u8,
max_out: usize,
in_: *const u8,
in_len: usize,
md: *const EVP_MD,
mgf1_md: *const EVP_MD,
salt_len: c_int,
) -> Result<(), BoringError> {
one_or_err(
"RSA_sign_pss_mgf1",
ffi::RSA_sign_pss_mgf1(rsa, out_len, out, max_out, in_, in_len, md, mgf1_md, salt_len),
)
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_size(key: *const RSA) -> Result<NonZeroUsize, BoringError> {
NonZeroUsize::new(ffi::RSA_size(key).try_into().unwrap_abort())
.ok_or_else(|| BoringError::consume_stack("RSA_size"))
}
#[cfg(feature = "rsa-pkcs1v15")]
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_verify(
hash_nid: c_int,
msg: *const u8,
msg_len: usize,
sig: *const u8,
sig_len: usize,
rsa: *mut RSA,
) -> bool {
match ffi::RSA_verify(hash_nid, msg, msg_len, sig, sig_len, rsa) {
0 => false,
1 => true,
_ => unreachable_abort!(),
}
}
#[allow(non_snake_case)]
#[must_use]
pub unsafe fn RSA_verify_pss_mgf1(
rsa: *mut RSA,
msg: *const u8,
msg_len: usize,
md: *const EVP_MD,
mgf1_md: *const EVP_MD,
salt_len: c_int,
sig: *const u8,
sig_len: usize,
) -> bool {
match ffi::RSA_verify_pss_mgf1(rsa, msg, msg_len, md, mgf1_md, salt_len, sig, sig_len) {
0 => false,
1 => true,
_ => unreachable_abort!(),
}
}
impl_traits!(RC4_KEY, CDestruct => _);
unsafe impl CInit for ffi::MD5_CTX {
unsafe fn init(ctx: *mut Self) {
assert_abort_eq!(ffi::MD5_Init(ctx), 1);
}
}
#[allow(non_snake_case)]
pub unsafe fn SHA384_Init(ctx: *mut SHA512_CTX) {
assert_abort_eq!(ffi::SHA384_Init(ctx), 1);
}
unsafe impl CInit for ffi::SHA_CTX {
unsafe fn init(ctx: *mut Self) {
assert_abort_eq!(ffi::SHA1_Init(ctx), 1);
}
}
unsafe impl CInit for ffi::SHA256_CTX {
unsafe fn init(ctx: *mut Self) {
assert_abort_eq!(ffi::SHA256_Init(ctx), 1);
}
}
unsafe impl CInit for ffi::SHA512_CTX {
unsafe fn init(ctx: *mut Self) {
assert_abort_eq!(ffi::SHA512_Init(ctx), 1);
}
}
impl_traits!(MD5_CTX, CDestruct => _);
impl_traits!(SHA_CTX, CDestruct => _);
impl_traits!(SHA256_CTX, CDestruct => _);
impl_traits!(SHA512_CTX, CDestruct => _);
impl_hash_context!(MD5_CTX, MD5_Update, MD5_Final);
impl_hash_context!(SHA_CTX, SHA1_Update, SHA1_Final);
impl_hash_context!(SHA256_CTX, SHA256_Update, SHA256_Final);
impl_hash_context!(SHA512_CTX, SHA384_Update, SHA384_Final);
impl_hash_context!(SHA512_CTX, SHA512_Update, SHA512_Final);
#[must_use]
pub fn one_or_err<S: TryInto<usize>>(f: &str, code: S) -> Result<(), BoringError> {
if code.try_into().map(|code| code == 1).unwrap_or(false) {
Ok(())
} else {
Err(BoringError::consume_stack(f))
}
}
fn ptr_or_err<T>(f: &str, ptr: *mut T) -> Result<NonNull<T>, BoringError> {
NonNull::new(ptr).ok_or_else(|| BoringError::consume_stack(f))
}