diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 7852e0d27245e..7c08862b30707 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -392,127 +392,19 @@ def _evp_pkey_to_private_key( Return the appropriate type of PrivateKey given an evp_pkey cdata pointer. """ - - key_type = self._lib.EVP_PKEY_id(evp_pkey) - - if key_type == self._lib.EVP_PKEY_RSA: - return rust_openssl.rsa.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)), - unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, - ) - elif ( - key_type == self._lib.EVP_PKEY_RSA_PSS - and not self._lib.CRYPTOGRAPHY_IS_LIBRESSL - and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL - and not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E - ): - # At the moment the way we handle RSA PSS keys is to strip the - # PSS constraints from them and treat them as normal RSA keys - # Unfortunately the RSA * itself tracks this data so we need to - # extract, serialize, and reload it without the constraints. - rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) - self.openssl_assert(rsa_cdata != self._ffi.NULL) - rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) - bio = self._create_mem_bio_gc() - res = self._lib.i2d_RSAPrivateKey_bio(bio, rsa_cdata) - self.openssl_assert(res == 1) - return self.load_der_private_key( - self._read_mem_bio(bio), - password=None, - unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, - ) - elif key_type == self._lib.EVP_PKEY_DSA: - return rust_openssl.dsa.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == self._lib.EVP_PKEY_EC: - return rust_openssl.ec.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type in self._dh_types: - return rust_openssl.dh.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): - # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return rust_openssl.ed25519.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): - # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return rust_openssl.x448.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == self._lib.EVP_PKEY_X25519: - return rust_openssl.x25519.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): - # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return rust_openssl.ed448.private_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - else: - raise UnsupportedAlgorithm("Unsupported key type.") + return rust_openssl.keys.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)), + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, + ) def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: """ Return the appropriate type of PublicKey given an evp_pkey cdata pointer. """ - - key_type = self._lib.EVP_PKEY_id(evp_pkey) - - if key_type == self._lib.EVP_PKEY_RSA: - return rust_openssl.rsa.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif ( - key_type == self._lib.EVP_PKEY_RSA_PSS - and not self._lib.CRYPTOGRAPHY_IS_LIBRESSL - and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL - and not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E - ): - rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) - self.openssl_assert(rsa_cdata != self._ffi.NULL) - rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) - bio = self._create_mem_bio_gc() - res = self._lib.i2d_RSAPublicKey_bio(bio, rsa_cdata) - self.openssl_assert(res == 1) - return self.load_der_public_key(self._read_mem_bio(bio)) - elif key_type == self._lib.EVP_PKEY_DSA: - return rust_openssl.dsa.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == self._lib.EVP_PKEY_EC: - return rust_openssl.ec.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type in self._dh_types: - return rust_openssl.dh.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): - # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return rust_openssl.ed25519.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): - # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return rust_openssl.x448.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == self._lib.EVP_PKEY_X25519: - return rust_openssl.x25519.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): - # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return rust_openssl.ed448.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) - else: - raise UnsupportedAlgorithm("Unsupported key type.") + return rust_openssl.keys.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) def _oaep_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: if self._fips_enabled and isinstance(algorithm, hashes.SHA1): @@ -620,9 +512,7 @@ def load_pem_public_key(self, data: bytes) -> PublicKeyTypes: if rsa_cdata != self._ffi.NULL: rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) - return rust_openssl.rsa.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) + return self._evp_pkey_to_public_key(evp_pkey) else: self._handle_key_loading_error() @@ -685,9 +575,7 @@ def load_der_public_key(self, data: bytes) -> PublicKeyTypes: if rsa_cdata != self._ffi.NULL: rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) - return rust_openssl.rsa.public_key_from_ptr( - int(self._ffi.cast("uintptr_t", evp_pkey)) - ) + return self._evp_pkey_to_public_key(evp_pkey) else: self._handle_key_loading_error() diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index e95bc15457ae0..9cdb4d6a5c6e4 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -15,6 +15,7 @@ from cryptography.hazmat.bindings._rust.openssl import ( hashes, hmac, kdf, + keys, poly1305, rsa, x448, @@ -32,6 +33,7 @@ __all__ = [ "hashes", "hmac", "kdf", + "keys", "ed448", "ed25519", "rsa", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi index bfd005d99fec9..e11203df3ab82 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi @@ -11,8 +11,6 @@ class DHPublicKey: ... class DHParameters: ... def generate_parameters(generator: int, key_size: int) -> dh.DHParameters: ... -def private_key_from_ptr(ptr: int) -> dh.DHPrivateKey: ... -def public_key_from_ptr(ptr: int) -> dh.DHPublicKey: ... def from_pem_parameters(data: bytes) -> dh.DHParameters: ... def from_der_parameters(data: bytes) -> dh.DHParameters: ... def from_private_numbers(numbers: dh.DHPrivateNumbers) -> dh.DHPrivateKey: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi index 5a56f256d52df..1a4a0062bed94 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi @@ -9,8 +9,6 @@ class DSAPublicKey: ... class DSAParameters: ... def generate_parameters(key_size: int) -> dsa.DSAParameters: ... -def private_key_from_ptr(ptr: int) -> dsa.DSAPrivateKey: ... -def public_key_from_ptr(ptr: int) -> dsa.DSAPublicKey: ... def from_private_numbers( numbers: dsa.DSAPrivateNumbers, ) -> dsa.DSAPrivateKey: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/ec.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/ec.pyi index f4fdf3856fc3a..d57d47923a0ce 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/ec.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/ec.pyi @@ -8,8 +8,6 @@ class ECPrivateKey: ... class ECPublicKey: ... def curve_supported(curve: ec.EllipticCurve) -> bool: ... -def private_key_from_ptr(ptr: int) -> ec.EllipticCurvePrivateKey: ... -def public_key_from_ptr(ptr: int) -> ec.EllipticCurvePublicKey: ... def generate_private_key( curve: ec.EllipticCurve, ) -> ec.EllipticCurvePrivateKey: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi index c7f127f0b157c..5233f9a1d1c8e 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi @@ -8,7 +8,5 @@ class Ed25519PrivateKey: ... class Ed25519PublicKey: ... def generate_key() -> ed25519.Ed25519PrivateKey: ... -def private_key_from_ptr(ptr: int) -> ed25519.Ed25519PrivateKey: ... -def public_key_from_ptr(ptr: int) -> ed25519.Ed25519PublicKey: ... def from_private_bytes(data: bytes) -> ed25519.Ed25519PrivateKey: ... def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi index 1cf5f1773a0bb..7a06520380a08 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi @@ -8,7 +8,5 @@ class Ed448PrivateKey: ... class Ed448PublicKey: ... def generate_key() -> ed448.Ed448PrivateKey: ... -def private_key_from_ptr(ptr: int) -> ed448.Ed448PrivateKey: ... -def public_key_from_ptr(ptr: int) -> ed448.Ed448PublicKey: ... def from_private_bytes(data: bytes) -> ed448.Ed448PrivateKey: ... def from_public_bytes(data: bytes) -> ed448.Ed448PublicKey: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/keys.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/keys.pyi new file mode 100644 index 0000000000000..931d3e9c369de --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/keys.pyi @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric.types import ( + PrivateKeyTypes, + PublicKeyTypes, +) + +def private_key_from_ptr( + ptr: int, + unsafe_skip_rsa_key_validation: bool, +) -> PrivateKeyTypes: ... +def public_key_from_ptr(ptr: int) -> PublicKeyTypes: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi index d42134f72c74c..d2abda9685434 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi @@ -11,11 +11,6 @@ def generate_private_key( public_exponent: int, key_size: int, ) -> rsa.RSAPrivateKey: ... -def private_key_from_ptr( - ptr: int, - unsafe_skip_rsa_key_validation: bool, -) -> rsa.RSAPrivateKey: ... -def public_key_from_ptr(ptr: int) -> rsa.RSAPublicKey: ... def from_private_numbers( numbers: rsa.RSAPrivateNumbers, unsafe_skip_rsa_key_validation: bool, diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi index 90f7cbdda950b..da0f3ec588b94 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi @@ -8,7 +8,5 @@ class X25519PrivateKey: ... class X25519PublicKey: ... def generate_key() -> x25519.X25519PrivateKey: ... -def private_key_from_ptr(ptr: int) -> x25519.X25519PrivateKey: ... -def public_key_from_ptr(ptr: int) -> x25519.X25519PublicKey: ... def from_private_bytes(data: bytes) -> x25519.X25519PrivateKey: ... def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi index d326c8d2d7c58..e51cfebe15f67 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi @@ -8,7 +8,5 @@ class X448PrivateKey: ... class X448PublicKey: ... def generate_key() -> x448.X448PrivateKey: ... -def private_key_from_ptr(ptr: int) -> x448.X448PrivateKey: ... -def public_key_from_ptr(ptr: int) -> x448.X448PublicKey: ... def from_private_bytes(data: bytes) -> x448.X448PrivateKey: ... def from_public_bytes(data: bytes) -> x448.X448PublicKey: ... diff --git a/src/rust/src/backend/dh.rs b/src/rust/src/backend/dh.rs index eb177cde44fe0..99e04ed76bfdf 100644 --- a/src/rust/src/backend/dh.rs +++ b/src/rust/src/backend/dh.rs @@ -7,17 +7,16 @@ use crate::backend::utils; use crate::error::{CryptographyError, CryptographyResult}; use crate::{types, x509}; use cryptography_x509::common; -use foreign_types_shared::ForeignTypeRef; const MIN_MODULUS_SIZE: u32 = 512; #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.dh")] -struct DHPrivateKey { +pub(crate) struct DHPrivateKey { pkey: openssl::pkey::PKey, } #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.dh")] -struct DHPublicKey { +pub(crate) struct DHPublicKey { pkey: openssl::pkey::PKey, } @@ -47,19 +46,17 @@ fn generate_parameters(generator: u32, key_size: u32) -> CryptographyResult DHPrivateKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> DHPrivateKey { DHPrivateKey { pkey: pkey.to_owned(), } } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> DHPublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> DHPublicKey { DHPublicKey { pkey: pkey.to_owned(), } @@ -390,8 +387,6 @@ impl DHParameters { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "dh")?; m.add_function(pyo3::wrap_pyfunction!(generate_parameters, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_der_parameters, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_pem_parameters, m)?)?; #[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] diff --git a/src/rust/src/backend/dsa.rs b/src/rust/src/backend/dsa.rs index fa4c9ae9d0ed3..ce39cbb058b4c 100644 --- a/src/rust/src/backend/dsa.rs +++ b/src/rust/src/backend/dsa.rs @@ -5,14 +5,13 @@ use crate::backend::utils; use crate::error::{CryptographyError, CryptographyResult}; use crate::{exceptions, types}; -use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass( frozen, module = "cryptography.hazmat.bindings._rust.openssl.dsa", name = "DSAPrivateKey" )] -struct DsaPrivateKey { +pub(crate) struct DsaPrivateKey { pkey: openssl::pkey::PKey, } @@ -21,7 +20,7 @@ struct DsaPrivateKey { module = "cryptography.hazmat.bindings._rust.openssl.dsa", name = "DSAPublicKey" )] -struct DsaPublicKey { +pub(crate) struct DsaPublicKey { pkey: openssl::pkey::PKey, } @@ -34,19 +33,17 @@ struct DsaParameters { dsa: openssl::dsa::Dsa, } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr(ptr: usize) -> DsaPrivateKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> DsaPrivateKey { DsaPrivateKey { pkey: pkey.to_owned(), } } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> DsaPublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> DsaPublicKey { DsaPublicKey { pkey: pkey.to_owned(), } @@ -293,8 +290,6 @@ impl DsaParameters { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "dsa")?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(generate_parameters, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_private_numbers, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_numbers, m)?)?; diff --git a/src/rust/src/backend/ec.rs b/src/rust/src/backend/ec.rs index 885a5cbf4dc28..276ae12a2b4db 100644 --- a/src/rust/src/backend/ec.rs +++ b/src/rust/src/backend/ec.rs @@ -5,18 +5,17 @@ use crate::backend::utils; use crate::error::{CryptographyError, CryptographyResult}; use crate::{exceptions, types}; -use foreign_types_shared::ForeignTypeRef; use pyo3::ToPyObject; #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ec")] -struct ECPrivateKey { +pub(crate) struct ECPrivateKey { pkey: openssl::pkey::PKey, #[pyo3(get)] curve: pyo3::Py, } #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ec")] -struct ECPublicKey { +pub(crate) struct ECPublicKey { pkey: openssl::pkey::PKey, #[pyo3(get)] curve: pyo3::Py, @@ -121,10 +120,10 @@ fn curve_supported(py: pyo3::Python<'_>, py_curve: &pyo3::PyAny) -> bool { curve_from_py_curve(py, py_curve).is_ok() } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr(py: pyo3::Python<'_>, ptr: usize) -> CryptographyResult { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + py: pyo3::Python<'_>, + pkey: &openssl::pkey::PKeyRef, +) -> CryptographyResult { let curve = py_curve_from_curve(py, pkey.ec_key().unwrap().group())?; check_key_infinity(&pkey.ec_key().unwrap())?; Ok(ECPrivateKey { @@ -133,10 +132,10 @@ fn private_key_from_ptr(py: pyo3::Python<'_>, ptr: usize) -> CryptographyResult< }) } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(py: pyo3::Python<'_>, ptr: usize) -> CryptographyResult { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + py: pyo3::Python<'_>, + pkey: &openssl::pkey::PKeyRef, +) -> CryptographyResult { let ec = pkey.ec_key().map_err(|e| { pyo3::exceptions::PyValueError::new_err(format!("Unable to load EC key: {}", e)) })?; @@ -505,8 +504,6 @@ impl ECPublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "ec")?; m.add_function(pyo3::wrap_pyfunction!(curve_supported, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(generate_private_key, m)?)?; m.add_function(pyo3::wrap_pyfunction!(derive_private_key, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs index 93ea3f6e8a873..f68da83bfb478 100644 --- a/src/rust/src/backend/ed25519.rs +++ b/src/rust/src/backend/ed25519.rs @@ -6,15 +6,14 @@ use crate::backend::utils; use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; -use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ed25519")] -struct Ed25519PrivateKey { +pub(crate) struct Ed25519PrivateKey { pkey: openssl::pkey::PKey, } #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ed25519")] -struct Ed25519PublicKey { +pub(crate) struct Ed25519PublicKey { pkey: openssl::pkey::PKey, } @@ -25,19 +24,17 @@ fn generate_key() -> CryptographyResult { }) } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr(ptr: usize) -> Ed25519PrivateKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> Ed25519PrivateKey { Ed25519PrivateKey { pkey: pkey.to_owned(), } } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> Ed25519PublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> Ed25519PublicKey { Ed25519PublicKey { pkey: pkey.to_owned(), } @@ -164,8 +161,6 @@ impl Ed25519PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "ed25519")?; m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs index 9950cf4b19c50..eeed28e92f6e5 100644 --- a/src/rust/src/backend/ed448.rs +++ b/src/rust/src/backend/ed448.rs @@ -6,15 +6,14 @@ use crate::backend::utils; use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; -use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ed448")] -struct Ed448PrivateKey { +pub(crate) struct Ed448PrivateKey { pkey: openssl::pkey::PKey, } #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ed448")] -struct Ed448PublicKey { +pub(crate) struct Ed448PublicKey { pkey: openssl::pkey::PKey, } @@ -25,19 +24,17 @@ fn generate_key() -> CryptographyResult { }) } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr(ptr: usize) -> Ed448PrivateKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> Ed448PrivateKey { Ed448PrivateKey { pkey: pkey.to_owned(), } } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> Ed448PublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> Ed448PublicKey { Ed448PublicKey { pkey: pkey.to_owned(), } @@ -161,8 +158,6 @@ impl Ed448PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "ed448")?; m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; diff --git a/src/rust/src/backend/keys.rs b/src/rust/src/backend/keys.rs new file mode 100644 index 0000000000000..398e911e88241 --- /dev/null +++ b/src/rust/src/backend/keys.rs @@ -0,0 +1,119 @@ +// This file is dual licensed under the terms of the Apache License, Version +// 2.0, and the BSD License. See the LICENSE file in the root of this repository +// for complete details. + +use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; +use foreign_types_shared::ForeignTypeRef; +use pyo3::IntoPy; + +#[pyo3::prelude::pyfunction] +fn private_key_from_ptr( + py: pyo3::Python<'_>, + ptr: usize, + unsafe_skip_rsa_key_validation: bool, +) -> CryptographyResult { + // SAFETY: Caller is responsible for passing a valid pointer. + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + match pkey.id() { + openssl::pkey::Id::RSA => Ok(crate::backend::rsa::private_key_from_pkey( + pkey, + unsafe_skip_rsa_key_validation, + )? + .into_py(py)), + openssl::pkey::Id::RSA_PSS => { + // At the moment the way we handle RSA PSS keys is to strip the + // PSS constraints from them and treat them as normal RSA keys + // Unfortunately the RSA * itself tracks this data so we need to + // extract, serialize, and reload it without the constraints. + let der_bytes = pkey.rsa()?.private_key_to_der()?; + let rsa = openssl::rsa::Rsa::private_key_from_der(&der_bytes)?; + let pkey = openssl::pkey::PKey::from_rsa(rsa)?; + Ok( + crate::backend::rsa::private_key_from_pkey(&pkey, unsafe_skip_rsa_key_validation)? + .into_py(py), + ) + } + openssl::pkey::Id::EC => { + Ok(crate::backend::ec::private_key_from_pkey(py, pkey)?.into_py(py)) + } + openssl::pkey::Id::X25519 => { + Ok(crate::backend::x25519::private_key_from_pkey(pkey).into_py(py)) + } + + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + openssl::pkey::Id::X448 => { + Ok(crate::backend::x448::private_key_from_pkey(pkey).into_py(py)) + } + + openssl::pkey::Id::ED25519 => { + Ok(crate::backend::ed25519::private_key_from_pkey(pkey).into_py(py)) + } + + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + openssl::pkey::Id::ED448 => { + Ok(crate::backend::ed448::private_key_from_pkey(pkey).into_py(py)) + } + openssl::pkey::Id::DSA => Ok(crate::backend::dsa::private_key_from_pkey(pkey).into_py(py)), + openssl::pkey::Id::DH => Ok(crate::backend::dh::private_key_from_pkey(pkey).into_py(py)), + + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + openssl::pkey::Id::DHX => Ok(crate::backend::dh::private_key_from_pkey(pkey).into_py(py)), + _ => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err("Unsupported key type."), + )), + } +} + +#[pyo3::prelude::pyfunction] +fn public_key_from_ptr(py: pyo3::Python<'_>, ptr: usize) -> CryptographyResult { + // SAFETY: Caller is responsible for passing a valid pointer. + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + match pkey.id() { + openssl::pkey::Id::RSA => Ok(crate::backend::rsa::public_key_from_pkey(pkey).into_py(py)), + openssl::pkey::Id::RSA_PSS => { + // At the moment the way we handle RSA PSS keys is to strip the + // PSS constraints from them and treat them as normal RSA keys + // Unfortunately the RSA * itself tracks this data so we need to + // extract, serialize, and reload it without the constraints. + let der_bytes = pkey.rsa()?.public_key_to_der()?; + let rsa = openssl::rsa::Rsa::public_key_from_der(&der_bytes)?; + let pkey = openssl::pkey::PKey::from_rsa(rsa)?; + Ok(crate::backend::rsa::public_key_from_pkey(&pkey).into_py(py)) + } + openssl::pkey::Id::EC => { + Ok(crate::backend::ec::public_key_from_pkey(py, pkey)?.into_py(py)) + } + openssl::pkey::Id::X25519 => { + Ok(crate::backend::x25519::public_key_from_pkey(pkey).into_py(py)) + } + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + openssl::pkey::Id::X448 => Ok(crate::backend::x448::public_key_from_pkey(pkey).into_py(py)), + + openssl::pkey::Id::ED25519 => { + Ok(crate::backend::ed25519::public_key_from_pkey(pkey).into_py(py)) + } + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + openssl::pkey::Id::ED448 => { + Ok(crate::backend::ed448::public_key_from_pkey(pkey).into_py(py)) + } + + openssl::pkey::Id::DSA => Ok(crate::backend::dsa::public_key_from_pkey(pkey).into_py(py)), + openssl::pkey::Id::DH => Ok(crate::backend::dh::public_key_from_pkey(pkey).into_py(py)), + + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + openssl::pkey::Id::DHX => Ok(crate::backend::dh::public_key_from_pkey(pkey).into_py(py)), + + _ => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err("Unsupported key type."), + )), + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "keys")?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index 99de91f948011..7e085d623b40f 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -14,6 +14,7 @@ pub(crate) mod ed448; pub(crate) mod hashes; pub(crate) mod hmac; pub(crate) mod kdf; +pub(crate) mod keys; pub(crate) mod poly1305; pub(crate) mod rsa; pub(crate) mod utils; @@ -27,6 +28,7 @@ pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult< module.add_submodule(dh::create_module(module.py())?)?; module.add_submodule(dsa::create_module(module.py())?)?; module.add_submodule(ec::create_module(module.py())?)?; + module.add_submodule(keys::create_module(module.py())?)?; module.add_submodule(ed25519::create_module(module.py())?)?; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] diff --git a/src/rust/src/backend/rsa.rs b/src/rust/src/backend/rsa.rs index 86168e3b8d8fc..3398b0ca377d2 100644 --- a/src/rust/src/backend/rsa.rs +++ b/src/rust/src/backend/rsa.rs @@ -5,14 +5,13 @@ use crate::backend::{hashes, utils}; use crate::error::{CryptographyError, CryptographyResult}; use crate::{exceptions, types}; -use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass( frozen, module = "cryptography.hazmat.bindings._rust.openssl.rsa", name = "RSAPrivateKey" )] -struct RsaPrivateKey { +pub(crate) struct RsaPrivateKey { pkey: openssl::pkey::PKey, } @@ -21,7 +20,7 @@ struct RsaPrivateKey { module = "cryptography.hazmat.bindings._rust.openssl.rsa", name = "RSAPublicKey" )] -struct RsaPublicKey { +pub(crate) struct RsaPublicKey { pkey: openssl::pkey::PKey, } @@ -37,13 +36,10 @@ fn check_rsa_private_key( Ok(()) } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr( - ptr: usize, +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, unsafe_skip_rsa_key_validation: bool, ) -> CryptographyResult { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; if !unsafe_skip_rsa_key_validation { check_rsa_private_key(&pkey.rsa().unwrap())?; } @@ -52,10 +48,9 @@ fn private_key_from_ptr( }) } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> RsaPublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> RsaPublicKey { RsaPublicKey { pkey: pkey.to_owned(), } @@ -568,8 +563,6 @@ impl RsaPublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "rsa")?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(generate_private_key, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_private_numbers, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_numbers, m)?)?; diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 8c9c93f066f64..076bfe87d96bb 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -5,15 +5,14 @@ use crate::backend::utils; use crate::buf::CffiBuf; use crate::error::CryptographyResult; -use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.x25519")] -struct X25519PrivateKey { +pub(crate) struct X25519PrivateKey { pkey: openssl::pkey::PKey, } #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.x25519")] -struct X25519PublicKey { +pub(crate) struct X25519PublicKey { pkey: openssl::pkey::PKey, } @@ -24,19 +23,17 @@ fn generate_key() -> CryptographyResult { }) } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr(ptr: usize) -> X25519PrivateKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> X25519PrivateKey { X25519PrivateKey { pkey: pkey.to_owned(), } } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> X25519PublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> X25519PublicKey { X25519PublicKey { pkey: pkey.to_owned(), } @@ -152,8 +149,6 @@ impl X25519PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "x25519")?; m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs index c466c337b2224..eb4718f5f1004 100644 --- a/src/rust/src/backend/x448.rs +++ b/src/rust/src/backend/x448.rs @@ -5,15 +5,14 @@ use crate::backend::utils; use crate::buf::CffiBuf; use crate::error::CryptographyResult; -use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.x448")] -struct X448PrivateKey { +pub(crate) struct X448PrivateKey { pkey: openssl::pkey::PKey, } #[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.x448")] -struct X448PublicKey { +pub(crate) struct X448PublicKey { pkey: openssl::pkey::PKey, } @@ -24,19 +23,17 @@ fn generate_key() -> CryptographyResult { }) } -#[pyo3::prelude::pyfunction] -fn private_key_from_ptr(ptr: usize) -> X448PrivateKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn private_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> X448PrivateKey { X448PrivateKey { pkey: pkey.to_owned(), } } -#[pyo3::prelude::pyfunction] -fn public_key_from_ptr(ptr: usize) -> X448PublicKey { - // SAFETY: Caller is responsible for passing a valid pointer. - let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; +pub(crate) fn public_key_from_pkey( + pkey: &openssl::pkey::PKeyRef, +) -> X448PublicKey { X448PublicKey { pkey: pkey.to_owned(), } @@ -151,8 +148,6 @@ impl X448PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "x448")?; m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; - m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 7d8a1fd05507c..c8d81f8de3409 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -291,8 +291,7 @@ def test_load_pss_keys_strips_constraints(self, path, backend): @pytest.mark.supported( only_if=lambda backend: ( - not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - and not backend._lib.CRYPTOGRAPHY_IS_BORINGSSL + not backend._lib.CRYPTOGRAPHY_IS_BORINGSSL and not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E ), skip_message="Does not support RSA PSS loading", @@ -315,8 +314,7 @@ def test_load_pss_pub_keys_strips_constraints(self, backend): @pytest.mark.supported( only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - or backend._lib.CRYPTOGRAPHY_IS_BORINGSSL + backend._lib.CRYPTOGRAPHY_IS_BORINGSSL or backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E ), skip_message="Test requires a backend without RSA-PSS key support",