From 169c7f59203b52ca370246ae31ed0f0cb5124391 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Thu, 11 Jan 2024 18:11:44 -0500 Subject: [PATCH] Revert "Raise minimum supported Apple OS versions (#388)" This reverts commit 5fe3c8e34ad36cd99674530094dd6c90b1c4a5c0. --- CHANGELOG.md | 5 +++++ src/apple-other.rs | 27 +++++++++++++++------------ src/error.rs | 4 +--- src/lib.rs | 7 ++++--- src/macos.rs | 40 +++++++++++++++++++++++++++++----------- src/use_file.rs | 11 ++++++++++- 6 files changed, 64 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a283d380..0821649b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [master] +### Changed + +- Reverted "Raise minimum supported Apple OS versions to macOS 10.12 and iOS 10 [#388]" + ## [0.2.12] - 2024-01-09 ### Fixed - Custom backend for targets without atomics [#385] diff --git a/src/apple-other.rs b/src/apple-other.rs index 167d8cf0..8f904859 100644 --- a/src/apple-other.rs +++ b/src/apple-other.rs @@ -1,21 +1,24 @@ -//! Implementation for iOS, tvOS, and watchOS where `getentropy` is unavailable. +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for iOS use crate::Error; -use core::{ffi::c_void, mem::MaybeUninit}; +use core::{ffi::c_void, mem::MaybeUninit, ptr::null}; -// libsystem contains the libc of Darwin, and every binary ends up linked against it either way. This -// makes it a more lightweight choice compared to `Security.framework`. +#[link(name = "Security", kind = "framework")] extern "C" { - // This RNG uses a thread-local CSPRNG to provide data, which is seeded by the operating system's root CSPRNG. - // Its the best option after `getentropy` on modern Darwin-based platforms that also avoids the - // high startup costs and linking of Security.framework. - // - // While its just an implementation detail, `Security.framework` just calls into this anyway. - fn CCRandomGenerateBytes(bytes: *mut c_void, size: usize) -> i32; + fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> i32; } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - let ret = unsafe { CCRandomGenerateBytes(dest.as_mut_ptr() as *mut c_void, dest.len()) }; - // kCCSuccess (from CommonCryptoError.h) is always zero. + // Apple's documentation guarantees kSecRandomDefault is a synonym for NULL. + let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr() as *mut u8) }; + // errSecSuccess (from SecBase.h) is always zero. if ret != 0 { Err(Error::IOS_SEC_RANDOM) } else { diff --git a/src/error.rs b/src/error.rs index 13c81c7a..1104d3ea 100644 --- a/src/error.rs +++ b/src/error.rs @@ -30,9 +30,7 @@ impl Error { pub const ERRNO_NOT_POSITIVE: Error = internal_error(1); /// Encountered an unexpected situation which should not happen in practice. pub const UNEXPECTED: Error = internal_error(2); - /// Call to [`CCRandomGenerateBytes`](https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html) failed - /// on iOS, tvOS, or waatchOS. - // TODO: Update this constant name in the next breaking release. + /// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed. pub const IOS_SEC_RANDOM: Error = internal_error(3); /// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed. pub const WINDOWS_RTL_GEN_RANDOM: Error = internal_error(4); diff --git a/src/lib.rs b/src/lib.rs index e80ec6f5..1e706edf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ //! | ----------------- | ------------------ | -------------- //! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` //! | Windows | `*‑windows‑*` | [`BCryptGenRandom`] -//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] -//! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`CCRandomGenerateBytes`] +//! | macOS | `*‑apple‑darwin` | [`getentropy`][3] if available, otherwise [`/dev/urandom`][4] (identical to `/dev/random`) +//! | iOS, tvOS, watchOS | `*‑apple‑ios`, `*-apple-tvos`, `*-apple-watchos` | [`SecRandomCopyBytes`] //! | FreeBSD | `*‑freebsd` | [`getrandom`][5] if available, otherwise [`kern.arandom`][6] //! | OpenBSD | `*‑openbsd` | [`getentropy`][7] //! | NetBSD | `*‑netbsd` | [`getrandom`][16] if available, otherwise [`kern.arandom`][8] @@ -171,7 +171,7 @@ //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom //! [`Crypto.getRandomValues`]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues //! [`RDRAND`]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide -//! [`CCRandomGenerateBytes`]: https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60074/include/CommonRandom.h.auto.html +//! [`SecRandomCopyBytes`]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc //! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw //! [`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size //! [`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t @@ -242,6 +242,7 @@ cfg_if! { #[path = "apple-other.rs"] mod imp; } else if #[cfg(target_os = "macos")] { mod util_libc; + mod use_file; #[path = "macos.rs"] mod imp; } else if #[cfg(target_os = "openbsd")] { mod util_libc; diff --git a/src/macos.rs b/src/macos.rs index 44af76b0..312f9b27 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -1,18 +1,36 @@ +// Copyright 2019 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + //! Implementation for macOS -use crate::{util_libc::last_os_error, Error}; -use core::mem::MaybeUninit; +use crate::{ + use_file, + util_libc::{last_os_error, Weak}, + Error, +}; +use core::mem::{self, MaybeUninit}; -extern "C" { - // Supported as of macOS 10.12+. - fn getentropy(buf: *mut u8, size: libc::size_t) -> libc::c_int; -} +type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - for chunk in dest.chunks_mut(256) { - let ret = unsafe { getentropy(chunk.as_mut_ptr() as *mut u8, chunk.len()) }; - if ret != 0 { - return Err(last_os_error()); + // getentropy(2) was added in 10.12, Rust supports 10.7+ + static GETENTROPY: Weak = unsafe { Weak::new("getentropy\0") }; + if let Some(fptr) = GETENTROPY.ptr() { + let func: GetEntropyFn = unsafe { mem::transmute(fptr) }; + for chunk in dest.chunks_mut(256) { + let ret = unsafe { func(chunk.as_mut_ptr() as *mut u8, chunk.len()) }; + if ret != 0 { + return Err(last_os_error()); + } } + Ok(()) + } else { + // We fallback to reading from /dev/random instead of SecRandomCopyBytes + // to avoid high startup costs and linking the Security framework. + use_file::getrandom_inner(dest) } - Ok(()) } diff --git a/src/use_file.rs b/src/use_file.rs index 333325b5..23a5a5ae 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -1,3 +1,11 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + //! Implementations that just need to read from a file use crate::{ util_libc::{open_readonly, sys_fill_exact}, @@ -12,7 +20,7 @@ use core::{ // We prefer using /dev/urandom and only use /dev/random if the OS // documentation indicates that /dev/urandom is insecure. // On Solaris/Illumos, see src/solaris_illumos.rs -// On Dragonfly, Haiku, and QNX Neutrino the devices are identical. +// On Dragonfly, Haiku, macOS, and QNX Neutrino the devices are identical. #[cfg(any(target_os = "solaris", target_os = "illumos"))] const FILE_PATH: &str = "/dev/random\0"; #[cfg(any( @@ -22,6 +30,7 @@ const FILE_PATH: &str = "/dev/random\0"; target_os = "redox", target_os = "dragonfly", target_os = "haiku", + target_os = "macos", target_os = "nto", ))] const FILE_PATH: &str = "/dev/urandom\0";