[rsa] Initial commit of rsa module
Change-Id: Iaea22a9e16701f3b73ce47ddac51115c5dc71a8e
diff --git a/boringssl/bindgen.h b/boringssl/bindgen.h
index 8297e68..16617c8 100644
--- a/boringssl/bindgen.h
+++ b/boringssl/bindgen.h
@@ -4,6 +4,7 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
+#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/curve25519.h>
#include <openssl/ec.h>
@@ -14,4 +15,5 @@
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
+#include <openssl/rsa.h>
#include <openssl/sha.h>
diff --git a/boringssl/bindgen.sh b/boringssl/bindgen.sh
index 57e62b1..a8262b8 100755
--- a/boringssl/bindgen.sh
+++ b/boringssl/bindgen.sh
@@ -41,7 +41,10 @@
# former for a consistency check of the postprocessing step which adds the
# #[link_name...] attributes. Any change of the whitelist must be made to the
# appropriate sub-list.
-WHITELIST_FUNCS="CBS_init|\
+WHITELIST_FUNCS="BN_free|\
+BN_init|\
+BN_set_u64|\
+CBS_init|\
CBS_len|\
CBB_init|\
CBB_cleanup|\
@@ -74,7 +77,9 @@
EVP_PKEY_free|\
EVP_PKEY_up_ref|\
EVP_PKEY_assign_EC_KEY|\
+EVP_PKEY_assign_RSA|\
EVP_PKEY_get1_EC_KEY|\
+EVP_PKEY_get1_RSA|\
EVP_parse_public_key|\
EVP_marshal_public_key|\
PKCS5_PBKDF2_HMAC|\
@@ -87,6 +92,18 @@
HMAC_size|\
CRYPTO_memcmp|\
RAND_bytes|\
+RSA_bits|\
+RSA_free|\
+RSA_generate_key_ex|\
+RSA_marshal_private_key|\
+RSA_new|\
+RSA_parse_private_key|\
+RSA_sign|\
+RSA_sign_pss_mgf1|\
+RSA_size|\
+RSA_up_ref|\
+RSA_verify|\
+RSA_verify_pss_mgf1|\
SHA1_Init|\
SHA1_Update|\
SHA1_Final|\
@@ -100,7 +117,9 @@
SHA512_Update|\
SHA512_Final"
-WHITELIST_OTHERS="CBB|\
+WHITELIST_OTHERS="BIGNUM|\
+BN_GENCB|\
+CBB|\
CBS|\
EC_GROUP|\
EC_KEY|\
@@ -113,6 +132,12 @@
NID_X9_62_prime256v1|\
NID_secp384r1|\
NID_secp521r1|\
+NID_sha1|\
+NID_sha256|\
+NID_sha384|\
+NID_sha512|\
+RSA|\
+RSA_F4|\
SHA_CTX|\
SHA_DIGEST_LENGTH|\
SHA256_CTX|\
diff --git a/boringssl/boringssl.rs b/boringssl/boringssl.rs
index 4ae4e0b..36b54eb 100644
--- a/boringssl/boringssl.rs
+++ b/boringssl/boringssl.rs
@@ -19,16 +19,165 @@
/* automatically generated by rust-bindgen */
+#[repr(C)]
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct __BindgenBitfieldUnit<Storage, Align>
+where
+ Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+ storage: Storage,
+ align: [Align; 0],
+}
+
+impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align>
+where
+ Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+ #[inline]
+ pub fn new(storage: Storage) -> Self {
+ Self { storage, align: [] }
+ }
+
+ #[inline]
+ pub fn get_bit(&self, index: usize) -> bool {
+ debug_assert!(index / 8 < self.storage.as_ref().len());
+
+ let byte_index = index / 8;
+ let byte = self.storage.as_ref()[byte_index];
+
+ let bit_index = if cfg!(target_endian = "big") {
+ 7 - (index % 8)
+ } else {
+ index % 8
+ };
+
+ let mask = 1 << bit_index;
+
+ byte & mask == mask
+ }
+
+ #[inline]
+ pub fn set_bit(&mut self, index: usize, val: bool) {
+ debug_assert!(index / 8 < self.storage.as_ref().len());
+
+ let byte_index = index / 8;
+ let byte = &mut self.storage.as_mut()[byte_index];
+
+ let bit_index = if cfg!(target_endian = "big") {
+ 7 - (index % 8)
+ } else {
+ index % 8
+ };
+
+ let mask = 1 << bit_index;
+ if val {
+ *byte |= mask;
+ } else {
+ *byte &= !mask;
+ }
+ }
+
+ #[inline]
+ pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
+ debug_assert!(bit_width <= 64);
+ debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+ debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
+
+ let mut val = 0;
+
+ for i in 0..(bit_width as usize) {
+ if self.get_bit(i + bit_offset) {
+ let index = if cfg!(target_endian = "big") {
+ bit_width as usize - 1 - i
+ } else {
+ i
+ };
+ val |= 1 << index;
+ }
+ }
+
+ val
+ }
+
+ #[inline]
+ pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
+ debug_assert!(bit_width <= 64);
+ debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+ debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
+
+ for i in 0..(bit_width as usize) {
+ let mask = 1 << i;
+ let val_bit_is_set = val & mask == mask;
+ let index = if cfg!(target_endian = "big") {
+ bit_width as usize - 1 - i
+ } else {
+ i
+ };
+ self.set_bit(index + bit_offset, val_bit_is_set);
+ }
+ }
+}
pub const ED25519_PRIVATE_KEY_LEN: u32 = 64;
pub const ED25519_PUBLIC_KEY_LEN: u32 = 32;
pub const ED25519_SIGNATURE_LEN: u32 = 64;
+pub const NID_sha1: u32 = 64;
pub const NID_X9_62_prime256v1: u32 = 415;
+pub const NID_sha256: u32 = 672;
+pub const NID_sha384: u32 = 673;
+pub const NID_sha512: u32 = 674;
pub const NID_secp384r1: u32 = 715;
pub const NID_secp521r1: u32 = 716;
+pub const RSA_F4: u32 = 65537;
pub const SHA_DIGEST_LENGTH: u32 = 20;
pub const SHA256_DIGEST_LENGTH: u32 = 32;
pub const SHA384_DIGEST_LENGTH: u32 = 48;
pub const SHA512_DIGEST_LENGTH: u32 = 64;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct _opaque_pthread_rwlock_t {
+ pub __sig: ::std::os::raw::c_long,
+ pub __opaque: [::std::os::raw::c_char; 192usize],
+}
+#[test]
+fn bindgen_test_layout__opaque_pthread_rwlock_t() {
+ assert_eq!(
+ ::std::mem::size_of::<_opaque_pthread_rwlock_t>(),
+ 200usize,
+ concat!("Size of: ", stringify!(_opaque_pthread_rwlock_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<_opaque_pthread_rwlock_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(_opaque_pthread_rwlock_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<_opaque_pthread_rwlock_t>())).__sig as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(_opaque_pthread_rwlock_t),
+ "::",
+ stringify!(__sig)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<_opaque_pthread_rwlock_t>())).__opaque as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(_opaque_pthread_rwlock_t),
+ "::",
+ stringify!(__opaque)
+ )
+ );
+}
+pub type __darwin_pthread_rwlock_t = _opaque_pthread_rwlock_t;
+pub type pthread_rwlock_t = __darwin_pthread_rwlock_t;
+pub type BIGNUM = bignum_st;
+pub type BN_GENCB = bn_gencb_st;
+pub type BN_MONT_CTX = bn_mont_ctx_st;
pub type CBB = cbb_st;
pub type CBS = cbs_st;
#[repr(C)]
@@ -82,15 +231,192 @@
pub type EVP_PKEY_CTX = evp_pkey_ctx_st;
pub type EVP_PKEY = evp_pkey_st;
pub type HMAC_CTX = hmac_ctx_st;
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct rsa_st {
- _unused: [u8; 0],
-}
+pub type RSA_METHOD = rsa_meth_st;
pub type RSA = rsa_st;
pub type SHA256_CTX = sha256_state_st;
pub type SHA512_CTX = sha512_state_st;
pub type SHA_CTX = sha_state_st;
+pub type CRYPTO_MUTEX = pthread_rwlock_t;
+pub type CRYPTO_refcount_t = u32;
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_BN_init"]
+ pub fn BN_init(bn: *mut BIGNUM);
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_BN_free"]
+ pub fn BN_free(bn: *mut BIGNUM);
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_BN_set_u64"]
+ pub fn BN_set_u64(bn: *mut BIGNUM, value: u64) -> ::std::os::raw::c_int;
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct bn_gencb_st {
+ pub arg: *mut ::std::os::raw::c_void,
+ pub callback: ::std::option::Option<
+ unsafe extern "C" fn(
+ event: ::std::os::raw::c_int,
+ n: ::std::os::raw::c_int,
+ arg1: *mut bn_gencb_st,
+ ) -> ::std::os::raw::c_int,
+ >,
+}
+#[test]
+fn bindgen_test_layout_bn_gencb_st() {
+ assert_eq!(
+ ::std::mem::size_of::<bn_gencb_st>(),
+ 16usize,
+ concat!("Size of: ", stringify!(bn_gencb_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<bn_gencb_st>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(bn_gencb_st))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bn_gencb_st>())).arg as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bn_gencb_st),
+ "::",
+ stringify!(arg)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bn_gencb_st>())).callback as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bn_gencb_st),
+ "::",
+ stringify!(callback)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct bignum_st {
+ pub d: *mut u64,
+ pub width: ::std::os::raw::c_int,
+ pub dmax: ::std::os::raw::c_int,
+ pub neg: ::std::os::raw::c_int,
+ pub flags: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_bignum_st() {
+ assert_eq!(
+ ::std::mem::size_of::<bignum_st>(),
+ 24usize,
+ concat!("Size of: ", stringify!(bignum_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<bignum_st>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(bignum_st))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bignum_st>())).d as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bignum_st),
+ "::",
+ stringify!(d)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bignum_st>())).width as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bignum_st),
+ "::",
+ stringify!(width)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bignum_st>())).dmax as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bignum_st),
+ "::",
+ stringify!(dmax)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bignum_st>())).neg as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bignum_st),
+ "::",
+ stringify!(neg)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bignum_st>())).flags as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bignum_st),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct bn_mont_ctx_st {
+ pub RR: BIGNUM,
+ pub N: BIGNUM,
+ pub n0: [u64; 2usize],
+}
+#[test]
+fn bindgen_test_layout_bn_mont_ctx_st() {
+ assert_eq!(
+ ::std::mem::size_of::<bn_mont_ctx_st>(),
+ 64usize,
+ concat!("Size of: ", stringify!(bn_mont_ctx_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<bn_mont_ctx_st>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(bn_mont_ctx_st))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bn_mont_ctx_st>())).RR as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bn_mont_ctx_st),
+ "::",
+ stringify!(RR)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bn_mont_ctx_st>())).N as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bn_mont_ctx_st),
+ "::",
+ stringify!(N)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<bn_mont_ctx_st>())).n0 as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(bn_mont_ctx_st),
+ "::",
+ stringify!(n0)
+ )
+ );
+}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cbs_st {
@@ -351,6 +677,83 @@
#[link_name = "__RUST_MUNDANE_0_2_2_EC_curve_nid2nist"]
pub fn EC_curve_nid2nist(nid: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char;
}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct openssl_method_common_st {
+ pub references: ::std::os::raw::c_int,
+ pub is_static: ::std::os::raw::c_char,
+}
+#[test]
+fn bindgen_test_layout_openssl_method_common_st() {
+ assert_eq!(
+ ::std::mem::size_of::<openssl_method_common_st>(),
+ 8usize,
+ concat!("Size of: ", stringify!(openssl_method_common_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<openssl_method_common_st>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(openssl_method_common_st))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<openssl_method_common_st>())).references as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(openssl_method_common_st),
+ "::",
+ stringify!(references)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<openssl_method_common_st>())).is_static as *const _ as usize
+ },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(openssl_method_common_st),
+ "::",
+ stringify!(is_static)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct stack_st_void {
+ _unused: [u8; 0],
+}
+pub type CRYPTO_EX_DATA = crypto_ex_data_st;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct crypto_ex_data_st {
+ pub sk: *mut stack_st_void,
+}
+#[test]
+fn bindgen_test_layout_crypto_ex_data_st() {
+ assert_eq!(
+ ::std::mem::size_of::<crypto_ex_data_st>(),
+ 8usize,
+ concat!("Size of: ", stringify!(crypto_ex_data_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<crypto_ex_data_st>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(crypto_ex_data_st))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<crypto_ex_data_st>())).sk as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(crypto_ex_data_st),
+ "::",
+ stringify!(sk)
+ )
+ );
+}
extern "C" {
#[link_name = "__RUST_MUNDANE_0_2_2_EC_KEY_new"]
pub fn EC_KEY_new() -> *mut EC_KEY;
@@ -427,7 +830,6 @@
ctx: *mut ::std::os::raw::c_void,
);
}
-pub type CRYPTO_refcount_t = u32;
extern "C" {
#[link_name = "__RUST_MUNDANE_0_2_2_EVP_sha1"]
pub fn EVP_sha1() -> *const EVP_MD;
@@ -523,6 +925,14 @@
pub fn EVP_PKEY_up_ref(pkey: *mut EVP_PKEY) -> ::std::os::raw::c_int;
}
extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_EVP_PKEY_assign_RSA"]
+ pub fn EVP_PKEY_assign_RSA(pkey: *mut EVP_PKEY, key: *mut RSA) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_EVP_PKEY_get1_RSA"]
+ pub fn EVP_PKEY_get1_RSA(pkey: *const EVP_PKEY) -> *mut RSA;
+}
+extern "C" {
#[link_name = "__RUST_MUNDANE_0_2_2_EVP_PKEY_assign_EC_KEY"]
pub fn EVP_PKEY_assign_EC_KEY(pkey: *mut EVP_PKEY, key: *mut EC_KEY) -> ::std::os::raw::c_int;
}
@@ -812,6 +1222,533 @@
pub fn RAND_bytes(buf: *mut u8, len: usize) -> ::std::os::raw::c_int;
}
extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_new"]
+ pub fn RSA_new() -> *mut RSA;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_free"]
+ pub fn RSA_free(rsa: *mut RSA);
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_up_ref"]
+ pub fn RSA_up_ref(rsa: *mut RSA) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_bits"]
+ pub fn RSA_bits(rsa: *const RSA) -> ::std::os::raw::c_uint;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_generate_key_ex"]
+ pub fn RSA_generate_key_ex(
+ rsa: *mut RSA,
+ bits: ::std::os::raw::c_int,
+ e: *const BIGNUM,
+ cb: *mut BN_GENCB,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_sign"]
+ pub fn RSA_sign(
+ hash_nid: ::std::os::raw::c_int,
+ in_: *const u8,
+ in_len: ::std::os::raw::c_uint,
+ out: *mut u8,
+ out_len: *mut ::std::os::raw::c_uint,
+ rsa: *mut RSA,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_sign_pss_mgf1"]
+ pub 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: ::std::os::raw::c_int,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_verify"]
+ pub fn RSA_verify(
+ hash_nid: ::std::os::raw::c_int,
+ msg: *const u8,
+ msg_len: usize,
+ sig: *const u8,
+ sig_len: usize,
+ rsa: *mut RSA,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_verify_pss_mgf1"]
+ pub 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: ::std::os::raw::c_int,
+ sig: *const u8,
+ sig_len: usize,
+ ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_size"]
+ pub fn RSA_size(rsa: *const RSA) -> ::std::os::raw::c_uint;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_parse_private_key"]
+ pub fn RSA_parse_private_key(cbs: *mut CBS) -> *mut RSA;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_2_2_RSA_marshal_private_key"]
+ pub fn RSA_marshal_private_key(cbb: *mut CBB, rsa: *const RSA) -> ::std::os::raw::c_int;
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct rsa_meth_st {
+ pub common: openssl_method_common_st,
+ pub app_data: *mut ::std::os::raw::c_void,
+ pub init: ::std::option::Option<unsafe extern "C" fn(rsa: *mut RSA) -> ::std::os::raw::c_int>,
+ pub finish: ::std::option::Option<unsafe extern "C" fn(rsa: *mut RSA) -> ::std::os::raw::c_int>,
+ pub size: ::std::option::Option<unsafe extern "C" fn(rsa: *const RSA) -> usize>,
+ pub sign: ::std::option::Option<
+ unsafe extern "C" fn(
+ type_: ::std::os::raw::c_int,
+ m: *const u8,
+ m_length: ::std::os::raw::c_uint,
+ sigret: *mut u8,
+ siglen: *mut ::std::os::raw::c_uint,
+ rsa: *const RSA,
+ ) -> ::std::os::raw::c_int,
+ >,
+ pub sign_raw: ::std::option::Option<
+ unsafe extern "C" fn(
+ rsa: *mut RSA,
+ out_len: *mut usize,
+ out: *mut u8,
+ max_out: usize,
+ in_: *const u8,
+ in_len: usize,
+ padding: ::std::os::raw::c_int,
+ ) -> ::std::os::raw::c_int,
+ >,
+ pub decrypt: ::std::option::Option<
+ unsafe extern "C" fn(
+ rsa: *mut RSA,
+ out_len: *mut usize,
+ out: *mut u8,
+ max_out: usize,
+ in_: *const u8,
+ in_len: usize,
+ padding: ::std::os::raw::c_int,
+ ) -> ::std::os::raw::c_int,
+ >,
+ pub private_transform: ::std::option::Option<
+ unsafe extern "C" fn(
+ rsa: *mut RSA,
+ out: *mut u8,
+ in_: *const u8,
+ len: usize,
+ ) -> ::std::os::raw::c_int,
+ >,
+ pub flags: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_rsa_meth_st() {
+ assert_eq!(
+ ::std::mem::size_of::<rsa_meth_st>(),
+ 80usize,
+ concat!("Size of: ", stringify!(rsa_meth_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<rsa_meth_st>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(rsa_meth_st))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).common as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(common)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).app_data as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(app_data)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).init as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(init)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).finish as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(finish)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).size as *const _ as usize },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).sign as *const _ as usize },
+ 40usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(sign)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).sign_raw as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(sign_raw)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).decrypt as *const _ as usize },
+ 56usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(decrypt)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).private_transform as *const _ as usize },
+ 64usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(private_transform)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_meth_st>())).flags as *const _ as usize },
+ 72usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_meth_st),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct bn_blinding_st {
+ _unused: [u8; 0],
+}
+pub type BN_BLINDING = bn_blinding_st;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct rsa_st {
+ pub meth: *mut RSA_METHOD,
+ pub n: *mut BIGNUM,
+ pub e: *mut BIGNUM,
+ pub d: *mut BIGNUM,
+ pub p: *mut BIGNUM,
+ pub q: *mut BIGNUM,
+ pub dmp1: *mut BIGNUM,
+ pub dmq1: *mut BIGNUM,
+ pub iqmp: *mut BIGNUM,
+ pub ex_data: CRYPTO_EX_DATA,
+ pub references: CRYPTO_refcount_t,
+ pub flags: ::std::os::raw::c_int,
+ pub lock: CRYPTO_MUTEX,
+ pub mont_n: *mut BN_MONT_CTX,
+ pub mont_p: *mut BN_MONT_CTX,
+ pub mont_q: *mut BN_MONT_CTX,
+ pub d_fixed: *mut BIGNUM,
+ pub dmp1_fixed: *mut BIGNUM,
+ pub dmq1_fixed: *mut BIGNUM,
+ pub inv_small_mod_large_mont: *mut BIGNUM,
+ pub num_blindings: ::std::os::raw::c_uint,
+ pub blindings: *mut *mut BN_BLINDING,
+ pub blindings_inuse: *mut ::std::os::raw::c_uchar,
+ pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>,
+ pub __bindgen_padding_0: [u8; 7usize],
+}
+#[test]
+fn bindgen_test_layout_rsa_st() {
+ assert_eq!(
+ ::std::mem::size_of::<rsa_st>(),
+ 376usize,
+ concat!("Size of: ", stringify!(rsa_st))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<rsa_st>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(rsa_st))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).meth as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(meth)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).n as *const _ as usize },
+ 8usize,
+ concat!("Offset of field: ", stringify!(rsa_st), "::", stringify!(n))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).e as *const _ as usize },
+ 16usize,
+ concat!("Offset of field: ", stringify!(rsa_st), "::", stringify!(e))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).d as *const _ as usize },
+ 24usize,
+ concat!("Offset of field: ", stringify!(rsa_st), "::", stringify!(d))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).p as *const _ as usize },
+ 32usize,
+ concat!("Offset of field: ", stringify!(rsa_st), "::", stringify!(p))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).q as *const _ as usize },
+ 40usize,
+ concat!("Offset of field: ", stringify!(rsa_st), "::", stringify!(q))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).dmp1 as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(dmp1)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).dmq1 as *const _ as usize },
+ 56usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(dmq1)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).iqmp as *const _ as usize },
+ 64usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(iqmp)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).ex_data as *const _ as usize },
+ 72usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(ex_data)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).references as *const _ as usize },
+ 80usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(references)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).flags as *const _ as usize },
+ 84usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).lock as *const _ as usize },
+ 88usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(lock)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).mont_n as *const _ as usize },
+ 288usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(mont_n)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).mont_p as *const _ as usize },
+ 296usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(mont_p)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).mont_q as *const _ as usize },
+ 304usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(mont_q)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).d_fixed as *const _ as usize },
+ 312usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(d_fixed)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).dmp1_fixed as *const _ as usize },
+ 320usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(dmp1_fixed)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).dmq1_fixed as *const _ as usize },
+ 328usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(dmq1_fixed)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).inv_small_mod_large_mont as *const _ as usize },
+ 336usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(inv_small_mod_large_mont)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).num_blindings as *const _ as usize },
+ 344usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(num_blindings)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).blindings as *const _ as usize },
+ 352usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(blindings)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<rsa_st>())).blindings_inuse as *const _ as usize },
+ 360usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(rsa_st),
+ "::",
+ stringify!(blindings_inuse)
+ )
+ );
+}
+impl rsa_st {
+ #[inline]
+ pub fn private_key_frozen(&self) -> ::std::os::raw::c_uint {
+ unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) }
+ }
+ #[inline]
+ pub fn set_private_key_frozen(&mut self, val: ::std::os::raw::c_uint) {
+ unsafe {
+ let val: u32 = ::std::mem::transmute(val);
+ self._bitfield_1.set(0usize, 1u8, val as u64)
+ }
+ }
+ #[inline]
+ pub fn new_bitfield_1(
+ private_key_frozen: ::std::os::raw::c_uint,
+ ) -> __BindgenBitfieldUnit<[u8; 1usize], u8> {
+ let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize], u8> =
+ Default::default();
+ __bindgen_bitfield_unit.set(0usize, 1u8, {
+ let private_key_frozen: u32 = unsafe { ::std::mem::transmute(private_key_frozen) };
+ private_key_frozen as u64
+ });
+ __bindgen_bitfield_unit
+ }
+}
+extern "C" {
#[link_name = "__RUST_MUNDANE_0_2_2_SHA1_Init"]
pub fn SHA1_Init(sha: *mut SHA_CTX) -> ::std::os::raw::c_int;
}
diff --git a/src/boringssl/mod.rs b/src/boringssl/mod.rs
index 56d280d..3b95135 100644
--- a/src/boringssl/mod.rs
+++ b/src/boringssl/mod.rs
@@ -63,6 +63,10 @@
// - Any BoringSSL documentation that says "x property must hold" means that, if
// that property doesn't hold, it may cause UB - you are not guaranteed that
// it will be detected and an error will be returned.
+// - If a pointer parameter is const, the function does NOT take ownership of
+// the object. If the pointer parameter is not const, it MAY take ownership
+// depending on documentation. Generally, ownership is only taken if
+// explicitly documented, but documentation bugs may exist, so be careful.
// NOTE(joshlf): It's important to define this module before the abort module,
// or else all of the assertions that are auto-generated by bindgen would result
@@ -77,17 +81,19 @@
// C types
pub use boringssl::ffi::{
- CBB, CBS, EC_GROUP, EC_KEY, EVP_MD, EVP_PKEY, HMAC_CTX, SHA256_CTX, SHA512_CTX, SHA_CTX,
+ BIGNUM, CBB, CBS, EC_GROUP, EC_KEY, EVP_MD, EVP_PKEY, HMAC_CTX, RSA, RSA_F4, SHA256_CTX,
+ SHA512_CTX, SHA_CTX,
};
// C constants
pub use boringssl::ffi::{
- NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, ED25519_PRIVATE_KEY_LEN,
- ED25519_PUBLIC_KEY_LEN, ED25519_SIGNATURE_LEN, SHA256_DIGEST_LENGTH, SHA384_DIGEST_LENGTH,
- SHA512_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
+ NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_sha1, NID_sha256, NID_sha384,
+ NID_sha512, ED25519_PRIVATE_KEY_LEN, ED25519_PUBLIC_KEY_LEN, ED25519_SIGNATURE_LEN,
+ SHA256_DIGEST_LENGTH, SHA384_DIGEST_LENGTH, SHA512_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
};
// wrapper types
pub use boringssl::wrapper::{CHeapWrapper, CRef, CStackWrapper};
+use std::convert::TryInto;
use std::ffi::CStr;
use std::fmt::{self, Debug, Display, Formatter};
use std::num::NonZeroUsize;
@@ -96,15 +102,25 @@
use boringssl::abort::UnwrapAbort;
use boringssl::raw::{
- CBB_data, CBB_init, CBB_len, CBS_init, CBS_len, CRYPTO_memcmp, ECDSA_sign, ECDSA_size,
- ECDSA_verify, EC_GROUP_get_curve_name, EC_GROUP_new_by_curve_name, EC_KEY_generate_key,
- EC_KEY_get0_group, EC_KEY_marshal_private_key, EC_KEY_parse_private_key, EC_KEY_set_group,
- EC_curve_nid2nist, ED25519_keypair, ED25519_keypair_from_seed, ED25519_sign, ED25519_verify,
- ERR_print_errors_cb, EVP_PBE_scrypt, EVP_PKEY_assign_EC_KEY, EVP_PKEY_get1_EC_KEY,
- EVP_marshal_public_key, EVP_parse_public_key, HMAC_CTX_init, HMAC_Final, HMAC_Init_ex,
- HMAC_Update, HMAC_size, RAND_bytes, SHA384_Init,
+ BN_set_u64, CBB_data, CBB_init, CBB_len, CBS_init, CBS_len, CRYPTO_memcmp, ECDSA_sign,
+ ECDSA_size, ECDSA_verify, EC_GROUP_get_curve_name, EC_GROUP_new_by_curve_name,
+ EC_KEY_generate_key, EC_KEY_get0_group, EC_KEY_marshal_private_key, EC_KEY_parse_private_key,
+ EC_KEY_set_group, EC_curve_nid2nist, ED25519_keypair, ED25519_keypair_from_seed, ED25519_sign,
+ ED25519_verify, ERR_print_errors_cb, EVP_PBE_scrypt, EVP_PKEY_assign_EC_KEY,
+ EVP_PKEY_assign_RSA, EVP_PKEY_get1_EC_KEY, EVP_PKEY_get1_RSA, EVP_marshal_public_key,
+ EVP_parse_public_key, HMAC_CTX_init, HMAC_Final, HMAC_Init_ex, HMAC_Update, HMAC_size,
+ RAND_bytes, RSA_bits, RSA_generate_key_ex, RSA_marshal_private_key, RSA_parse_private_key,
+ RSA_size, SHA384_Init,
};
+impl CStackWrapper<BIGNUM> {
+ /// The `BN_set_u64` function.
+ #[must_use]
+ pub fn bn_set_u64(&mut self, value: u64) -> Result<(), BoringError> {
+ unsafe { BN_set_u64(self.as_mut(), value) }
+ }
+}
+
impl CStackWrapper<CBB> {
/// Creates a new `CBB` and initializes it with `CBB_init`.
///
@@ -276,8 +292,9 @@
)?;
// ECDSA_sign guarantees that it only needs ECDSA_size bytes for the
// signature.
- assert_abort!(sig_len as usize <= min_size.get());
- Ok(sig_len as usize)
+ let sig_len = sig_len.try_into().unwrap_abort();
+ assert_abort!(sig_len <= min_size.get());
+ Ok(sig_len)
}
}
@@ -373,6 +390,19 @@
}
}
+ /// The `EVP_PKEY_assign_RSA` function.
+ pub fn evp_pkey_assign_rsa(&mut self, rsa: CHeapWrapper<RSA>) {
+ unsafe {
+ // NOTE: It's very important that we use 'into_mut' here so that
+ // rsa's refcount is not decremented. That's because
+ // EVP_PKEY_assign_RSA doesn't increment the refcount of its
+ // argument.
+ let key = rsa.into_mut();
+ // EVP_PKEY_assign_RSA only fails if key is NULL.
+ EVP_PKEY_assign_RSA(self.as_mut(), key).unwrap_abort()
+ }
+ }
+
/// The `EVP_PKEY_get1_EC_KEY` function.
#[must_use]
pub fn evp_pkey_get1_ec_key(&mut self) -> Result<CHeapWrapper<EC_KEY>, BoringError> {
@@ -380,6 +410,14 @@
// refcount of the EC_KEY before returning a pointer to it.
unsafe { Ok(CHeapWrapper::new_from(EVP_PKEY_get1_EC_KEY(self.as_mut())?)) }
}
+
+ /// The `EVP_PKEY_get1_RSA` function.
+ #[must_use]
+ pub fn evp_pkey_get1_rsa(&mut self) -> Result<CHeapWrapper<RSA>, BoringError> {
+ // NOTE: It's important that we use get1 here, as it increments the
+ // refcount of the RSA key before returning a pointer to it.
+ unsafe { Ok(CHeapWrapper::new_from(EVP_PKEY_get1_RSA(self.as_mut())?)) }
+ }
}
/// The `EVP_PBE_scrypt` function.
@@ -543,6 +581,52 @@
}
}
+impl CHeapWrapper<RSA> {
+ /// The `RSA_bits` function.
+ #[must_use]
+ pub fn rsa_bits(&self) -> c_uint {
+ // RSA_bits does not mutate its argument but, for
+ // backwards-compatibility reasons, continues to take a normal
+ // (non-const) pointer.
+ unsafe { RSA_bits(self.as_const() as *mut _) }
+ }
+
+ /// The `RSA_generate_key_ex` function.
+ #[must_use]
+ pub fn rsa_generate_key_ex(
+ &mut self,
+ bits: c_int,
+ e: &CRef<BIGNUM>,
+ ) -> Result<(), BoringError> {
+ unsafe {
+ // NOTE: It's very important that we use 'into_mut' here so that e's
+ // refcount is not decremented. That's because RSA_generate_key_ex
+ // takes ownership of e, and thus doesn't increment its refcount.
+ RSA_generate_key_ex(self.as_mut(), bits, e.as_const(), ptr::null_mut())
+ }
+ }
+
+ /// The `RSA_marshal_private_key` function.
+ #[must_use]
+ pub fn rsa_marshal_private_key(&self, cbb: &mut CStackWrapper<CBB>) -> Result<(), BoringError> {
+ unsafe { RSA_marshal_private_key(cbb.as_mut(), self.as_const()) }
+ }
+
+ /// The `RSA_parse_private_key` function.
+ #[must_use]
+ pub fn rsa_parse_private_key(
+ cbs: &mut CStackWrapper<CBS>,
+ ) -> Result<CHeapWrapper<RSA>, BoringError> {
+ unsafe { Ok(CHeapWrapper::new_from(RSA_parse_private_key(cbs.as_mut())?)) }
+ }
+
+ /// The `RSA_size` function.
+ #[must_use]
+ pub fn rsa_size(&self) -> Result<NonZeroUsize, BoringError> {
+ unsafe { RSA_size(self.as_const()) }
+ }
+}
+
/// Implements `CStackWrapper` for a hash context type.
///
/// The caller provides doc comments, a public method name, and a private
diff --git a/src/boringssl/raw.rs b/src/boringssl/raw.rs
index d8b212b..0251597 100644
--- a/src/boringssl/raw.rs
+++ b/src/boringssl/raw.rs
@@ -18,17 +18,35 @@
pub use boringssl::ffi::{
CBB_cleanup, 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,
+ RSA_bits,
};
+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 boringssl::ffi::{self, CBB, CBS, EC_GROUP, EC_KEY, EVP_MD, EVP_PKEY, HMAC_CTX, SHA512_CTX};
+use boringssl::ffi::{
+ self, 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;
+// bn.h
+
+// BIGNUMs can be either heap- or stack-allocated, and they keep track of which
+// they are internally so that BN_free does the right thing - freeing the object
+// itself if heap-allocated, and only freeing its internal state otherwise.
+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))
+}
+
// bytestring.h
impl_traits!(CBB, CDestruct => CBB_cleanup);
@@ -252,11 +270,23 @@
#[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(
@@ -365,6 +395,46 @@
assert_abort_eq!(ffi::RAND_bytes(buf, len), 1);
}
+// rsa.h
+
+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))
+}
+
+#[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"))
+}
+
// sha.h
#[allow(non_snake_case)]
diff --git a/src/boringssl/wrapper.rs b/src/boringssl/wrapper.rs
index 864a8b0..91ff668 100644
--- a/src/boringssl/wrapper.rs
+++ b/src/boringssl/wrapper.rs
@@ -322,6 +322,11 @@
}
#[must_use]
+ pub fn as_c_ref(&mut self) -> CRef<C> {
+ unsafe { CRef::new(NonNull::new_unchecked(&mut self.obj as *mut C)) }
+ }
+
+ #[must_use]
pub fn as_mut(&mut self) -> *mut C {
&mut self.obj
}
diff --git a/src/hash.rs b/src/hash.rs
index 39ecef6..a42da6b 100644
--- a/src/hash.rs
+++ b/src/hash.rs
@@ -11,10 +11,13 @@
use boringssl::{self, CStackWrapper};
pub(crate) mod inner {
+ use std::os::raw::c_int;
+
use boringssl::{CRef, EVP_MD};
pub trait Hasher {
fn evp_md() -> CRef<'static, EVP_MD>;
+ fn nid() -> c_int;
}
pub trait Digest {
@@ -176,7 +179,7 @@
/// For the digest type, the traits `PartialEq`, `Eq`, `Display`, and `Debug`
/// are also implemented.
macro_rules! impl_hash {
- ($name:ident, $digest_name:path, $digest_len:path, $update:ident, $final:ident, $evp_md:ident) => {
+ ($name:ident, $digest_name:path, $digest_len:path, $update:ident, $final:ident, $evp_md:ident, $nid:ident) => {
#[allow(deprecated)]
impl ::util::Sealed for $name {}
#[allow(deprecated)]
@@ -196,6 +199,10 @@
fn evp_md() -> ::boringssl::CRef<'static, ::boringssl::EVP_MD> {
::boringssl::CRef::$evp_md()
}
+ fn nid() -> ::std::os::raw::c_int {
+ use std::convert::TryInto;
+ ::boringssl::$nid.try_into().unwrap()
+ }
}
#[allow(deprecated)]
impl self::inner::Digest for $digest_name {
@@ -254,7 +261,8 @@
boringssl::SHA_DIGEST_LENGTH,
sha1_update,
sha1_final,
- evp_sha1
+ evp_sha1,
+ NID_sha1
);
impl_hash!(
Sha256,
@@ -262,7 +270,8 @@
boringssl::SHA256_DIGEST_LENGTH,
sha256_update,
sha256_final,
- evp_sha256
+ evp_sha256,
+ NID_sha256
);
impl_hash!(
Sha384,
@@ -270,7 +279,8 @@
boringssl::SHA384_DIGEST_LENGTH,
sha384_update,
sha384_final,
- evp_sha384
+ evp_sha384,
+ NID_sha384
);
impl_hash!(
Sha512,
@@ -278,7 +288,8 @@
boringssl::SHA512_DIGEST_LENGTH,
sha512_update,
sha512_final,
- evp_sha512
+ evp_sha512,
+ NID_sha512
);
#[cfg(test)]
diff --git a/src/lib.rs b/src/lib.rs
index b4e71e1..a58c679 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,6 +46,11 @@
// just in case we forget to add #[forbid(unsafe_code)] on new module
// definitions
#![deny(unsafe_code)]
+// NOTE(joshlf): This is the only feature we allow. It keeps us from working on
+// stable Rust, but that's justified by the fact that it's important for
+// ensuring the soundness of our unsafe code. Once this feature is stabilized,
+// we will promise to work on stable going forward.
+#![feature(try_from)]
#[macro_use]
mod macros;
diff --git a/src/public/mod.rs b/src/public/mod.rs
index 171e9d4..7ec6643 100644
--- a/src/public/mod.rs
+++ b/src/public/mod.rs
@@ -8,6 +8,7 @@
pub mod ec;
pub mod ed25519;
+pub mod rsa;
use boringssl::{CHeapWrapper, CStackWrapper};
use public::inner::BoringDerKey;
diff --git a/src/public/rsa/bits.rs b/src/public/rsa/bits.rs
new file mode 100644
index 0000000..e0a8d7c
--- /dev/null
+++ b/src/public/rsa/bits.rs
@@ -0,0 +1,77 @@
+// Copyright 2018 Google LLC
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT.
+
+use std::fmt::{self, Debug, Display, Formatter};
+
+use util::Sealed;
+
+/// The bit length of an RSA key.
+///
+/// The [`RsaPrivKey`] and [`RsaPubKey`] types take a `B: RsaKeyBits` type
+/// parameter indicating the key's length in bits.
+///
+/// We only support bit lengths of 2048 or greater, as smaller bit lengths are
+/// considered insecure. If 2048 is considered insecure at some point in the
+/// future, then we will remove support for it, which will be a breaking change.
+///
+/// [`RsaPrivKey`]: ::public::rsa::RsaPrivKey
+/// [`RsaPubKey`]: ::public::rsa::RsaPubKey
+pub trait RsaKeyBits: Sized + Copy + Clone + Default + Display + Debug + Sealed {
+ /// The number of bits.
+ const BITS: usize;
+}
+
+/// 2048 bits.
+///
+/// `B2048` indicates a 2048-bit RSA key; it implements [`RsaKeyBits`].
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
+pub struct B2048;
+
+/// 3072 bits.
+///
+/// `B3072` indicates a 3072-bit RSA key; it implements [`RsaKeyBits`].
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
+pub struct B3072;
+
+/// 4096 bits.
+///
+/// `B4096` indicates a 4096-bit RSA key; it implements [`RsaKeyBits`].
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
+pub struct B4096;
+
+/// 6144 bits.
+///
+/// `B6144` indicates a 6144-bit RSA key; it implements [`RsaKeyBits`].
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
+pub struct B6144;
+
+/// 8192 bits.
+///
+/// `B8192` indicates a 8192-bit RSA key; it implements [`RsaKeyBits`].
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
+pub struct B8192;
+
+macro_rules! impl_bits {
+ ($name:ident, $bits:expr) => {
+ impl RsaKeyBits for $name {
+ const BITS: usize = $bits;
+ }
+
+ impl Display for $name {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
+ write!(f, "{} bits", $bits)
+ }
+ }
+
+ impl Sealed for $name {}
+ };
+}
+
+impl_bits!(B2048, 2048);
+impl_bits!(B3072, 3072);
+impl_bits!(B4096, 4096);
+impl_bits!(B6144, 6144);
+impl_bits!(B8192, 8192);
diff --git a/src/public/rsa/mod.rs b/src/public/rsa/mod.rs
new file mode 100644
index 0000000..548615a
--- /dev/null
+++ b/src/public/rsa/mod.rs
@@ -0,0 +1,554 @@
+// Copyright 2018 Google LLC
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT.
+
+//! The RSA public-key cryptosystem.
+
+mod bits;
+
+pub use public::rsa::bits::{RsaKeyBits, B2048, B3072, B4096, B6144, B8192};
+
+use std::convert::TryInto;
+use std::fmt::{self, Debug, Formatter};
+
+use boringssl::{CHeapWrapper, CStackWrapper};
+use public::rsa::inner::RsaKey;
+use public::{inner::DerKey, DerPrivateKey, DerPublicKey, PrivateKey, PublicKey};
+use util::Sealed;
+use Error;
+
+mod inner {
+ use std::convert::TryInto;
+ use std::marker::PhantomData;
+ use std::os::raw::c_uint;
+
+ use boringssl::{self, BoringError, CHeapWrapper, CStackWrapper};
+ use public::inner::BoringDerKey;
+ use public::rsa::RsaKeyBits;
+ use Error;
+
+ // A convenience wrapper around boringssl::RSA.
+ //
+ // RsaKey maintains the following invariants:
+ // - The key is valid.
+ // - The key has B bits.
+ //
+ // This is marked pub and put in this (non-public) module so that using it in impls of
+ // the Key trait don't result in public-in-private errors.
+ #[derive(Clone)]
+ pub struct RsaKey<B: RsaKeyBits> {
+ pub key: CHeapWrapper<boringssl::RSA>,
+ _marker: PhantomData<B>,
+ }
+
+ impl<B: RsaKeyBits> RsaKey<B> {
+ pub fn generate() -> Result<RsaKey<B>, BoringError> {
+ let mut key = CHeapWrapper::default();
+ let mut e = CStackWrapper::default();
+ // BN_set_u64 can only fail due to OOM.
+ e.bn_set_u64(boringssl::RSA_F4.into()).unwrap();
+ key.rsa_generate_key_ex(B::BITS.try_into().unwrap(), &e.as_c_ref())?;
+ Ok(RsaKey {
+ key,
+ _marker: PhantomData,
+ })
+ }
+
+ /// Creates an `RsaKey` from a BoringSSL `RSA`.
+ ///
+ /// `from_RSA` validates that `key` has `B` bits.
+ #[allow(non_snake_case)]
+ pub fn from_RSA(key: CHeapWrapper<boringssl::RSA>) -> Result<RsaKey<B>, Error> {
+ B::validate_bits(key.rsa_bits())?;
+ Ok(RsaKey {
+ key,
+ _marker: PhantomData,
+ })
+ }
+ }
+
+ impl<B: RsaKeyBits> BoringDerKey for RsaKey<B> {
+ fn pkey_assign(&self, pkey: &mut CHeapWrapper<boringssl::EVP_PKEY>) {
+ pkey.evp_pkey_assign_rsa(self.key.clone())
+ }
+
+ fn pkey_get(pkey: &mut CHeapWrapper<boringssl::EVP_PKEY>) -> Result<Self, Error> {
+ let key = pkey.evp_pkey_get1_rsa()?;
+ RsaKey::from_RSA(key)
+ }
+
+ fn parse_private_key(cbs: &mut CStackWrapper<boringssl::CBS>) -> Result<RsaKey<B>, Error> {
+ let key = CHeapWrapper::rsa_parse_private_key(cbs)?;
+ RsaKey::from_RSA(key)
+ }
+
+ fn marshal_private_key(
+ &self,
+ cbb: &mut CStackWrapper<boringssl::CBB>,
+ ) -> Result<(), Error> {
+ self.key.rsa_marshal_private_key(cbb).map_err(From::from)
+ }
+ }
+
+ trait RsaKeyBitsExt: RsaKeyBits {
+ fn validate_bits(bits: c_uint) -> Result<(), Error> {
+ if <c_uint as TryInto<usize>>::try_into(bits).unwrap() != Self::BITS {
+ return Err(Error::new(format!(
+ "unexpected RSA key bit length: got {}; want {}",
+ bits,
+ Self::BITS
+ )));
+ }
+ Ok(())
+ }
+ }
+
+ impl<B: RsaKeyBits> RsaKeyBitsExt for B {}
+
+ #[cfg(test)]
+ mod tests {
+ use std::mem;
+
+ use super::*;
+ use public::rsa::{B2048, B3072, B4096, B6144, B8192};
+
+ #[test]
+ fn test_refcount() {
+ // Test that we refcount properly by creating many clones and then
+ // freeing them all. If we decrement the recount below 0, a test in
+ // BoringSSL will catch it and crash the program. This test cannot
+ // currently detect not decrementing the refcount enough (thus
+ // leaking resources).
+ //
+ // TODO(joshlf): Figure out a way to also test that we decrement the
+ // refcount enough.
+
+ fn test<B: RsaKeyBits>() {
+ let key = RsaKey::<B>::generate().unwrap();
+ for i in 0..8 {
+ // make i clones and then free them all
+ let mut keys = Vec::new();
+ for _ in 0..i {
+ keys.push(key.clone());
+ }
+ mem::drop(keys);
+ }
+ mem::drop(key);
+ }
+
+ test::<B2048>();
+ test::<B3072>();
+ test::<B4096>();
+ test::<B6144>();
+ test::<B8192>();
+ }
+ }
+}
+
+/// A `B`-bit RSA public key.
+///
+/// `RsaPubKey` is an RSA public key which is `B` bits long.
+pub struct RsaPubKey<B: RsaKeyBits> {
+ inner: RsaKey<B>,
+}
+
+impl<B: RsaKeyBits> Sealed for RsaPubKey<B> {}
+impl<B: RsaKeyBits> DerPublicKey for RsaPubKey<B> {}
+
+impl<B: RsaKeyBits> DerKey for RsaPubKey<B> {
+ type Boring = RsaKey<B>;
+ fn boring(&self) -> &RsaKey<B> {
+ &self.inner
+ }
+ fn from_boring(inner: RsaKey<B>) -> RsaPubKey<B> {
+ RsaPubKey { inner }
+ }
+}
+
+impl<B: RsaKeyBits> PublicKey for RsaPubKey<B> {
+ type Private = RsaPrivKey<B>;
+}
+
+impl<B: RsaKeyBits> Debug for RsaPubKey<B> {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
+ write!(f, "RsaPubKey")
+ }
+}
+
+/// A `B`-bit RSA private key.
+///
+/// `RsaPrivKey` is an RSA private key which is `B` bits long.
+pub struct RsaPrivKey<B: RsaKeyBits> {
+ inner: RsaKey<B>,
+}
+
+impl<B: RsaKeyBits> RsaPrivKey<B> {
+ /// Generates a new private key.
+ #[must_use]
+ pub fn generate() -> Result<RsaPrivKey<B>, Error> {
+ Ok(RsaPrivKey {
+ inner: RsaKey::generate()?,
+ })
+ }
+}
+
+impl<B: RsaKeyBits> Sealed for RsaPrivKey<B> {}
+impl<B: RsaKeyBits> DerPrivateKey for RsaPrivKey<B> {}
+
+impl<B: RsaKeyBits> DerKey for RsaPrivKey<B> {
+ type Boring = RsaKey<B>;
+ fn boring(&self) -> &RsaKey<B> {
+ &self.inner
+ }
+ fn from_boring(inner: RsaKey<B>) -> RsaPrivKey<B> {
+ RsaPrivKey { inner }
+ }
+}
+
+impl<B: RsaKeyBits> PrivateKey for RsaPrivKey<B> {
+ type Public = RsaPubKey<B>;
+
+ fn public(&self) -> RsaPubKey<B> {
+ RsaPubKey {
+ inner: self.inner.clone(),
+ }
+ }
+}
+
+impl<B: RsaKeyBits> Debug for RsaPrivKey<B> {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
+ write!(f, "RsaPrivKey")
+ }
+}
+
+/// An RSA public key whose bit length is unknown at compile time.
+///
+/// An `RsaPubKeyAnyBits` is an enum of [`RsaPubKey`]s over all supported bit
+/// lengths. It is returned from [`parse_public_key_der_any_bits`].
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub enum RsaPubKeyAnyBits {
+ B2048(RsaPubKey<B2048>),
+ B3072(RsaPubKey<B3072>),
+ B4096(RsaPubKey<B4096>),
+ B6144(RsaPubKey<B6144>),
+ B8192(RsaPubKey<B8192>),
+}
+
+impl RsaPubKeyAnyBits {
+ /// Parses a public key in DER format with any bit length.
+ ///
+ /// `parse_from_der` is like [`DerPublicKey::parse_from_der`], but it
+ /// accepts any bit length rather than a particular bit length.
+ ///
+ /// Since [`RsaPubKey`] requires a static [`RsaKeyBits`] type parameter, the
+ /// `parse_from_der` function on `RsaPubKey`'s `DerPublicKey` implementation
+ /// can only be called when the bit length is known ahead of time. This
+ /// function, on the other hand, accepts any bit length.
+ ///
+ /// [`DerPublicKey::parse_from_der`]: ::public::DerPublicKey::parse_from_der
+ /// [`PublicKey`]: ::public::PublicKey
+ #[must_use]
+ pub fn parse_from_der(bytes: &[u8]) -> Result<RsaPubKeyAnyBits, Error> {
+ CStackWrapper::cbs_with_temp_buffer(bytes, |cbs| {
+ let mut evp_pkey = CHeapWrapper::evp_parse_public_key(cbs)?;
+ let key = evp_pkey.evp_pkey_get1_rsa()?;
+ if cbs.cbs_len() > 0 {
+ return Err(Error::new(
+ "excess data provided after valid DER input".to_string(),
+ ));
+ }
+
+ Ok(match key.rsa_bits().try_into().unwrap() {
+ B2048::BITS => RsaPubKeyAnyBits::B2048(RsaPubKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B3072::BITS => RsaPubKeyAnyBits::B3072(RsaPubKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B4096::BITS => RsaPubKeyAnyBits::B4096(RsaPubKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B6144::BITS => RsaPubKeyAnyBits::B6144(RsaPubKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B8192::BITS => RsaPubKeyAnyBits::B8192(RsaPubKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ bits => return Err(Error::new(format!("unsupported bit length: {}", bits))),
+ })
+ })
+ }
+}
+
+/// An RSA private key whose bit length is unknown at compile time.
+///
+/// An `RsaPrivKeyAnyBits` is an enum of [`RsaPrivKey`]s over all supported bit
+/// lengths. It is returned from [`parse_private_key_der_any_bits`].
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub enum RsaPrivKeyAnyBits {
+ B2048(RsaPrivKey<B2048>),
+ B3072(RsaPrivKey<B3072>),
+ B4096(RsaPrivKey<B4096>),
+ B6144(RsaPrivKey<B6144>),
+ B8192(RsaPrivKey<B8192>),
+}
+
+impl RsaPrivKeyAnyBits {
+ /// Gets the public key corresponding to this private key.
+ #[must_use]
+ pub fn public(&self) -> RsaPubKeyAnyBits {
+ match self {
+ RsaPrivKeyAnyBits::B2048(key) => RsaPubKeyAnyBits::B2048(key.public()),
+ RsaPrivKeyAnyBits::B3072(key) => RsaPubKeyAnyBits::B3072(key.public()),
+ RsaPrivKeyAnyBits::B4096(key) => RsaPubKeyAnyBits::B4096(key.public()),
+ RsaPrivKeyAnyBits::B6144(key) => RsaPubKeyAnyBits::B6144(key.public()),
+ RsaPrivKeyAnyBits::B8192(key) => RsaPubKeyAnyBits::B8192(key.public()),
+ }
+ }
+
+ /// Parses a private key in DER format with any bit length.
+ ///
+ /// `parse_from_der` is like [`DerPrivateKey::parse_from_der`], but it
+ /// accepts any bit length rather that a particular bit length.
+ ///
+ /// Since [`RsaPrivKey`] requires a static [`RsaKeyBits`] type parameter,
+ /// the `parse_from_der` function on `RsaPrivKey`'s `DerPrivateKey`
+ /// implementation can only be called when the bit length is known ahead of
+ /// time. This function, on the other hand, accepts any bit length.
+ ///
+ /// [`DerPrivateKey::parse_from_der`]: ::public::DerPrivateKey::parse_from_der
+ /// [`PrivateKey`]: ::public::PrivateKey
+ #[must_use]
+ pub fn parse_from_der(bytes: &[u8]) -> Result<RsaPrivKeyAnyBits, Error> {
+ CStackWrapper::cbs_with_temp_buffer(bytes, |cbs| {
+ let key = CHeapWrapper::rsa_parse_private_key(cbs)?;
+ if cbs.cbs_len() > 0 {
+ return Err(Error::new(
+ "excess data provided after valid DER input".to_string(),
+ ));
+ }
+
+ Ok(match key.rsa_bits().try_into().unwrap() {
+ B2048::BITS => RsaPrivKeyAnyBits::B2048(RsaPrivKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B3072::BITS => RsaPrivKeyAnyBits::B3072(RsaPrivKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B4096::BITS => RsaPrivKeyAnyBits::B4096(RsaPrivKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B6144::BITS => RsaPrivKeyAnyBits::B6144(RsaPrivKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ B8192::BITS => RsaPrivKeyAnyBits::B8192(RsaPrivKey {
+ inner: RsaKey::from_RSA(key.clone())?,
+ }),
+ bits => return Err(Error::new(format!("unsupported bit length: {}", bits))),
+ })
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use util::should_fail;
+
+ #[test]
+ fn test_generate() {
+ RsaPrivKey::<B2048>::generate().unwrap();
+ RsaPrivKey::<B3072>::generate().unwrap();
+ RsaPrivKey::<B4096>::generate().unwrap();
+ RsaPrivKey::<B6144>::generate().unwrap();
+ RsaPrivKey::<B8192>::generate().unwrap();
+ }
+
+ #[test]
+ fn test_marshal_parse() {
+ // Test various combinations of parsing and serializing keys.
+ //
+ // Since we need to test dynamic parsing (the
+ // parse_private_key_der_any_bits and parse_public_key_der_any_bits
+ // functions), we need a way of unwrapping their return values into a
+ // static key type. Unfortunately, there's no way (on stable Rust) to do
+ // that generically, so the caller must pass a function which will do
+ // it.
+ fn test<
+ B: RsaKeyBits,
+ F: Fn(RsaPrivKeyAnyBits) -> RsaPrivKey<B>,
+ G: Fn(RsaPubKeyAnyBits) -> RsaPubKey<B>,
+ >(
+ unwrap_priv_any: F,
+ unwrap_pub_any: G,
+ ) {
+ let key = RsaPrivKey::<B>::generate().unwrap();
+
+ let _ = RsaPrivKey::<B>::parse_from_der(&key.marshal_to_der()).unwrap();
+ let _ =
+ unwrap_priv_any(RsaPrivKeyAnyBits::parse_from_der(&key.marshal_to_der()).unwrap());
+ let pubkey = key.public();
+ let _ = RsaPubKey::<B>::parse_from_der(&pubkey.marshal_to_der()).unwrap();
+ let _ =
+ unwrap_pub_any(RsaPubKeyAnyBits::parse_from_der(&pubkey.marshal_to_der()).unwrap());
+
+ let _ = RsaPubKey::<B>::marshal_to_der;
+ let _ = RsaPubKey::<B>::parse_from_der;
+ }
+
+ macro_rules! unwrap_any_bits {
+ ($name:ident, $any_type:ty, $key_type:ty, $bits_variant:path) => {
+ fn $name(key: $any_type) -> $key_type {
+ match key {
+ $bits_variant(key) => key,
+ _ => panic!("unexpected bits"),
+ }
+ }
+ };
+ }
+
+ unwrap_any_bits!(
+ unwrap_priv_key_any_2048,
+ RsaPrivKeyAnyBits,
+ RsaPrivKey<B2048>,
+ RsaPrivKeyAnyBits::B2048
+ );
+ unwrap_any_bits!(
+ unwrap_priv_key_any_3072,
+ RsaPrivKeyAnyBits,
+ RsaPrivKey<B3072>,
+ RsaPrivKeyAnyBits::B3072
+ );
+ unwrap_any_bits!(
+ unwrap_priv_key_any_4096,
+ RsaPrivKeyAnyBits,
+ RsaPrivKey<B4096>,
+ RsaPrivKeyAnyBits::B4096
+ );
+ unwrap_any_bits!(
+ unwrap_priv_key_any_6144,
+ RsaPrivKeyAnyBits,
+ RsaPrivKey<B6144>,
+ RsaPrivKeyAnyBits::B6144
+ );
+ unwrap_any_bits!(
+ unwrap_priv_key_any_8192,
+ RsaPrivKeyAnyBits,
+ RsaPrivKey<B8192>,
+ RsaPrivKeyAnyBits::B8192
+ );
+ unwrap_any_bits!(
+ unwrap_pub_key_any_2048,
+ RsaPubKeyAnyBits,
+ RsaPubKey<B2048>,
+ RsaPubKeyAnyBits::B2048
+ );
+ unwrap_any_bits!(
+ unwrap_pub_key_any_3072,
+ RsaPubKeyAnyBits,
+ RsaPubKey<B3072>,
+ RsaPubKeyAnyBits::B3072
+ );
+ unwrap_any_bits!(
+ unwrap_pub_key_any_4096,
+ RsaPubKeyAnyBits,
+ RsaPubKey<B4096>,
+ RsaPubKeyAnyBits::B4096
+ );
+ unwrap_any_bits!(
+ unwrap_pub_key_any_6144,
+ RsaPubKeyAnyBits,
+ RsaPubKey<B6144>,
+ RsaPubKeyAnyBits::B6144
+ );
+ unwrap_any_bits!(
+ unwrap_pub_key_any_8192,
+ RsaPubKeyAnyBits,
+ RsaPubKey<B8192>,
+ RsaPubKeyAnyBits::B8192
+ );
+
+ test::<B2048, _, _>(unwrap_priv_key_any_2048, unwrap_pub_key_any_2048);
+ test::<B3072, _, _>(unwrap_priv_key_any_3072, unwrap_pub_key_any_3072);
+ test::<B4096, _, _>(unwrap_priv_key_any_4096, unwrap_pub_key_any_4096);
+ test::<B6144, _, _>(unwrap_priv_key_any_6144, unwrap_pub_key_any_6144);
+ test::<B8192, _, _>(unwrap_priv_key_any_8192, unwrap_pub_key_any_8192);
+ }
+
+ #[test]
+ fn test_parse_fail() {
+ // Test that invalid input is rejected.
+ fn test_parse_invalid<B: RsaKeyBits>() {
+ should_fail(
+ RsaPrivKey::<B>::parse_from_der(&[]),
+ "RsaPrivKey::parse_from_der",
+ "RSA routines:OPENSSL_internal:BAD_ENCODING",
+ );
+ should_fail(
+ RsaPubKey::<B>::parse_from_der(&[]),
+ "RsaPubKey::parse_from_der",
+ "public key routines:OPENSSL_internal:DECODE_ERROR",
+ );
+ should_fail(
+ RsaPrivKeyAnyBits::parse_from_der(&[]),
+ "RsaPrivKeyAnyBits::parse_from_der",
+ "RSA routines:OPENSSL_internal:BAD_ENCODING",
+ );
+ should_fail(
+ RsaPubKeyAnyBits::parse_from_der(&[]),
+ "RsaPubKeyAnyBits::parse_from_der",
+ "public key routines:OPENSSL_internal:DECODE_ERROR",
+ );
+ }
+
+ test_parse_invalid::<B2048>();
+ test_parse_invalid::<B3072>();
+ test_parse_invalid::<B4096>();
+ test_parse_invalid::<B6144>();
+ test_parse_invalid::<B8192>();
+
+ // Test that, when a particular bit size is expected, other bit sizes are
+ // rejected.
+ fn test_parse_wrong_bit_size<B1: RsaKeyBits, B2: RsaKeyBits>() {
+ let privkey = RsaPrivKey::<B1>::generate().unwrap();
+ let key_der = privkey.marshal_to_der();
+ should_fail(
+ RsaPrivKey::<B2>::parse_from_der(&key_der),
+ "RsaPrivKey::parse_from_der",
+ "unexpected RSA key bit length:",
+ );
+ let key_der = privkey.public().marshal_to_der();
+ should_fail(
+ RsaPubKey::<B2>::parse_from_der(&key_der),
+ "RsaPubKey::parse_from_der",
+ "unexpected RSA key bit length:",
+ );
+ }
+
+ // All pairs of bit sizes, (X, Y), such that X != Y.
+ test_parse_wrong_bit_size::<B2048, B3072>();
+ test_parse_wrong_bit_size::<B2048, B4096>();
+ test_parse_wrong_bit_size::<B2048, B6144>();
+ test_parse_wrong_bit_size::<B2048, B8192>();
+ test_parse_wrong_bit_size::<B3072, B2048>();
+ test_parse_wrong_bit_size::<B3072, B4096>();
+ test_parse_wrong_bit_size::<B3072, B6144>();
+ test_parse_wrong_bit_size::<B3072, B8192>();
+ test_parse_wrong_bit_size::<B4096, B2048>();
+ test_parse_wrong_bit_size::<B4096, B3072>();
+ test_parse_wrong_bit_size::<B4096, B6144>();
+ test_parse_wrong_bit_size::<B4096, B8192>();
+ test_parse_wrong_bit_size::<B6144, B2048>();
+ test_parse_wrong_bit_size::<B6144, B3072>();
+ test_parse_wrong_bit_size::<B6144, B4096>();
+ test_parse_wrong_bit_size::<B6144, B8192>();
+ test_parse_wrong_bit_size::<B8192, B2048>();
+ test_parse_wrong_bit_size::<B8192, B3072>();
+ test_parse_wrong_bit_size::<B8192, B4096>();
+ test_parse_wrong_bit_size::<B8192, B6144>();
+ }
+}