drop support for openssl < 1.1.1d (#8449)

This removes the OS random engine, which contained the only CPython PSF
licensed code in the repository. Accordingly, that license has now been
removed.
This commit is contained in:
Paul Kehrer 2023-03-24 20:36:58 +08:00 committed by GitHub
parent 4c24dd05eb
commit 5e6476a4c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 20 additions and 1194 deletions

View file

@ -136,7 +136,6 @@ jobs:
- {IMAGE: "bullseye", TOXENV: "py39", RUNNER: "ubuntu-latest"}
- {IMAGE: "bookworm", TOXENV: "py311", RUNNER: "ubuntu-latest"}
- {IMAGE: "sid", TOXENV: "py311", RUNNER: "ubuntu-latest"}
- {IMAGE: "ubuntu-bionic", TOXENV: "py36", RUNNER: "ubuntu-latest"}
- {IMAGE: "ubuntu-focal", TOXENV: "py38", RUNNER: "ubuntu-latest"}
- {IMAGE: "ubuntu-jammy", TOXENV: "py310", RUNNER: "ubuntu-latest"}
- {IMAGE: "ubuntu-rolling", TOXENV: "py310", RUNNER: "ubuntu-latest"}
@ -182,7 +181,6 @@ jobs:
run: mkdir -p "${HOME}/.cache/pip"
- run: |
echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV
echo "CFLAGS=-DUSE_OSRANDOM_RNG_FOR_TESTING" >> $GITHUB_ENV
if: matrix.IMAGE.FIPS
- run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage
- run: '/venv/bin/tox -vvv --notest'
@ -373,11 +371,11 @@ jobs:
- {OS: 'macos-12', ARCH: 'x86_64'}
- {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'}
PYTHON:
- {VERSION: "3.6", TOXENV: "py36-nocoverage", EXTRA_CFLAGS: ""}
- {VERSION: "3.11", TOXENV: "py311", EXTRA_CFLAGS: "-DUSE_OSRANDOM_RNG_FOR_TESTING"}
- {VERSION: "3.6", TOXENV: "py36-nocoverage"}
- {VERSION: "3.11", TOXENV: "py311"}
exclude:
# We only test latest Python on arm64. The py36 won't work since there's no universal2 binary
- PYTHON: {VERSION: "3.6", TOXENV: "py36-nocoverage", EXTRA_CFLAGS: ""}
- PYTHON: {VERSION: "3.6", TOXENV: "py36-nocoverage"}
RUNNER: {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'}
name: "${{ matrix.PYTHON.TOXENV }} on macOS ${{ matrix.RUNNER.ARCH }}"
timeout-minutes: 15
@ -420,11 +418,10 @@ jobs:
run: |
OPENSSL_DIR=$(readlink -f ../openssl-macos-universal2/) \
OPENSSL_STATIC=1 \
CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -mmacosx-version-min=10.12 $EXTRA_CFLAGS" \
CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -mmacosx-version-min=10.12" \
tox -vvv --notest
env:
TOXENV: ${{ matrix.PYTHON.TOXENV }}
EXTRA_CFLAGS: ${{ matrix.PYTHON.EXTRA_CFLAGS }}
CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }}
- name: Tests
run: tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof
@ -443,8 +440,8 @@ jobs:
- {ARCH: 'x86', WINDOWS: 'win32'}
- {ARCH: 'x64', WINDOWS: 'win64'}
PYTHON:
- {VERSION: "3.6", TOXENV: "py36-nocoverage", CL_FLAGS: ""}
- {VERSION: "3.11", TOXENV: "py311", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"}
- {VERSION: "3.6", TOXENV: "py36-nocoverage"}
- {VERSION: "3.11", TOXENV: "py311"}
JOB_NUMBER: [0, 1]
name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})"
timeout-minutes: 15
@ -481,7 +478,6 @@ jobs:
- name: Configure
run: |
echo "OPENSSL_DIR=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}" >> $GITHUB_ENV
echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV
shell: bash
- name: Clone wycheproof

View file

@ -8,6 +8,9 @@ Changelog
.. note:: This version is not yet released and is under active development.
* **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been
removed. Users on older version of OpenSSL will need to upgrade.
.. _v40-0-0:
40.0.0 - 2023-03-24

View file

@ -1,6 +1,3 @@
This software is made available under the terms of *either* of the licenses
found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
under the terms of *both* these licenses.
The code used in the OS random engine is derived from CPython, and is licensed
under the terms of the PSF License Agreement.

View file

@ -1,41 +0,0 @@
1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
the Individual or Organization ("Licensee") accessing and otherwise using Python
2.7.12 software in source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python 2.7.12 alone or in any derivative
version, provided, however, that PSF's License Agreement and PSF's notice of
copyright, i.e., "Copyright © 2001-2016 Python Software Foundation; All Rights
Reserved" are retained in Python 2.7.12 alone or in any derivative version
prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates Python 2.7.12 or any part thereof, and wants to make the
derivative work available to others as provided herein, then Licensee hereby
agrees to include in any such work a brief summary of the changes made to Python
2.7.12.
4. PSF is making Python 2.7.12 available to Licensee on an "AS IS" basis.
PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
USE OF PYTHON 2.7.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.12
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.12, OR ANY DERIVATIVE
THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach of
its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between PSF and Licensee. This License
Agreement does not grant permission to use PSF trademarks or trade name in a
trademark sense to endorse or promote products or services of Licensee, or any
third party.
8. By copying, installing or otherwise using Python 2.7.12, Licensee agrees
to be bound by the terms and conditions of this License Agreement.

View file

@ -3,7 +3,6 @@ include CONTRIBUTING.rst
include LICENSE
include LICENSE.APACHE
include LICENSE.BSD
include LICENSE.PSF
include README.rst
include tox.ini

View file

@ -10,8 +10,8 @@ A list of supported versions can be found in our :doc:`/installation`
documentation.
In general the backend should be considered an internal implementation detail
of the project, but there are some public methods available for more advanced
control.
of the project, but there are some public methods available for debugging
purposes.
.. data:: cryptography.hazmat.backends.openssl.backend
@ -29,21 +29,6 @@ control.
typically shown in hexadecimal (e.g. ``0x1010003f``). This is
not necessarily the same version as it was compiled against.
.. method:: activate_osrandom_engine()
Activates the OS random engine. This will effectively disable OpenSSL's
default CSPRNG.
.. method:: osrandom_engine_implementation()
.. versionadded:: 1.7
Returns the implementation of OS random engine.
.. method:: activate_builtin_random()
This will activate the default OpenSSL CSPRNG.
.. _legacy-provider:
Legacy provider in OpenSSL 3.x
@ -56,68 +41,5 @@ disable the legacy provider in OpenSSL 3.x. This will disable legacy
cryptographic algorithms, including ``Blowfish``, ``CAST5``, ``SEED``,
``ARC4``, and ``RC2`` (which is used by some encrypted serialization formats).
OS random engine
----------------
.. note::
As of OpenSSL 1.1.1d its CSPRNG is fork-safe by default.
``cryptography`` does not compile or load the custom engine on
>= 1.1.1d.
By default OpenSSL uses a user-space CSPRNG that is seeded from system random (
``/dev/urandom`` or ``CryptGenRandom``). This CSPRNG is not reseeded
automatically when a process calls ``fork()``. This can result in situations
where two different processes can return similar or identical keys and
compromise the security of the system.
The approach this project has chosen to mitigate this vulnerability is to
include an engine that replaces the OpenSSL default CSPRNG with one that
sources its entropy from ``/dev/urandom`` on UNIX-like operating systems and
uses ``CryptGenRandom`` on Windows. This method of pulling from the system pool
allows us to avoid potential issues with `initializing the RNG`_ as well as
protecting us from the ``fork()`` weakness.
This engine is **active** by default when importing the OpenSSL backend. When
active this engine will be used to generate all the random data OpenSSL
requests.
When importing only the binding it is added to the engine list but
**not activated**.
OS random sources
-----------------
On macOS and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random``. The
implementation on macOS uses the `Yarrow`_ algorithm. FreeBSD uses the
`Fortuna`_ algorithm.
On Windows the implementation of ``CryptGenRandom`` depends on which version of
the operation system you are using. See the `Microsoft documentation`_ for more
details.
Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source
seeded from the same pool as ``/dev/random``.
+------------------------------------------+------------------------------+
| Windows | ``CryptGenRandom()`` |
+------------------------------------------+------------------------------+
| Linux >= 3.17 with working | ``getrandom()`` |
| ``SYS_getrandom`` syscall | |
+------------------------------------------+------------------------------+
| OpenBSD >= 5.6 | ``getentropy()`` |
+------------------------------------------+------------------------------+
| BSD family (including macOS 10.12+) with | ``getentropy()`` |
| ``SYS_getentropy`` in ``sys/syscall.h`` | |
+------------------------------------------+------------------------------+
| fallback | ``/dev/urandom`` with |
| | cached file descriptor |
+------------------------------------------+------------------------------+
.. _`OpenSSL`: https://www.openssl.org/
.. _`initializing the RNG`: https://en.wikipedia.org/wiki/OpenSSL#Predictable_private_keys_.28Debian-specific.29
.. _`Fortuna`: https://en.wikipedia.org/wiki/Fortuna_(PRNG)
.. _`Yarrow`: https://en.wikipedia.org/wiki/Yarrow_algorithm
.. _`Microsoft documentation`: https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenrandom

View file

@ -4,7 +4,7 @@ version = attr: cryptography.__version__
description = cryptography is a package which provides cryptographic recipes and primitives to Python developers.
long_description = file: README.rst
long_description_content_type = text/x-rst
license = (Apache-2.0 OR BSD-3-Clause) AND PSF-2.0
license = Apache-2.0 OR BSD-3-Clause
url = https://github.com/pyca/cryptography
author = The Python Cryptographic Authority and individual contributors
author_email = cryptography-dev@python.org

View file

@ -100,7 +100,6 @@ ffi = build_ffi_for_binding(
"nid",
"objects",
"opensslv",
"osrandom_engine",
"pem",
"pkcs12",
"rand",

View file

@ -52,40 +52,25 @@ INCLUDES = """
#define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370 (0)
#endif
#if OPENSSL_VERSION_NUMBER < 0x10101000
#error "pyca/cryptography MUST be linked with Openssl 1.1.1 or later"
#if OPENSSL_VERSION_NUMBER < 0x10101040
#error "pyca/cryptography MUST be linked with Openssl 1.1.1d or later"
#endif
#define CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER \
(OPENSSL_VERSION_NUMBER >= 0x10101040 && !CRYPTOGRAPHY_IS_LIBRESSL)
#define CRYPTOGRAPHY_OPENSSL_300_OR_GREATER \
(OPENSSL_VERSION_NUMBER >= 0x30000000 && !CRYPTOGRAPHY_IS_LIBRESSL)
#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B \
(OPENSSL_VERSION_NUMBER < 0x10101020 || CRYPTOGRAPHY_IS_LIBRESSL)
#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111D \
(OPENSSL_VERSION_NUMBER < 0x10101040 || CRYPTOGRAPHY_IS_LIBRESSL)
#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E \
(OPENSSL_VERSION_NUMBER < 0x10101050 || CRYPTOGRAPHY_IS_LIBRESSL)
#if (CRYPTOGRAPHY_OPENSSL_LESS_THAN_111D && !CRYPTOGRAPHY_IS_LIBRESSL && \
!defined(OPENSSL_NO_ENGINE)) || defined(USE_OSRANDOM_RNG_FOR_TESTING)
#define CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE 1
#else
#define CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE 0
#endif
/* Ed25519 support is available from OpenSSL 1.1.1b and LibreSSL 3.7.0. */
/* Ed25519 support is in all supported OpenSSLs as well as LibreSSL 3.7.0. */
#define CRYPTOGRAPHY_HAS_WORKING_ED25519 \
(!CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B || \
(!CRYPTOGRAPHY_IS_LIBRESSL || \
(CRYPTOGRAPHY_IS_LIBRESSL && !CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370))
"""
TYPES = """
static const int CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER;
static const int CRYPTOGRAPHY_OPENSSL_300_OR_GREATER;
static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B;
static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E;
static const int CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE;
static const int CRYPTOGRAPHY_HAS_WORKING_ED25519;
static const int CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370;

View file

@ -49,7 +49,7 @@ CUSTOMIZATIONS = """
#define ERR_LIB_PROV 0
#endif
#if !CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER || CRYPTOGRAPHY_IS_BORINGSSL
#ifndef EVP_R_XTS_DUPLICATED_KEYS
static const int EVP_R_XTS_DUPLICATED_KEYS = 0;
#endif

View file

@ -1,23 +0,0 @@
# 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.
import os
HERE = os.path.dirname(os.path.abspath(__file__))
with open(os.path.join(HERE, "src/osrandom_engine.h")) as f:
INCLUDES = f.read()
TYPES = """
static const char *const Cryptography_osrandom_engine_name;
static const char *const Cryptography_osrandom_engine_id;
"""
FUNCTIONS = """
int Cryptography_add_osrandom_engine(void);
"""
with open(os.path.join(HERE, "src/osrandom_engine.c")) as f:
CUSTOMIZATIONS = f.read()

View file

@ -1,627 +0,0 @@
/* osurandom engine
*
* Windows CryptGenRandom()
* macOS >= 10.12 getentropy()
* OpenBSD 5.6+ getentropy()
* other BSD getentropy() if SYS_getentropy is defined
* Linux 3.17+ getrandom() with fallback to /dev/urandom
* other /dev/urandom with cached fd
*
* The /dev/urandom, getrandom and getentropy code is derived from Python's
* Python/random.c, written by Antoine Pitrou and Victor Stinner.
*
* Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
*/
#ifdef __linux__
#include <poll.h>
#endif
#if CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE
/* OpenSSL has ENGINE support and is older than 1.1.1d (the first version that
* properly implements fork safety in its RNG) so build the engine. */
static const char *Cryptography_osrandom_engine_id = "osrandom";
/****************************************************************************
* Windows
*/
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
static const char *Cryptography_osrandom_engine_name = "osrandom_engine CryptGenRandom()";
static HCRYPTPROV hCryptProv = 0;
static int osrandom_init(ENGINE *e) {
if (hCryptProv != 0) {
return 1;
}
if (CryptAcquireContext(&hCryptProv, NULL, NULL,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
return 1;
} else {
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_INIT,
CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT,
__FILE__, __LINE__
);
return 0;
}
}
static int osrandom_rand_bytes(unsigned char *buffer, int size) {
if (hCryptProv == 0) {
return 0;
}
if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM,
__FILE__, __LINE__
);
return 0;
}
return 1;
}
static int osrandom_finish(ENGINE *e) {
if (CryptReleaseContext(hCryptProv, 0)) {
hCryptProv = 0;
return 1;
} else {
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_FINISH,
CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT,
__FILE__, __LINE__
);
return 0;
}
}
static int osrandom_rand_status(void) {
return hCryptProv != 0;
}
static const char *osurandom_get_implementation(void) {
return "CryptGenRandom";
}
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */
/****************************************************************************
* /dev/urandom helpers for all non-BSD Unix platforms
*/
#ifdef CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM
static struct {
int fd;
dev_t st_dev;
ino_t st_ino;
} urandom_cache = { -1 };
static int open_cloexec(const char *path) {
int open_flags = O_RDONLY;
#ifdef O_CLOEXEC
open_flags |= O_CLOEXEC;
#endif
int fd = open(path, open_flags);
if (fd == -1) {
return -1;
}
#ifndef O_CLOEXEC
int flags = fcntl(fd, F_GETFD);
if (flags == -1) {
return -1;
}
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
return -1;
}
#endif
return fd;
}
#ifdef __linux__
/* On Linux, we open("/dev/random") and use poll() to wait until it's readable
* before we read from /dev/urandom, this ensures that we don't read from
* /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on
* other platforms because they don't have the same _bug_ as Linux does with
* /dev/urandom and early boot. */
static int wait_on_devrandom(void) {
struct pollfd pfd = {};
int ret = 0;
int random_fd = open_cloexec("/dev/random");
if (random_fd < 0) {
return -1;
}
pfd.fd = random_fd;
pfd.events = POLLIN;
pfd.revents = 0;
do {
ret = poll(&pfd, 1, -1);
} while (ret < 0 && (errno == EINTR || errno == EAGAIN));
close(random_fd);
return ret;
}
#endif
/* return -1 on error */
static int dev_urandom_fd(void) {
int fd = -1;
struct stat st;
/* Check that fd still points to the correct device */
if (urandom_cache.fd >= 0) {
if (fstat(urandom_cache.fd, &st)
|| st.st_dev != urandom_cache.st_dev
|| st.st_ino != urandom_cache.st_ino) {
/* Somebody replaced our FD. Invalidate our cache but don't
* close the fd. */
urandom_cache.fd = -1;
}
}
if (urandom_cache.fd < 0) {
#ifdef __linux__
if (wait_on_devrandom() < 0) {
goto error;
}
#endif
fd = open_cloexec("/dev/urandom");
if (fd < 0) {
goto error;
}
if (fstat(fd, &st)) {
goto error;
}
/* Another thread initialized the fd */
if (urandom_cache.fd >= 0) {
close(fd);
return urandom_cache.fd;
}
urandom_cache.st_dev = st.st_dev;
urandom_cache.st_ino = st.st_ino;
urandom_cache.fd = fd;
}
return urandom_cache.fd;
error:
if (fd != -1) {
close(fd);
}
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED,
__FILE__, __LINE__
);
return -1;
}
static int dev_urandom_read(unsigned char *buffer, int size) {
int fd;
int n;
fd = dev_urandom_fd();
if (fd < 0) {
return 0;
}
while (size > 0) {
do {
n = (int)read(fd, buffer, (size_t)size);
} while (n < 0 && errno == EINTR);
if (n <= 0) {
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ,
CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED,
__FILE__, __LINE__
);
return 0;
}
buffer += n;
size -= n;
}
return 1;
}
static void dev_urandom_close(void) {
if (urandom_cache.fd >= 0) {
int fd;
struct stat st;
if (fstat(urandom_cache.fd, &st)
&& st.st_dev == urandom_cache.st_dev
&& st.st_ino == urandom_cache.st_ino) {
fd = urandom_cache.fd;
urandom_cache.fd = -1;
close(fd);
}
}
}
#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
/****************************************************************************
* BSD getentropy
*/
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
static int osrandom_init(ENGINE *e) {
return 1;
}
static int osrandom_rand_bytes(unsigned char *buffer, int size) {
int len;
int res;
while (size > 0) {
/* OpenBSD and macOS restrict maximum buffer size to 256. */
len = size > 256 ? 256 : size;
res = getentropy(buffer, (size_t)len);
if (res < 0) {
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED,
__FILE__, __LINE__
);
return 0;
}
buffer += len;
size -= len;
}
return 1;
}
static int osrandom_finish(ENGINE *e) {
return 1;
}
static int osrandom_rand_status(void) {
return 1;
}
static const char *osurandom_get_implementation(void) {
return "getentropy";
}
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
/****************************************************************************
* Linux getrandom engine with fallback to dev_urandom
*/
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT;
static int osrandom_init(ENGINE *e) {
/* We try to detect working getrandom until we succeed. */
if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) {
long n;
char dest[1];
/* if the kernel CSPRNG is not initialized this will block */
n = syscall(SYS_getrandom, dest, sizeof(dest), 0);
if (n == sizeof(dest)) {
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS;
} else {
int e = errno;
switch(e) {
case ENOSYS:
/* Fallback: Kernel does not support the syscall. */
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
break;
case EPERM:
/* Fallback: seccomp prevents syscall */
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
break;
default:
/* EINTR cannot occur for buflen < 256. */
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_INIT,
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED,
"errno", e
);
getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
break;
}
}
}
/* fallback to dev urandom */
if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) {
int fd = dev_urandom_fd();
if (fd < 0) {
return 0;
}
}
return 1;
}
static int osrandom_rand_bytes(unsigned char *buffer, int size) {
long n;
switch(getrandom_works) {
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED,
__FILE__, __LINE__
);
return 0;
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT,
__FILE__, __LINE__
);
return 0;
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
return dev_urandom_read(buffer, size);
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
while (size > 0) {
do {
n = syscall(SYS_getrandom, buffer, size, 0);
} while (n < 0 && errno == EINTR);
if (n <= 0) {
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED,
__FILE__, __LINE__
);
return 0;
}
buffer += n;
size -= (int)n;
}
return 1;
}
__builtin_unreachable();
}
static int osrandom_finish(ENGINE *e) {
dev_urandom_close();
return 1;
}
static int osrandom_rand_status(void) {
switch(getrandom_works) {
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
return 0;
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
return 0;
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
return urandom_cache.fd >= 0;
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
return 1;
}
__builtin_unreachable();
}
static const char *osurandom_get_implementation(void) {
switch(getrandom_works) {
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
return "<failed>";
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
return "<not initialized>";
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
return "/dev/urandom";
case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
return "getrandom";
}
__builtin_unreachable();
}
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
/****************************************************************************
* dev_urandom engine for all remaining platforms
*/
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
static const char *Cryptography_osrandom_engine_name = "osrandom_engine /dev/urandom";
static int osrandom_init(ENGINE *e) {
int fd = dev_urandom_fd();
if (fd < 0) {
return 0;
}
return 1;
}
static int osrandom_rand_bytes(unsigned char *buffer, int size) {
return dev_urandom_read(buffer, size);
}
static int osrandom_finish(ENGINE *e) {
dev_urandom_close();
return 1;
}
static int osrandom_rand_status(void) {
return urandom_cache.fd >= 0;
}
static const char *osurandom_get_implementation(void) {
return "/dev/urandom";
}
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */
/****************************************************************************
* ENGINE boiler plate
*/
/* This replicates the behavior of the OpenSSL FIPS RNG, which returns a
-1 in the event that there is an error when calling RAND_pseudo_bytes. */
static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) {
int res = osrandom_rand_bytes(buffer, size);
if (res == 0) {
return -1;
} else {
return res;
}
}
static RAND_METHOD osrandom_rand = {
NULL,
osrandom_rand_bytes,
NULL,
NULL,
osrandom_pseudo_rand_bytes,
osrandom_rand_status,
};
static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = {
{CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION,
"get_implementation",
"Get CPRNG implementation.",
ENGINE_CMD_FLAG_NO_INPUT},
{0, NULL, NULL, 0}
};
static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) {
const char *name;
size_t len;
switch (cmd) {
case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION:
/* i: buffer size, p: char* buffer */
name = osurandom_get_implementation();
len = strlen(name);
if ((p == NULL) && (i == 0)) {
/* return required buffer len */
return (int)len;
}
if ((p == NULL) || i < 0 || ((size_t)i <= len)) {
/* no buffer or buffer too small */
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT);
return 0;
}
strcpy((char *)p, name);
return (int)len;
default:
ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
return 0;
}
}
/* error reporting */
#define ERR_FUNC(func) ERR_PACK(0, func, 0)
#define ERR_REASON(reason) ERR_PACK(0, 0, reason)
static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = {
{0, "osrandom_engine"},
{0, NULL}
};
static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = {
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT),
"osrandom_init"},
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES),
"osrandom_rand_bytes"},
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH),
"osrandom_finish"},
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD),
"dev_urandom_fd"},
{ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ),
"dev_urandom_read"},
{0, NULL}
};
static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = {
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT),
"CryptAcquireContext() failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM),
"CryptGenRandom() failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT),
"CryptReleaseContext() failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED),
"getentropy() failed"},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED),
"open('/dev/urandom') failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED),
"Reading from /dev/urandom fd failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED),
"getrandom() initialization failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED),
"getrandom() initialization failed with unexpected errno."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED),
"getrandom() syscall failed."},
{ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT),
"getrandom() engine was not properly initialized."},
{0, NULL}
};
static int Cryptography_OSRandom_lib_error_code = 0;
static void ERR_load_Cryptography_OSRandom_strings(void)
{
if (Cryptography_OSRandom_lib_error_code == 0) {
Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library();
ERR_load_strings(Cryptography_OSRandom_lib_error_code,
CRYPTOGRAPHY_OSRANDOM_lib_name);
ERR_load_strings(Cryptography_OSRandom_lib_error_code,
CRYPTOGRAPHY_OSRANDOM_str_funcs);
ERR_load_strings(Cryptography_OSRandom_lib_error_code,
CRYPTOGRAPHY_OSRANDOM_str_reasons);
}
}
static void ERR_Cryptography_OSRandom_error(int function, int reason,
char *file, int line)
{
ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason,
file, line);
}
/* Returns 1 if successfully added, 2 if engine has previously been added,
and 0 for error. */
int Cryptography_add_osrandom_engine(void) {
ENGINE *e;
ERR_load_Cryptography_OSRandom_strings();
e = ENGINE_by_id(Cryptography_osrandom_engine_id);
if (e != NULL) {
ENGINE_free(e);
return 2;
} else {
ERR_clear_error();
}
e = ENGINE_new();
if (e == NULL) {
return 0;
}
if (!ENGINE_set_id(e, Cryptography_osrandom_engine_id) ||
!ENGINE_set_name(e, Cryptography_osrandom_engine_name) ||
!ENGINE_set_RAND(e, &osrandom_rand) ||
!ENGINE_set_init_function(e, osrandom_init) ||
!ENGINE_set_finish_function(e, osrandom_finish) ||
!ENGINE_set_cmd_defns(e, osrandom_cmd_defns) ||
!ENGINE_set_ctrl_function(e, osrandom_ctrl)) {
ENGINE_free(e);
return 0;
}
if (!ENGINE_add(e)) {
ENGINE_free(e);
return 0;
}
if (!ENGINE_free(e)) {
return 0;
}
return 1;
}
#else
/* If OpenSSL has no ENGINE support then we don't want
* to compile the osrandom engine, but we do need some
* placeholders */
static const char *Cryptography_osrandom_engine_id = "no-engine-support";
static const char *Cryptography_osrandom_engine_name = "osrandom_engine disabled";
int Cryptography_add_osrandom_engine(void) {
return 0;
}
#endif

View file

@ -1,116 +0,0 @@
#if CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE
/* OpenSSL has ENGINE support so include all of this. */
#ifdef _WIN32
#include <Wincrypt.h>
#else
#include <fcntl.h>
#include <unistd.h>
/* for defined(BSD) */
#ifndef __MVS__
#include <sys/param.h>
#endif
#ifdef BSD
/* for SYS_getentropy */
#include <sys/syscall.h>
#endif
#ifdef __APPLE__
#include <sys/random.h>
/* To support weak linking we need to declare this as a weak import even if
* it's not present in sys/random (e.g. macOS < 10.12). */
extern int getentropy(void *buffer, size_t size) __attribute((weak_import));
#endif
#ifdef __linux__
/* for SYS_getrandom */
#include <sys/syscall.h>
#ifndef GRND_NONBLOCK
#define GRND_NONBLOCK 0x0001
#endif /* GRND_NONBLOCK */
#ifndef SYS_getrandom
/* We only bother to define the constants for platforms where we ship
* wheels, since that's the predominant way you get a situation where
* you don't have SYS_getrandom at compile time but do have the syscall
* at runtime */
#if defined(__x86_64__)
#define SYS_getrandom 318
#elif defined(__i386__)
#define SYS_getrandom 355
#elif defined(__aarch64__)
#define SYS_getrandom 278
#endif
#endif
#endif /* __linux__ */
#endif /* _WIN32 */
#define CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM 1
#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY 2
#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM 3
#define CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM 4
#ifndef CRYPTOGRAPHY_OSRANDOM_ENGINE
#if defined(_WIN32)
/* Windows */
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
#elif defined(BSD) && defined(SYS_getentropy)
/* OpenBSD 5.6+ & macOS with SYS_getentropy defined, although < 10.12 will fallback
* to urandom */
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
#elif defined(__linux__) && defined(SYS_getrandom)
/* Linux 3.17+ */
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
#else
/* Keep this as last entry, fall back to /dev/urandom */
#define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
#endif
#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE */
/* Fallbacks need /dev/urandom helper functions. */
#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM || \
CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
#define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1
#endif
enum {
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED = -2,
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT,
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK,
CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS
};
enum {
CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT,
CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK,
CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS
};
/* engine ctrl */
#define CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION ENGINE_CMD_BASE
/* error reporting */
static void ERR_load_Cryptography_OSRandom_strings(void);
static void ERR_Cryptography_OSRandom_error(int function, int reason,
char *file, int line);
#define CRYPTOGRAPHY_OSRANDOM_F_INIT 100
#define CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES 101
#define CRYPTOGRAPHY_OSRANDOM_F_FINISH 102
#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD 300
#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ 301
#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT 100
#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM 101
#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT 102
#define CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED 200
#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED 300
#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED 301
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED 400
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED 402
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED 403
#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT 404
#endif

View file

@ -7,7 +7,6 @@ import collections
import contextlib
import itertools
import typing
import warnings
from contextlib import contextmanager
from cryptography import utils, x509
@ -185,13 +184,6 @@ class Backend:
typing.Callable,
] = {}
self._register_default_ciphers()
if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
warnings.warn(
"OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.",
UserWarning,
)
else:
self.activate_osrandom_engine()
self._dh_types = [self._lib.EVP_PKEY_DH]
if self._lib.Cryptography_HAS_EVP_PKEY_DHX:
self._dh_types.append(self._lib.EVP_PKEY_DHX)
@ -230,60 +222,6 @@ class Backend:
assert self._is_fips_enabled()
self._fips_enabled = self._is_fips_enabled()
def activate_builtin_random(self) -> None:
if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
# Obtain a new structural reference.
e = self._lib.ENGINE_get_default_RAND()
if e != self._ffi.NULL:
self._lib.ENGINE_unregister_RAND(e)
# Reset the RNG to use the built-in.
res = self._lib.RAND_set_rand_method(self._ffi.NULL)
self.openssl_assert(res == 1)
# decrement the structural reference from get_default_RAND
res = self._lib.ENGINE_finish(e)
self.openssl_assert(res == 1)
@contextlib.contextmanager
def _get_osurandom_engine(self):
# Fetches an engine by id and returns it. This creates a structural
# reference.
e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id)
self.openssl_assert(e != self._ffi.NULL)
# Initialize the engine for use. This adds a functional reference.
res = self._lib.ENGINE_init(e)
self.openssl_assert(res == 1)
try:
yield e
finally:
# Decrement the structural ref incremented by ENGINE_by_id.
res = self._lib.ENGINE_free(e)
self.openssl_assert(res == 1)
# Decrement the functional ref incremented by ENGINE_init.
res = self._lib.ENGINE_finish(e)
self.openssl_assert(res == 1)
def activate_osrandom_engine(self) -> None:
if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
# Unregister and free the current engine.
self.activate_builtin_random()
with self._get_osurandom_engine() as e:
# Set the engine as the default RAND provider.
res = self._lib.ENGINE_set_default_RAND(e)
self.openssl_assert(res == 1)
# Reset the RNG to use the engine
res = self._lib.RAND_set_rand_method(self._ffi.NULL)
self.openssl_assert(res == 1)
def osrandom_engine_implementation(self) -> str:
buf = self._ffi.new("char[]", 64)
with self._get_osurandom_engine() as e:
res = self._lib.ENGINE_ctrl_cmd(
e, b"get_implementation", len(buf), buf, self._ffi.NULL, 0
)
self.openssl_assert(res > 0)
return self._ffi.string(buf).decode("ascii")
def openssl_version_text(self) -> str:
"""
Friendly string name of the loaded OpenSSL library. This is not
@ -1968,7 +1906,7 @@ class Backend:
if self._fips_enabled:
return False
return (
not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
not self._lib.CRYPTOGRAPHY_IS_LIBRESSL
and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL
)

View file

@ -119,7 +119,7 @@ class _CipherContext:
lib = self._backend._lib
if res == 0 and (
(
lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER
not lib.CRYPTOGRAPHY_IS_LIBRESSL
and errors[0]._lib_reason_match(
lib.ERR_LIB_EVP, lib.EVP_R_XTS_DUPLICATED_KEYS
)

View file

@ -162,7 +162,6 @@ def cryptography_has_engine() -> typing.List[str]:
"ENGINE_ctrl_cmd",
"ENGINE_free",
"ENGINE_get_name",
"Cryptography_add_osrandom_engine",
"ENGINE_ctrl_cmd_string",
"ENGINE_load_builtin_engines",
"ENGINE_load_private_key",

View file

@ -10,7 +10,6 @@ import typing
import warnings
import cryptography
from cryptography import utils
from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._rust import _openssl, openssl
from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
@ -98,18 +97,6 @@ class Binding:
res = self.lib.EVP_default_properties_enable_fips(self.ffi.NULL, 1)
_openssl_assert(self.lib, res == 1)
@classmethod
def _register_osrandom_engine(cls) -> None:
# Clear any errors extant in the queue before we start. In many
# scenarios other things may be interacting with OpenSSL in the same
# process space and it has proven untenable to assume that they will
# reliably clear the error queue. Once we clear it here we will
# error on any subsequent unexpected item in the stack.
cls.lib.ERR_clear_error()
if cls.lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
result = cls.lib.Cryptography_add_osrandom_engine()
_openssl_assert(cls.lib, result in (1, 2))
@classmethod
def _ensure_ffi_initialized(cls) -> None:
with cls._init_lock:
@ -118,7 +105,6 @@ class Binding:
_openssl.lib, CONDITIONAL_NAMES
)
cls._lib_loaded = True
cls._register_osrandom_engine()
# 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
@ -189,20 +175,3 @@ if (
UserWarning,
stacklevel=2,
)
def _verify_openssl_version(lib):
if (
not lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER
and not lib.CRYPTOGRAPHY_IS_LIBRESSL
and not lib.CRYPTOGRAPHY_IS_BORINGSSL
):
warnings.warn(
"Support for OpenSSL less than version 1.1.1d is deprecated and "
"the next release of cryptography will drop support. Please "
"upgrade your OpenSSL to version 1.1.1d or newer.",
utils.DeprecatedIn40,
)
_verify_openssl_version(Binding.lib)

View file

@ -5,9 +5,6 @@
import itertools
import os
import subprocess
import sys
import textwrap
import pytest
@ -179,158 +176,6 @@ class TestOpenSSL:
assert backend._bn_to_int(bn) == 0
@pytest.mark.skipif(
not backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE,
reason="Requires OpenSSL with ENGINE support and OpenSSL < 1.1.1d",
)
@pytest.mark.skip_fips(reason="osrandom engine disabled for FIPS")
class TestOpenSSLRandomEngine:
def setup_method(self):
# The default RAND engine is global and shared between
# tests. We make sure that the default engine is osrandom
# before we start each test and restore the global state to
# that engine in teardown.
current_default = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(current_default)
assert name == backend._lib.Cryptography_osrandom_engine_name
def teardown_method(self):
# we need to reset state to being default. backend is a shared global
# for all these tests.
backend.activate_osrandom_engine()
current_default = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(current_default)
assert name == backend._lib.Cryptography_osrandom_engine_name
@pytest.mark.skipif(
sys.executable is None, reason="No Python interpreter available."
)
def test_osrandom_engine_is_default(self, tmpdir):
engine_printer = textwrap.dedent(
"""
import sys
from cryptography.hazmat.backends.openssl.backend import backend
e = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(e)
sys.stdout.write(backend._ffi.string(name).decode('ascii'))
res = backend._lib.ENGINE_free(e)
assert res == 1
"""
)
engine_name = tmpdir.join("engine_name")
# If we're running tests via ``python setup.py test`` in a clean
# environment then all of our dependencies are going to be installed
# into either the current directory or the .eggs directory. However the
# subprocess won't know to activate these dependencies, so we'll get it
# to do so by passing our entire sys.path into the subprocess via the
# PYTHONPATH environment variable.
env = os.environ.copy()
env["PYTHONPATH"] = os.pathsep.join(sys.path)
with engine_name.open("w") as out:
subprocess.check_call(
[sys.executable, "-c", engine_printer],
env=env,
stdout=out,
stderr=subprocess.PIPE,
)
osrandom_engine_name = backend._ffi.string(
backend._lib.Cryptography_osrandom_engine_name
)
assert engine_name.read().encode("ascii") == osrandom_engine_name
def test_osrandom_sanity_check(self):
# This test serves as a check against catastrophic failure.
buf = backend._ffi.new("unsigned char[]", 500)
res = backend._lib.RAND_bytes(buf, 500)
assert res == 1
assert backend._ffi.buffer(buf)[:] != "\x00" * 500
def test_activate_osrandom_no_default(self):
backend.activate_builtin_random()
e = backend._lib.ENGINE_get_default_RAND()
assert e == backend._ffi.NULL
backend.activate_osrandom_engine()
e = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(e)
assert name == backend._lib.Cryptography_osrandom_engine_name
res = backend._lib.ENGINE_free(e)
assert res == 1
def test_activate_builtin_random(self):
e = backend._lib.ENGINE_get_default_RAND()
assert e != backend._ffi.NULL
name = backend._lib.ENGINE_get_name(e)
assert name == backend._lib.Cryptography_osrandom_engine_name
res = backend._lib.ENGINE_free(e)
assert res == 1
backend.activate_builtin_random()
e = backend._lib.ENGINE_get_default_RAND()
assert e == backend._ffi.NULL
def test_activate_builtin_random_already_active(self):
backend.activate_builtin_random()
e = backend._lib.ENGINE_get_default_RAND()
assert e == backend._ffi.NULL
backend.activate_builtin_random()
e = backend._lib.ENGINE_get_default_RAND()
assert e == backend._ffi.NULL
def test_osrandom_engine_implementation(self):
name = backend.osrandom_engine_implementation()
assert name in [
"/dev/urandom",
"CryptGenRandom",
"getentropy",
"getrandom",
]
if sys.platform.startswith("linux"):
assert name in ["getrandom", "/dev/urandom"]
if sys.platform == "darwin":
assert name in ["getentropy"]
if sys.platform == "win32":
assert name == "CryptGenRandom"
def test_activate_osrandom_already_default(self):
e = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(e)
assert name == backend._lib.Cryptography_osrandom_engine_name
res = backend._lib.ENGINE_free(e)
assert res == 1
backend.activate_osrandom_engine()
e = backend._lib.ENGINE_get_default_RAND()
name = backend._lib.ENGINE_get_name(e)
assert name == backend._lib.Cryptography_osrandom_engine_name
res = backend._lib.ENGINE_free(e)
assert res == 1
@pytest.mark.skipif(
backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE,
reason="Requires OpenSSL without ENGINE support or OpenSSL >=1.1.1d",
)
class TestOpenSSLNoEngine:
def test_no_engine_support(self):
assert (
backend._ffi.string(backend._lib.Cryptography_osrandom_engine_id)
== b"no-engine-support"
)
assert (
backend._ffi.string(backend._lib.Cryptography_osrandom_engine_name)
== b"osrandom_engine disabled"
)
def test_activate_builtin_random_does_nothing(self):
backend.activate_builtin_random()
def test_activate_osrandom_does_nothing(self):
backend.activate_osrandom_engine()
class TestOpenSSLRSA:
def test_generate_rsa_parameters_supported(self):
assert backend.generate_rsa_parameters_supported(1, 1024) is False

View file

@ -21,11 +21,6 @@ class TestOpenSSL:
assert binding.lib
assert binding.ffi
def test_add_engine_more_than_once(self):
b = Binding()
b._register_osrandom_engine()
assert b.lib.ERR_get_error() == 0
def test_ssl_ctx_options(self):
# Test that we're properly handling 32-bit unsigned on all platforms.
b = Binding()
@ -85,18 +80,6 @@ class TestOpenSSL:
if not b.lib.CRYPTOGRAPHY_IS_BORINGSSL:
assert b"data not multiple of block length" in error.reason_text
def test_check_startup_errors_are_allowed(self):
b = Binding()
b.lib.ERR_put_error(
b.lib.ERR_LIB_EVP,
b.lib.EVP_F_EVP_ENCRYPTFINAL_EX,
b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH,
b"",
-1,
)
b._register_osrandom_engine()
assert rust_openssl.capture_error_stack() == []
def test_version_mismatch(self):
with pytest.raises(ImportError):
_verify_package_version("nottherightversion")

View file

@ -61,9 +61,7 @@ class TestAESModeXTS:
enc.update(b"0" * 15)
@pytest.mark.supported(
only_if=lambda backend: (
backend._lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER
),
only_if=lambda backend: (not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL),
skip_message="duplicate key encryption error added in OpenSSL 1.1.1d",
)
def test_xts_no_duplicate_keys_encryption(self, backend):