Avoid static initializers, lazily load CPUID info from Rust.

Avoid all the messiness involved with static initializers by doing it
the dumb way. Static initializers are commonly banned from applications
because they add latency to application startup.

This implementation needs to be fine-tuned to account for cases where
we don't need CPUID info (e.g. hard-coded ARM target profiles, NO_ASM
builds, platforms where we have no ASM code).

Also, it is worth investigating whether the Rust implementation of
`call_once` has optimal performance, but for now we punt on that issue.
This commit is contained in:
Brian Smith 2016-04-25 17:17:56 -10:00
parent aadc9518b5
commit 006d93a203
17 changed files with 48 additions and 125 deletions

View File

@ -16,7 +16,6 @@
#include <string.h>
#include <openssl/aes.h>
#include <openssl/crypto.h>
extern "C" int bssl_aes_test_main();
@ -69,8 +68,6 @@ static bool TestAES(const uint8_t *key, size_t key_len,
}
extern "C" int bssl_aes_test_main() {
CRYPTO_library_init();
// Test vectors from FIPS-197, Appendix C.
if (!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",

View File

@ -86,7 +86,6 @@
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/mem.h>
@ -140,8 +139,6 @@ static const uint8_t kSample[] =
"\x9B\x04\x5D\x48\x36\xC2\xFD\x16\xC9\x64\xF0";
extern "C" int bssl_bn_test_main(RAND *rng) {
CRYPTO_library_init();
ScopedBN_CTX ctx(BN_CTX_new());
if (!ctx) {
return 1;

View File

@ -28,7 +28,6 @@
#include <vector>
#include <openssl/crypto.h>
#include <openssl/bytestring.h>
#include "internal.h"
@ -413,8 +412,6 @@ static int TestZero() {
}
extern "C" int bssl_bytestring_test_main() {
CRYPTO_library_init();
if (!TestGetASN1() ||
!TestCBBBasic() ||
!TestCBBFixed() ||

View File

@ -24,7 +24,6 @@
#include <memory>
#include <openssl/crypto.h>
#include <openssl/chacha.h>
@ -256,8 +255,6 @@ static bool TestChaCha20(size_t len) {
}
extern "C" int bssl_chacha_test_main(void) {
CRYPTO_library_init();
// Run the test with the test vector at all lengths.
for (size_t len = 0; len <= sizeof(kInput); len++) {
if (!TestChaCha20(len)) {

View File

@ -12,8 +12,6 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <openssl/crypto.h>
#include <stdint.h>
#include <openssl/cpu.h>
@ -40,14 +38,6 @@
OPENSSL_ARM || OPENSSL_AARCH64) */
/* The capability variables are defined in this file in order to work around a
* linker bug. When linking with a .a, if no symbols in a .o are referenced
* then the .o is discarded, even if it has constructor functions.
*
* This still means that any binaries that don't include some functionality
* that tests the capability values will still skip the constructor but, so
* far, the init constructor function only sets the capability variables. */
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
/* This value must be explicitly initialised to zero in order to work around a
* bug in libtool or the linker on OS X.
@ -89,44 +79,6 @@ uint32_t OPENSSL_armcap_P = 0;
#endif
#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_NO_STATIC_INITIALIZER)
#define OPENSSL_CDECL __cdecl
#else
#define OPENSSL_CDECL
#endif
#if defined(BORINGSSL_NO_STATIC_INITIALIZER)
static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
#elif defined(OPENSSL_WINDOWS)
#pragma section(".CRT$XCU", read)
static void __cdecl do_library_init(void);
__declspec(allocate(".CRT$XCU")) void(*library_init_constructor)(void) =
do_library_init;
#else
static void do_library_init(void) __attribute__ ((constructor));
#endif
/* do_library_init is the actual initialization function. If
* BORINGSSL_NO_STATIC_INITIALIZER isn't defined, this is set as a static
* initializer. Otherwise, it is called by CRYPTO_library_init. */
static void OPENSSL_CDECL do_library_init(void) {
/* WARNING: this function may only configure the capability variables. See the
* note above about the linker bug. */
#if defined(NEED_CPUID)
OPENSSL_cpuid_setup();
#endif
}
void CRYPTO_library_init(void) {
/* TODO(davidben): It would be tidier if this build knob could be replaced
* with an internal lazy-init mechanism that would handle things correctly
* in-library. https://crbug.com/542879 */
#if defined(BORINGSSL_NO_STATIC_INITIALIZER)
CRYPTO_once(&once, do_library_init);
#endif
}
/* These functions allow tests in other languages to verify that their
* understanding of the C types matches the C compiler's understanding. */

View File

@ -28,7 +28,6 @@
#include <string.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include "../bn/internal.h"

View File

@ -61,7 +61,6 @@
#include <vector>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
@ -322,8 +321,6 @@ static size_t BitsToBytes(size_t bits) {
}
extern "C" int bssl_ecdsa_test_main(RAND *rng) {
CRYPTO_library_init();
if (!TestBuiltin(rng, stdout) ||
!TestECDSA_SIG_max_len(BitsToBytes(256)) ||
!TestECDSA_SIG_max_len(BitsToBytes(384))) {

View File

@ -23,7 +23,6 @@
#include <vector>
#include <openssl/crypto.h>
#include <openssl/poly1305.h>
#include "../internal.h"
@ -129,8 +128,6 @@ static bool TestPoly1305(FileTest *t, void * /*arg*/) {
}
extern "C" int bssl_poly1305_test_main() {
CRYPTO_library_init();
return FileTestMain(TestPoly1305, nullptr,
"crypto/poly1305/poly1305_test.txt");
}

View File

@ -66,7 +66,6 @@
#include <string.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/nid.h>
@ -363,8 +362,6 @@ static bool TestBadExponent() {
}
extern "C" int bssl_rsa_test_main(RAND *rng) {
CRYPTO_library_init();
if (!TestRSA(kKey1, sizeof(kKey1) - 1, kOAEPCiphertext1,
sizeof(kOAEPCiphertext1) - 1, rng) ||
!TestRSA(kKey2, sizeof(kKey2) - 1, kOAEPCiphertext2,

View File

@ -1,47 +0,0 @@
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef OPENSSL_HEADER_CRYPTO_H
#define OPENSSL_HEADER_CRYPTO_H
#include <openssl/base.h>
/* Upstream OpenSSL defines |OPENSSL_malloc|, etc., in crypto.h rather than
* mem.h. */
#include <openssl/mem.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* crypto.h contains functions for initializing the crypto library. */
/* CRYPTO_library_init initializes the crypto library. It must be called if the
* library is built with BORINGSSL_NO_STATIC_INITIALIZER. Otherwise, it does
* nothing and a static initializer is used instead. It is safe to call this
* function multiple times and concurrently from multiple threads.
*
* On some ARM configurations, this function may require filesystem access and
* should be called before entering a sandbox. */
OPENSSL_EXPORT void CRYPTO_library_init(void);
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_CRYPTO_H */

View File

@ -26,7 +26,7 @@
mod chacha20_poly1305;
mod aes_gcm;
use super::{constant_time, polyfill};
use super::{constant_time, init, polyfill};
pub use self::chacha20_poly1305::{CHACHA20_POLY1305, CHACHA20_POLY1305_OLD};
pub use self::aes_gcm::{AES_128_GCM, AES_256_GCM};
@ -205,6 +205,8 @@ impl Key {
///
/// C analogs: `EVP_AEAD_CTX_init`, `EVP_AEAD_CTX_init_with_direction`
fn init(&mut self, key_bytes: &[u8]) -> Result<(), ()> {
init::init_once();
if key_bytes.len() != self.algorithm.key_len() {
return Err(());
}

View File

@ -16,7 +16,8 @@
#![allow(unsafe_code)]
use super::{c, ecc};
use {c, ecc, init};
#[cfg(not(feature = "no_heap"))] use super::bssl;
use super::input::Input;
@ -62,6 +63,8 @@ impl EphemeralKeyPair {
/// C analog: `EC_KEY_new_by_curve_name` + `EC_KEY_generate_key`.
pub fn generate(algorithm: &'static Algorithm)
-> Result<EphemeralKeyPair, ()> {
init::init_once();
let key_pair_impl = try!((algorithm.generate_key_pair)(algorithm));
Ok(EphemeralKeyPair {
key_pair_impl: key_pair_impl,

View File

@ -41,11 +41,13 @@ macro_rules! bssl_test {
#[test]
#[allow(unsafe_code)]
fn $fn_name() {
use $crate::c;
use $crate::{c, init};
extern {
fn $bssl_test_main_fn_name() -> c::int;
}
init::init_once();
let result = unsafe {
$bssl_test_main_fn_name()
};
@ -62,11 +64,13 @@ macro_rules! bssl_test_rng {
#[test]
#[allow(improper_ctypes, unsafe_code)]
fn $fn_name() {
use $crate::{c, rand};
use $crate::{c, init, rand};
extern {
fn $bssl_test_main_fn_name(rng: *mut rand::RAND) -> c::int;
}
init::init_once();
let mut rng = rand::SystemRandom::new().unwrap();
let mut rng = rand::RAND { rng: &mut rng };
let result = unsafe {

View File

@ -27,7 +27,7 @@
#![allow(unsafe_code)]
use core;
use super::{c, polyfill};
use super::{c, init, polyfill};
// XXX: endian-specific.
// XXX: Replace with `const fn` when `const fn` is stable:
@ -80,6 +80,8 @@ impl Context {
///
/// C analogs: `EVP_DigestInit`, `EVP_DigestInit_ex`
pub fn new(algorithm: &'static Algorithm) -> Context {
init::init_once();
Context {
algorithm: algorithm,
state: algorithm.initial_state,

25
src/init.rs Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2016 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#[allow(unsafe_code)]
#[inline(always)]
pub fn init_once() {
extern crate std;
static INIT: std::sync::Once = std::sync::ONCE_INIT;
INIT.call_once(|| unsafe { OPENSSL_cpuid_setup() });
}
extern {
fn OPENSSL_cpuid_setup();
}

View File

@ -116,6 +116,7 @@ pub mod der;
mod ecc;
pub mod hkdf;
pub mod hmac;
mod init;
pub mod input;
pub mod pbkdf2;

View File

@ -41,7 +41,7 @@
#![allow(unsafe_code)]
use super::{c, bssl};
use super::{c, bssl, init};
#[cfg(not(feature = "no_heap"))] use super::{digest, ecc};
use super::input::Input;
@ -110,6 +110,7 @@ trait VerificationAlgorithmImpl {
/// ```
pub fn verify(alg: &VerificationAlgorithm, public_key: Input, msg: Input,
signature: Input) -> Result<(), ()> {
init::init_once();
alg.implementation.verify(public_key, msg, signature)
}
@ -234,6 +235,8 @@ pub static ED25519_VERIFY: VerificationAlgorithm = VerificationAlgorithm {
#[cfg(test)]
fn ed25519_sign(private_key: &[u8], msg: &[u8], signature: &mut [u8])
-> Result<(), ()> {
init::init_once();
if private_key.len() != 64 || signature.len() != 64 {
return Err(());
}