Add getters for RSA public exponent and modulus
Closes: #28
Change-Id: I3effea784346fe6c0712780087a6929a2ee5c027
Reviewed-on: https://fuchsia-review.googlesource.com/c/mundane/+/486717
Reviewed-by: Joshua Liebow-Feeser <joshlf@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b99852..5020343 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,9 @@
## Unreleased
+### Added
+- Exposed getters for RSA public exponent and modulus
+
## [0.4.3] - 2020-03-26
### Added
diff --git a/boringssl/bindgen.sh b/boringssl/bindgen.sh
index 227faa2..dbe740f 100755
--- a/boringssl/bindgen.sh
+++ b/boringssl/bindgen.sh
@@ -41,8 +41,10 @@
# former for a consistency check of the postprocessing step which adds the
# #[link_name...] attributes. Any change of the allowlist must be made to the
# appropriate sub-list.
-ALLOWLIST_FUNCS="BN_free|\
+ALLOWLIST_FUNCS="BN_bn2bin_padded|\
+BN_free|\
BN_init|\
+BN_num_bytes|\
BN_set_u64|\
CBS_init|\
CBS_len|\
@@ -103,6 +105,8 @@
RSA_bits|\
RSA_free|\
RSA_generate_key_ex|\
+RSA_get0_e|\
+RSA_get0_n|\
RSA_marshal_private_key|\
RSA_new|\
RSA_parse_private_key|\
diff --git a/boringssl/boringssl.rs b/boringssl/boringssl.rs
index a847438..f4167a2 100644
--- a/boringssl/boringssl.rs
+++ b/boringssl/boringssl.rs
@@ -211,9 +211,18 @@
pub fn BN_free(bn: *mut BIGNUM);
}
extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_4_3_BN_num_bytes"]
+ pub fn BN_num_bytes(bn: *const BIGNUM) -> ::std::os::raw::c_uint;
+}
+extern "C" {
#[link_name = "__RUST_MUNDANE_0_4_3_BN_set_u64"]
pub fn BN_set_u64(bn: *mut BIGNUM, value: u64) -> ::std::os::raw::c_int;
}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_4_3_BN_bn2bin_padded"]
+ pub fn BN_bn2bin_padded(out: *mut u8, len: size_t, in_: *const BIGNUM)
+ -> ::std::os::raw::c_int;
+}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct bn_gencb_st {
@@ -1107,6 +1116,14 @@
pub fn RSA_bits(rsa: *const RSA) -> ::std::os::raw::c_uint;
}
extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_4_3_RSA_get0_n"]
+ pub fn RSA_get0_n(rsa: *const RSA) -> *const BIGNUM;
+}
+extern "C" {
+ #[link_name = "__RUST_MUNDANE_0_4_3_RSA_get0_e"]
+ pub fn RSA_get0_e(rsa: *const RSA) -> *const BIGNUM;
+}
+extern "C" {
#[link_name = "__RUST_MUNDANE_0_4_3_RSA_generate_key_ex"]
pub fn RSA_generate_key_ex(
rsa: *mut RSA,
diff --git a/src/boringssl/mod.rs b/src/boringssl/mod.rs
index 10e17cc..18e69b9 100644
--- a/src/boringssl/mod.rs
+++ b/src/boringssl/mod.rs
@@ -107,15 +107,15 @@
use boringssl::abort::UnwrapAbort;
use boringssl::raw::{
- size_t, 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,
+ size_t, BN_bn2bin_padded, BN_num_bytes, 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_copy, HMAC_CTX_init, HMAC_Final, HMAC_Init_ex, HMAC_Update,
HMAC_size, IntoSizeT, IntoUsize, RAND_bytes, RC4_set_key, RSA_bits, RSA_generate_key_ex,
- RSA_marshal_private_key, RSA_parse_private_key, RSA_sign_pss_mgf1, RSA_size,
+ RSA_get0_e, RSA_get0_n, RSA_marshal_private_key, RSA_parse_private_key, RSA_sign_pss_mgf1, RSA_size,
RSA_verify_pss_mgf1, SHA384_Init, RC4,
};
#[cfg(feature = "rsa-pkcs1v15")]
@@ -129,6 +129,33 @@
}
}
+impl CRef<'_, BIGNUM> {
+ /// The `BN_bn2bin_padded` function.
+ ///
+ /// `bn_bn2bin_padded` can only fail if `out` is shorter than the minimum
+ /// number of bytes required by [`bn_num_bytes`].
+ ///
+ /// [`bn_num_bytes`]: CRef::bn_num_bytes
+ #[must_use]
+ pub fn bn_bn2bin_padded(&self, out: &mut [u8]) -> Result<(), BoringError> {
+ unsafe {
+ BN_bn2bin_padded(
+ out.as_mut_ptr(), out.len().into_size_t(), self.as_const())
+ }
+ }
+
+ /// The `BN_num_bytes` function.
+ ///
+ /// `bn_num_bytes` returns minimum number of bytes required to serialize
+ /// using [`bn_bn2bin_padded`].
+ ///
+ /// [`bn_bn2bin_padded`]: CRef::bn_bn2bin_padded
+ #[must_use]
+ pub fn bn_num_bytes(&self) -> usize {
+ unsafe { BN_num_bytes(self.as_const()).into_usize() }
+ }
+}
+
impl CStackWrapper<CBB> {
/// Creates a new `CBB` and initializes it with `CBB_init`.
///
@@ -648,6 +675,23 @@
unsafe { RSA_bits(self.as_const() as *mut _).into_usize() }
}
+ /// The `RSA_get0_e` function.
+ ///
+ /// Returns a constant reference to the key public exponent.
+ #[must_use]
+ #[allow(clippy::needless_lifetimes)] // to be more explicit
+ pub fn rsa_get0_e<'a>(&'a self) -> Result<CRef<'a, BIGNUM>, BoringError> {
+ unsafe { Ok(CRef::new(RSA_get0_e(self.as_const())?)) }
+ }
+
+ /// The `RSA_get0_n` function.
+ ///
+ /// Returns a constant reference to the key public modulus.
+ #[allow(clippy::needless_lifetimes)] // to be more explicit
+ pub fn rsa_get0_n<'a>(&'a self) -> Result<CRef<'a, BIGNUM>, BoringError> {
+ unsafe { Ok(CRef::new(RSA_get0_n(self.as_const())?)) }
+ }
+
/// The `RSA_generate_key_ex` function.
#[must_use]
pub fn rsa_generate_key_ex(
diff --git a/src/boringssl/raw.rs b/src/boringssl/raw.rs
index dc7bd0f..2561206 100644
--- a/src/boringssl/raw.rs
+++ b/src/boringssl/raw.rs
@@ -21,7 +21,7 @@
// Infallible functions and the `size_t` type.
pub use boringssl::ffi::{
- size_t, CBB_cleanup, CBB_len, CBS_init, CBS_len, CRYPTO_memcmp, EC_GROUP_get_curve_name,
+ size_t, BN_num_bytes, 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,
RC4_set_key, RSA_bits, RC4,
};
@@ -62,6 +62,13 @@
#[allow(non_snake_case)]
#[must_use]
+pub unsafe fn BN_bn2bin_padded(out: *mut u8, len: size_t, bn: *const BIGNUM)
+ -> Result<(), BoringError> {
+ one_or_err("BN_bn2bin_padded", ffi::BN_bn2bin_padded(out, len, bn))
+}
+
+#[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))
}
@@ -418,6 +425,18 @@
ptr_or_err("RSA_parse_private_key", ffi::RSA_parse_private_key(cbs))
}
+#[allow(non_snake_case)]
+#[must_use]
+pub unsafe fn RSA_get0_n(rsa: *const RSA) -> Result<NonNull<BIGNUM>, BoringError> {
+ ptr_or_err("RSA_get0_n", ffi::RSA_get0_n(rsa) as *mut BIGNUM)
+}
+
+#[allow(non_snake_case)]
+#[must_use]
+pub unsafe fn RSA_get0_e(rsa: *const RSA) -> Result<NonNull<BIGNUM>, BoringError> {
+ ptr_or_err("RSA_get0_e", ffi::RSA_get0_e(rsa) as *mut BIGNUM)
+}
+
#[cfg(feature = "rsa-pkcs1v15")]
#[allow(non_snake_case)]
#[must_use]
diff --git a/src/public/rsa/mod.rs b/src/public/rsa/mod.rs
index 9195e89..cf5e85c 100644
--- a/src/public/rsa/mod.rs
+++ b/src/public/rsa/mod.rs
@@ -82,6 +82,36 @@
pub fn get_key(&self) -> &CHeapWrapper<boringssl::RSA> {
&self.key
}
+
+ /// Returns the key's public exponent as a big-endian byte vector.
+ pub fn public_exponent_be(&self) -> Vec<u8> {
+ // Guaranteed to succeed because RSA_get0_e can only fail if
+ // the "e" parameter is not initialized, but one of the invariants
+ // on RsaKey is that it is initialized.
+ let bignum = self.key.rsa_get0_e().unwrap();
+ let num_bytes = bignum.bn_num_bytes();
+ let mut exponent = vec![0; num_bytes];
+ // Guaranteed to succeed because the size of `exponent` is
+ // [`bn_num_bytes`].
+ bignum.bn_bn2bin_padded(exponent.as_mut_slice()).unwrap();
+
+ exponent
+ }
+
+ /// Returns the key's public modulus as a big-endian byte vector.
+ pub fn public_modulus_be(&self) -> Vec<u8> {
+ // Guaranteed to succeed because RSA_get0_n can only fail if
+ // the "n" parameter is not initialized, but one of the invariants
+ // on RsaKey is that it is initialized.
+ let bignum = self.key.rsa_get0_n().unwrap();
+ let num_bytes = bignum.bn_num_bytes();
+ let mut modulus = vec![0; num_bytes];
+ // Guaranteed to succeed because the size of `modulus` is
+ // [`bn_num_bytes`].
+ bignum.bn_bn2bin_padded(modulus.as_mut_slice()).unwrap();
+
+ modulus
+ }
}
impl<B: RsaKeyBits> BoringDerKey for RsaKey<B> {
@@ -215,6 +245,18 @@
pub fn generate() -> Result<RsaPrivKey<B>, Error> {
Ok(RsaPrivKey { inner: RsaKey::generate()? })
}
+
+ #[must_use]
+ /// Returns the key's public exponent as a big-endian byte vector.
+ pub fn public_exponent_be(&self) -> Vec<u8> {
+ self.inner.public_exponent_be()
+ }
+
+ #[must_use]
+ /// Returns the key's public modulus as a big-endian byte vector.
+ pub fn public_modulus_be(&self) -> Vec<u8> {
+ self.inner.public_modulus_be()
+ }
}
impl<B: RsaKeyBits> Sealed for RsaPrivKey<B> {}