Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions src/_cffi_src/openssl/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
"""

TYPES = """
static const long Cryptography_HAS_MEM_FUNCTIONS;

static const int OPENSSL_VERSION;
static const int OPENSSL_CFLAGS;
static const int OPENSSL_BUILT_ON;
Expand All @@ -26,50 +24,7 @@

void *OPENSSL_malloc(size_t);
void OPENSSL_free(void *);


/* Signature is significantly different in LibreSSL, so expose via different
symbol name */
int Cryptography_CRYPTO_set_mem_functions(
void *(*)(size_t, const char *, int),
void *(*)(void *, size_t, const char *, int),
void (*)(void *, const char *, int));

void *Cryptography_malloc_wrapper(size_t, const char *, int);
void *Cryptography_realloc_wrapper(void *, size_t, const char *, int);
void Cryptography_free_wrapper(void *, const char *, int);
"""

CUSTOMIZATIONS = """
#if CRYPTOGRAPHY_IS_LIBRESSL || CRYPTOGRAPHY_IS_BORINGSSL
static const long Cryptography_HAS_MEM_FUNCTIONS = 0;
int (*Cryptography_CRYPTO_set_mem_functions)(
void *(*)(size_t, const char *, int),
void *(*)(void *, size_t, const char *, int),
void (*)(void *, const char *, int)) = NULL;

#else
static const long Cryptography_HAS_MEM_FUNCTIONS = 1;

int Cryptography_CRYPTO_set_mem_functions(
void *(*m)(size_t, const char *, int),
void *(*r)(void *, size_t, const char *, int),
void (*f)(void *, const char *, int)
) {
return CRYPTO_set_mem_functions(m, r, f);
}
#endif

void *Cryptography_malloc_wrapper(size_t size, const char *path, int line) {
return malloc(size);
}

void *Cryptography_realloc_wrapper(void *ptr, size_t size, const char *path,
int line) {
return realloc(ptr, size);
}

void Cryptography_free_wrapper(void *ptr, const char *path, int line) {
free(ptr);
}
"""
4 changes: 2 additions & 2 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def __repr__(self) -> str:
return "<OpenSSLBackend(version: {}, FIPS: {}, Legacy: {})>".format(
self.openssl_version_text(),
self._fips_enabled,
self._binding._legacy_provider_loaded,
rust_openssl._legacy_provider_loaded,
)

def openssl_assert(
Expand Down Expand Up @@ -277,7 +277,7 @@ def _register_default_ciphers(self) -> None:
# we get an EVP_CIPHER * in the _CipherContext __init__, but OpenSSL 3
# will return a valid pointer even though the cipher is unavailable.
if (
self._binding._legacy_provider_loaded
rust_openssl._legacy_provider_loaded
or not self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER
):
for mode_cls in [CBC, CFB, OFB, ECB]:
Expand Down
2 changes: 2 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ __all__ = [
"x25519",
]

_legacy_provider_loaded: bool

def openssl_version() -> int: ...
def raise_openssl_error() -> typing.NoReturn: ...
def capture_error_stack() -> list[OpenSSLError]: ...
Expand Down
7 changes: 0 additions & 7 deletions src/cryptography/hazmat/bindings/openssl/_conditional.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ def cryptography_has_tls_st() -> list[str]:
]


def cryptography_has_mem_functions() -> list[str]:
return [
"Cryptography_CRYPTO_set_mem_functions",
]


def cryptography_has_ed448() -> list[str]:
return [
"EVP_PKEY_ED448",
Expand Down Expand Up @@ -202,7 +196,6 @@ def cryptography_has_get_extms_support() -> list[str]:
"Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb,
"Cryptography_HAS_SSL_ST": cryptography_has_ssl_st,
"Cryptography_HAS_TLS_ST": cryptography_has_tls_st,
"Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions,
"Cryptography_HAS_ED448": cryptography_has_ed448,
"Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs,
"Cryptography_HAS_PSK": cryptography_has_psk,
Expand Down
31 changes: 0 additions & 31 deletions src/cryptography/hazmat/bindings/openssl/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,6 @@ def _openssl_assert(
)


def _legacy_provider_error(loaded: bool) -> None:
if not loaded:
raise RuntimeError(
"OpenSSL 3.0's legacy provider failed to load. This is a fatal "
"error by default, but cryptography supports running without "
"legacy algorithms by setting the environment variable "
"CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error,"
" you have likely made a mistake with your OpenSSL configuration."
)


def build_conditional_library(
lib: typing.Any,
conditional_names: dict[str, typing.Callable[[], list[str]]],
Expand Down Expand Up @@ -76,7 +65,6 @@ class Binding:
_lib_loaded = False
_init_lock = threading.Lock()
_legacy_provider: typing.Any = ffi.NULL
_legacy_provider_loaded = False
_default_provider: typing.Any = ffi.NULL

def __init__(self) -> None:
Expand Down Expand Up @@ -106,25 +94,6 @@ def _ensure_ffi_initialized(cls) -> None:
_openssl.lib, CONDITIONAL_NAMES
)
cls._lib_loaded = True
# As of OpenSSL 3.0.0 we must register a legacy cipher provider
# to get RC2 (needed for junk asymmetric private key
# serialization), RC4, Blowfish, IDEA, SEED, etc. These things
# are ugly legacy, but we aren't going to get rid of them
# any time soon.
if cls.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER:
if not os.environ.get("CRYPTOGRAPHY_OPENSSL_NO_LEGACY"):
cls._legacy_provider = cls.lib.OSSL_PROVIDER_load(
cls.ffi.NULL, b"legacy"
)
cls._legacy_provider_loaded = (
cls._legacy_provider != cls.ffi.NULL
)
_legacy_provider_error(cls._legacy_provider_loaded)

cls._default_provider = cls.lib.OSSL_PROVIDER_load(
cls.ffi.NULL, b"default"
)
_openssl_assert(cls._default_provider != cls.ffi.NULL)

@classmethod
def init_static_locks(cls) -> None:
Expand Down
65 changes: 65 additions & 0 deletions src/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

#![deny(rust_2018_idioms, clippy::undocumented_unsafe_blocks)]

use crate::error::CryptographyResult;
#[cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)]
use openssl::provider;
use std::env;

mod asn1;
mod backend;
mod buf;
Expand All @@ -15,6 +20,12 @@ mod pkcs7;
pub(crate) mod types;
mod x509;

#[cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)]
#[pyo3::prelude::pyclass(frozen, module = "cryptography.hazmat.bindings._rust")]
struct LoadedProviders {
legacy: Option<provider::Provider>,
}

#[pyo3::prelude::pyfunction]
fn openssl_version() -> i64 {
openssl::version::number()
Expand All @@ -25,6 +36,35 @@ fn is_fips_enabled() -> bool {
cryptography_openssl::fips::is_enabled()
}

#[cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)]
fn _initialize_legacy_provider() -> CryptographyResult<LoadedProviders> {
// As of OpenSSL 3.0.0 we must register a legacy cipher provider
// to get RC2 (needed for junk asymmetric private key
// serialization), RC4, Blowfish, IDEA, SEED, etc. These things
// are ugly legacy, but we aren't going to get rid of them
// any time soon.
let load_legacy = env::var("CRYPTOGRAPHY_OPENSSL_NO_LEGACY")
.map(|v| v.is_empty() || v == "0")
.unwrap_or(true);
let legacy = if load_legacy {
let legacy_result = provider::Provider::try_load(None, "legacy", true);
_legacy_provider_error(legacy_result.is_ok())?;
Some(legacy_result?)
} else {
None
};
Ok(LoadedProviders { legacy })
}

fn _legacy_provider_error(success: bool) -> pyo3::PyResult<()> {
if !success {
return Err(pyo3::exceptions::PyRuntimeError::new_err(
"OpenSSL 3.0's legacy provider failed to load. This is a fatal error by default, but cryptography supports running without legacy algorithms by setting the environment variable CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error, you have likely made a mistake with your OpenSSL configuration."
));
}
Ok(())
}

#[pyo3::prelude::pymodule]
fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> {
m.add_function(pyo3::wrap_pyfunction!(padding::check_pkcs7_padding, m)?)?;
Expand Down Expand Up @@ -52,6 +92,20 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()>
m.add_submodule(cryptography_cffi::create_module(py)?)?;

let openssl_mod = pyo3::prelude::PyModule::new(py, "openssl")?;
cfg_if::cfg_if! {
if #[cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)] {
let providers = _initialize_legacy_provider()?;
if providers.legacy.is_some() {
openssl_mod.add("_legacy_provider_loaded", true)?;
openssl_mod.add("_providers", providers)?;
} else {
openssl_mod.add("_legacy_provider_loaded", false)?;
}
} else {
// default value for non-openssl 3+
openssl_mod.add("_legacy_provider_loaded", false)?;
}
}
openssl_mod.add_function(pyo3::wrap_pyfunction!(openssl_version, m)?)?;
openssl_mod.add_function(pyo3::wrap_pyfunction!(error::raise_openssl_error, m)?)?;
openssl_mod.add_function(pyo3::wrap_pyfunction!(error::capture_error_stack, m)?)?;
Expand All @@ -62,3 +116,14 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()>

Ok(())
}

#[cfg(test)]
mod tests {
use super::_legacy_provider_error;

#[test]
fn test_legacy_provider_error() {
assert!(_legacy_provider_error(true).is_ok());
assert!(_legacy_provider_error(false).is_err());
}
}
Loading