integrated changes to deps

This commit is contained in:
Monica Moniot
2023-08-15 12:57:24 -04:00
parent 656c538481
commit bd55e032e2
95 changed files with 550 additions and 12906 deletions
+25 -11
View File
@@ -1,12 +1,26 @@
[workspace]
members = [
"crypto-glue",
"openssl-sys",
]
[package]
name = "zerotier-crypto-glue"
authors = ["ZeroTier, Inc. <contact@zerotier.com>"]
license = "MPL-2.0"
description = "ZeroTier common security functions and glue code to wrap cryptography APIs."
readme = "README.md"
categories = ["cryptography", "api-bindings"]
edition = "2021"
version = "0.1.0"
#[profile.release]
#opt-level = 3
#strip = true
#debug = false
#codegen-units = 1
#lto = true
[features]
[dependencies]
x25519-dalek = { version = "2.0.0", features = ["static_secrets"], default-features = false }
ed25519-dalek = { version = "2.0.0", features = ["digest", "rand_core"], default-features = false }
poly1305 = { version = "0.8.0", features = [], default-features = false }
cfg-if = "1.0"
libc = "0.2"
once_cell = "1.18.0"
ctor = "^0"
zssp = { git = "ssh://git@github.com/zerotier/zssp.git", branch = "proto", features = ["openssl-sys"], default-features = false }
rand_xoshiro = { version = "0.6.0"}
[dev-dependencies]
hex = "0.4.3"
hex-literal = "0.4.1"
View File
+6 -3
View File
@@ -1,4 +1,7 @@
ZeroTier Cryptographic Glue
======
# ZeroTier Cryptography Library
This repository contains a few utility classes and mostly glue code to provide a common layer for other ZeroTier Rust projects to use various cryptographic APIs.
------
Most of this library is just glue to provide a simple safe API around things like OpenSSL or OS-specific crypto APIs.
It is very important that this library is only linked to OpenSSL versions greater than 1.1.0. 1.1.0 introduced no-hassle threadsafety which we take advantage of. If we want a version prior to 1.1.0 we will have to add conditional threadsafety code.
-30
View File
@@ -1,30 +0,0 @@
[package]
name = "zerotier-crypto-glue"
authors = ["ZeroTier, Inc. <contact@zerotier.com>"]
license = "MPL-2.0"
description = "ZeroTier common security functions and glue code to wrap cryptography APIs."
readme = "README.md"
categories = ["cryptography", "api-bindings"]
edition = "2021"
version = "0.1.0"
[features]
[dependencies]
ed25519-dalek = { version = "1.0.1", features = ["std", "u64_backend"], default-features = false }
poly1305 = { version = "0.8.0", features = [], default-features = false }
x25519-dalek = { version = "1.2.0", features = ["std", "u64_backend"], default-features = false }
cfg-if = "1.0"
foreign-types = "0.5.0"
libc = "0.2"
once_cell = "1.18.0"
ctor = "^0"
#ed25519-dalek still uses rand_core 0.5.1, and that version is incompatible with 0.6.4, so we need to implement both.
rand_core_051 = { package = "rand_core", version = "0.5.1" }
ffi = { package = "openssl-sys", version = "0.9.80", path = "../openssl-sys" }
zssp = { git = "ssh://git@github.com/zerotier/zssp.git", branch = "dev" }
rand_xoshiro = { version = "0.6.0"}
[dev-dependencies]
hex = "0.4.3"
hex-literal = "0.3.4"
-7
View File
@@ -1,7 +0,0 @@
# ZeroTier Cryptography Library
------
Most of this library is just glue to provide a simple safe API around things like OpenSSL or OS-specific crypto APIs.
It is very important that this library is only linked to OpenSSL versions greater than 1.1.0. 1.1.0 introduced no-hassle threadsafety which we take advantage of. If we want a version prior to 1.1.0 we will have to add conditional threadsafety code.
-110
View File
@@ -1,110 +0,0 @@
#![allow(
clippy::inconsistent_digit_grouping,
clippy::uninlined_format_args,
clippy::unusual_byte_groupings
)]
use std::env;
fn main() {
if env::var("DEP_OPENSSL_LIBRESSL").is_ok() {
println!("cargo:rustc-cfg=libressl");
}
if env::var("CARGO_FEATURE_UNSTABLE_BORINGSSL").is_ok() {
println!("cargo:rustc-cfg=boringssl");
return;
}
if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION") {
println!("cargo:rustc-cfg=libressl{}", v);
}
if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
for var in vars.split(',') {
println!("cargo:rustc-cfg=osslconf=\"{}\"", var);
}
}
if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") {
let version = u64::from_str_radix(&version, 16).unwrap();
if version >= 0x1_00_01_00_0 {
println!("cargo:rustc-cfg=ossl101");
}
if version >= 0x1_00_02_00_0 {
println!("cargo:rustc-cfg=ossl102");
}
if version >= 0x1_01_00_00_0 {
println!("cargo:rustc-cfg=ossl110");
}
if version >= 0x1_01_00_07_0 {
println!("cargo:rustc-cfg=ossl110g");
}
if version >= 0x1_01_00_08_0 {
println!("cargo:rustc-cfg=ossl110h");
}
if version >= 0x1_01_01_00_0 {
println!("cargo:rustc-cfg=ossl111");
}
if version >= 0x3_00_00_00_0 {
println!("cargo:rustc-cfg=ossl300");
}
}
if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") {
let version = u64::from_str_radix(&version, 16).unwrap();
if version >= 0x2_05_01_00_0 {
println!("cargo:rustc-cfg=libressl251");
}
if version >= 0x2_06_01_00_0 {
println!("cargo:rustc-cfg=libressl261");
}
if version >= 0x2_07_00_00_0 {
println!("cargo:rustc-cfg=libressl270");
}
if version >= 0x2_07_01_00_0 {
println!("cargo:rustc-cfg=libressl271");
}
if version >= 0x2_07_03_00_0 {
println!("cargo:rustc-cfg=libressl273");
}
if version >= 0x2_08_00_00_0 {
println!("cargo:rustc-cfg=libressl280");
}
if version >= 0x2_09_01_00_0 {
println!("cargo:rustc-cfg=libressl291");
}
if version >= 0x3_02_01_00_0 {
println!("cargo:rustc-cfg=libressl321");
}
if version >= 0x3_03_02_00_0 {
println!("cargo:rustc-cfg=libressl332");
}
if version >= 0x3_04_00_00_0 {
println!("cargo:rustc-cfg=libressl340");
}
if version >= 0x3_05_00_00_0 {
println!("cargo:rustc-cfg=libressl350");
}
if version >= 0x3_06_00_00_0 {
println!("cargo:rustc-cfg=libressl360");
}
if version >= 0x3_06_01_00_0 {
println!("cargo:rustc-cfg=libressl361");
}
}
}
-335
View File
@@ -1,335 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
// MacOS implementation of AES primitives since CommonCrypto seems to be faster than OpenSSL, especially on ARM64.
use std::os::raw::{c_int, c_void};
use std::ptr::{null, null_mut};
use std::sync::Mutex;
use zssp::crypto::aes::{self, AES_256_BLOCK_SIZE, AES_256_KEY_SIZE};
use zssp::crypto::aes_gcm::{self, AES_GCM_IV_SIZE, AES_GCM_TAG_SIZE};
#[allow(unused_imports)]
use crate::secure_eq;
#[allow(non_upper_case_globals, unused)]
const kCCModeECB: i32 = 1;
#[allow(non_upper_case_globals, unused)]
const kCCModeCTR: i32 = 4;
#[allow(non_upper_case_globals, unused)]
const kCCModeGCM: i32 = 11;
#[allow(non_upper_case_globals, unused)]
const kCCEncrypt: i32 = 0;
#[allow(non_upper_case_globals, unused)]
const kCCDecrypt: i32 = 1;
#[allow(non_upper_case_globals, unused)]
const kCCAlgorithmAES: i32 = 0;
#[allow(non_upper_case_globals, unused)]
const kCCOptionECBMode: i32 = 2;
extern "C" {
fn CCCryptorCreateWithMode(
op: i32,
mode: i32,
alg: i32,
padding: i32,
iv: *const c_void,
key: *const c_void,
key_len: usize,
tweak: *const c_void,
tweak_len: usize,
num_rounds: c_int,
options: i32,
cryyptor_ref: *mut *mut c_void,
) -> i32;
fn CCCryptorUpdate(
cryptor_ref: *mut c_void,
data_in: *const c_void,
data_in_len: usize,
data_out: *mut c_void,
data_out_len: usize,
data_out_written: *mut usize,
) -> i32;
//fn CCCryptorReset(cryptor_ref: *mut c_void, iv: *const c_void) -> i32;
fn CCCryptorRelease(cryptor_ref: *mut c_void) -> i32;
fn CCCryptorGCMSetIV(cryptor_ref: *mut c_void, iv: *const c_void, iv_len: usize) -> i32;
fn CCCryptorGCMAddAAD(cryptor_ref: *mut c_void, aad: *const c_void, len: usize) -> i32;
fn CCCryptorGCMEncrypt(
cryptor_ref: *mut c_void,
data_in: *const c_void,
data_in_len: usize,
data_out: *mut c_void,
) -> i32;
fn CCCryptorGCMDecrypt(
cryptor_ref: *mut c_void,
data_in: *const c_void,
data_in_len: usize,
data_out: *mut c_void,
) -> i32;
fn CCCryptorGCMFinal(cryptor_ref: *mut c_void, tag: *mut c_void, tag_len: *mut usize) -> i32;
fn CCCryptorGCMReset(cryptor_ref: *mut c_void) -> i32;
}
pub struct AesGcm<const ENCRYPT: bool>(*mut c_void);
impl<const ENCRYPT: bool> Drop for AesGcm<ENCRYPT> {
#[inline(always)]
fn drop(&mut self) {
unsafe { CCCryptorRelease(self.0) };
}
}
impl<const ENCRYPT: bool> AesGcm<ENCRYPT> {
pub fn new(k: &[u8; AES_256_KEY_SIZE]) -> Self {
unsafe {
let mut ptr: *mut c_void = null_mut();
assert_eq!(
CCCryptorCreateWithMode(
if ENCRYPT {
kCCEncrypt
} else {
kCCDecrypt
},
kCCModeGCM,
kCCAlgorithmAES,
0,
null(),
k.as_ptr().cast(),
AES_256_KEY_SIZE,
null(),
0,
0,
0,
&mut ptr,
),
0
);
AesGcm(ptr)
}
}
#[inline(always)]
pub fn reset_init_gcm(&mut self, iv: &[u8]) {
assert_eq!(iv.len(), AES_GCM_IV_SIZE);
unsafe {
assert_eq!(CCCryptorGCMReset(self.0), 0);
assert_eq!(CCCryptorGCMSetIV(self.0, iv.as_ptr().cast(), AES_GCM_IV_SIZE), 0);
}
}
#[inline(always)]
pub fn aad(&mut self, aad: &[u8]) {
unsafe {
assert_eq!(CCCryptorGCMAddAAD(self.0, aad.as_ptr().cast(), aad.len()), 0);
}
}
#[inline(always)]
pub fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
unsafe {
assert_eq!(input.len(), output.len());
if ENCRYPT {
assert_eq!(
CCCryptorGCMEncrypt(self.0, input.as_ptr().cast(), input.len(), output.as_mut_ptr().cast()),
0
);
} else {
assert_eq!(
CCCryptorGCMDecrypt(self.0, input.as_ptr().cast(), input.len(), output.as_mut_ptr().cast()),
0
);
}
}
}
#[inline(always)]
pub fn crypt_in_place(&mut self, data: &mut [u8]) {
unsafe {
if ENCRYPT {
assert_eq!(
CCCryptorGCMEncrypt(self.0, data.as_ptr().cast(), data.len(), data.as_mut_ptr().cast()),
0
);
} else {
assert_eq!(
CCCryptorGCMDecrypt(self.0, data.as_ptr().cast(), data.len(), data.as_mut_ptr().cast()),
0
);
}
}
}
#[inline(always)]
fn finish(&mut self, tag: &mut [u8; AES_GCM_TAG_SIZE]) {
unsafe {
let mut tag_len = AES_GCM_TAG_SIZE;
if CCCryptorGCMFinal(self.0, tag.as_mut_ptr().cast(), &mut tag_len) != 0 {
debug_assert!(false);
tag.fill(0);
}
}
}
}
pub struct Aes<const ENCRYPT: bool>(Mutex<*mut c_void>);
unsafe impl<const ENCRYPT: bool> Send for Aes<ENCRYPT> {}
unsafe impl<const ENCRYPT: bool> Sync for Aes<ENCRYPT> {}
impl<const ENCRYPT: bool> Drop for Aes<ENCRYPT> {
#[inline(always)]
fn drop(&mut self) {
let p = self.0.lock().unwrap();
unsafe {
CCCryptorRelease(*p);
}
}
}
impl<const ENCRYPT: bool> Aes<ENCRYPT> {
pub fn new(key: &[u8; AES_256_KEY_SIZE]) -> Self {
unsafe {
let mut p = null_mut();
assert_eq!(
CCCryptorCreateWithMode(
if ENCRYPT {
kCCEncrypt
} else {
kCCDecrypt
},
kCCModeECB,
kCCAlgorithmAES,
0,
null(),
key.as_ptr().cast(),
AES_256_KEY_SIZE,
null(),
0,
0,
kCCOptionECBMode,
&mut p,
),
0
);
Self(Mutex::new(p))
}
}
pub fn reset(&self, key: &[u8; AES_256_KEY_SIZE]) {
let mut p = self.0.lock().unwrap();
unsafe {
CCCryptorRelease(*p);
assert_eq!(
CCCryptorCreateWithMode(
if ENCRYPT {
kCCEncrypt
} else {
kCCDecrypt
},
kCCModeECB,
kCCAlgorithmAES,
0,
null(),
key.as_ptr().cast(),
AES_256_KEY_SIZE,
null(),
0,
0,
kCCOptionECBMode,
&mut *p,
),
0
);
}
}
#[inline(always)]
pub fn crypt_block_in_place(&self, data: &mut [u8]) {
assert_eq!(data.len(), AES_256_BLOCK_SIZE);
unsafe {
let mut data_out_written = 0;
let p = self.0.lock().unwrap();
CCCryptorUpdate(
*p,
data.as_ptr().cast(),
AES_256_BLOCK_SIZE,
data.as_mut_ptr().cast(),
AES_256_BLOCK_SIZE,
&mut data_out_written,
);
}
}
}
impl aes_gcm::AesGcmEnc for AesGcm<true> {
fn new(key: &[u8; aes_gcm::AES_GCM_KEY_SIZE]) -> Self {
Self::new(key)
}
fn set_iv(&mut self, iv: &[u8; aes_gcm::AES_GCM_IV_SIZE]) {
self.reset_init_gcm(iv)
}
fn set_aad(&mut self, aad: &[u8]) {
self.aad(aad)
}
fn encrypt(&mut self, input: &[u8], output: &mut [u8]) {
self.crypt(input, output)
}
fn encrypt_in_place(&mut self, data: &mut [u8]) {
self.crypt_in_place(data)
}
fn finish_encrypt(&mut self, output: &mut [u8; aes_gcm::AES_GCM_TAG_SIZE]) {
self.finish(output);
}
}
impl aes_gcm::AesGcmDec for AesGcm<false> {
fn new(key: &[u8; aes_gcm::AES_GCM_KEY_SIZE]) -> Self {
Self::new(key)
}
fn set_iv(&mut self, iv: &[u8; aes_gcm::AES_GCM_IV_SIZE]) {
self.reset_init_gcm(iv)
}
fn set_aad(&mut self, aad: &[u8]) {
self.aad(aad)
}
fn decrypt(&mut self, input: &[u8], output: &mut [u8]) {
self.crypt(input, output)
}
fn decrypt_in_place(&mut self, data: &mut [u8]) {
self.crypt_in_place(data)
}
fn finish_decrypt(&mut self, expected_tag: &[u8; aes_gcm::AES_GCM_TAG_SIZE]) -> bool {
let mut output = [0u8; aes_gcm::AES_GCM_TAG_SIZE];
self.finish(&mut output);
secure_eq(expected_tag, &output)
}
}
impl aes::AesEnc for Aes<true> {
fn new(key: &[u8; AES_256_KEY_SIZE]) -> Self {
Self::new(key)
}
fn reset(&self, key: &[u8; AES_256_KEY_SIZE]) {
self.reset(key)
}
fn encrypt_in_place(&self, block: &mut [u8; AES_256_BLOCK_SIZE]) {
self.crypt_block_in_place(block)
}
}
impl aes::AesDec for Aes<false> {
fn new(key: &[u8; AES_256_KEY_SIZE]) -> Self {
Self::new(key)
}
fn reset(&self, key: &[u8; AES_256_KEY_SIZE]) {
self.reset(key)
}
fn decrypt_in_place(&self, block: &mut [u8; AES_256_BLOCK_SIZE]) {
self.crypt_block_in_place(block)
}
}
-482
View File
@@ -1,482 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
// AES-GMAC-SIV implemented using MacOS/iOS CommonCrypto (MacOS 10.13 or newer required).
use std::os::raw::{c_int, c_void};
use std::ptr::{null, null_mut};
#[allow(non_upper_case_globals)]
const kCCModeECB: i32 = 1;
#[allow(non_upper_case_globals)]
const kCCModeCTR: i32 = 4;
#[allow(non_upper_case_globals)]
const kCCModeGCM: i32 = 11;
#[allow(non_upper_case_globals)]
const kCCEncrypt: i32 = 0;
#[allow(non_upper_case_globals)]
const kCCDecrypt: i32 = 1;
#[allow(non_upper_case_globals)]
const kCCAlgorithmAES: i32 = 0;
#[allow(non_upper_case_globals)]
const kCCOptionECBMode: i32 = 2;
extern "C" {
fn CCCryptorCreateWithMode(
op: i32,
mode: i32,
alg: i32,
padding: i32,
iv: *const c_void,
key: *const c_void,
key_len: usize,
tweak: *const c_void,
tweak_len: usize,
num_rounds: c_int,
options: i32,
cryyptor_ref: *mut *mut c_void,
) -> i32;
fn CCCryptorUpdate(
cryptor_ref: *mut c_void,
data_in: *const c_void,
data_in_len: usize,
data_out: *mut c_void,
data_out_len: usize,
data_out_written: *mut usize,
) -> i32;
fn CCCryptorReset(cryptor_ref: *mut c_void, iv: *const c_void) -> i32;
fn CCCryptorRelease(cryptor_ref: *mut c_void) -> i32;
fn CCCryptorGCMSetIV(cryptor_ref: *mut c_void, iv: *const c_void, iv_len: usize) -> i32;
fn CCCryptorGCMAddAAD(cryptor_ref: *mut c_void, aad: *const c_void, len: usize) -> i32;
fn CCCryptorGCMFinalize(cryptor_ref: *mut c_void, tag: *mut c_void, tag_len: usize) -> i32;
fn CCCryptorGCMReset(cryptor_ref: *mut c_void) -> i32;
}
pub struct AesCtr(*mut c_void);
impl Drop for AesCtr {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
CCCryptorRelease(self.0);
}
}
}
}
impl AesCtr {
/// Construct a new AES-CTR cipher.
/// Key must be 16, 24, or 32 bytes in length or a panic will occur.
pub fn new(k: &[u8]) -> Self {
if k.len() != 32 && k.len() != 24 && k.len() != 16 {
panic!("AES supports 128, 192, or 256 bits keys");
}
unsafe {
let mut ptr: *mut c_void = null_mut();
let result = CCCryptorCreateWithMode(
kCCEncrypt,
kCCModeCTR,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k.as_ptr().cast(),
k.len(),
null(),
0,
0,
0,
&mut ptr,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for CTR mode returned {}", result);
}
AesCtr(ptr)
}
}
/// Initialize AES-CTR for encryption or decryption with the given IV.
/// If it's already been used, this also resets the cipher. There is no separate reset.
pub fn init(&mut self, iv: &[u8]) {
unsafe {
if iv.len() == 16 {
if CCCryptorReset(self.0, iv.as_ptr().cast()) != 0 {
panic!("CCCryptorReset for CTR mode failed (old MacOS bug)");
}
} else if iv.len() < 16 {
let mut iv2 = [0_u8; 16];
iv2[0..iv.len()].copy_from_slice(iv);
if CCCryptorReset(self.0, iv2.as_ptr().cast()) != 0 {
panic!("CCCryptorReset for CTR mode failed (old MacOS bug)");
}
} else {
panic!("CTR IV must be less than or equal to 16 bytes in length");
}
}
}
/// Encrypt or decrypt (same operation with CTR mode)
#[inline(always)]
pub fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
unsafe {
assert!(output.len() >= input.len());
let mut data_out_written: usize = 0;
CCCryptorUpdate(
self.0,
input.as_ptr().cast(),
input.len(),
output.as_mut_ptr().cast(),
output.len(),
&mut data_out_written,
);
}
}
/// Encrypt or decrypt in place (same operation with CTR mode)
#[inline(always)]
pub fn crypt_in_place(&mut self, data: &mut [u8]) {
unsafe {
let mut data_out_written: usize = 0;
CCCryptorUpdate(
self.0,
data.as_ptr().cast(),
data.len(),
data.as_mut_ptr().cast(),
data.len(),
&mut data_out_written,
);
}
}
}
unsafe impl Send for AesCtr {}
#[repr(align(8))]
pub struct AesGmacSiv {
tag: [u8; 16],
tmp: [u8; 16],
ctr: *mut c_void,
ecb_enc: *mut c_void,
ecb_dec: *mut c_void,
gmac: *mut c_void,
}
impl Drop for AesGmacSiv {
fn drop(&mut self) {
unsafe {
if !self.ctr.is_null() {
CCCryptorRelease(self.ctr);
}
if !self.ecb_enc.is_null() {
CCCryptorRelease(self.ecb_enc);
}
if !self.ecb_dec.is_null() {
CCCryptorRelease(self.ecb_dec);
}
if !self.gmac.is_null() {
CCCryptorRelease(self.gmac);
}
}
}
}
impl AesGmacSiv {
/// Create a new keyed instance of AES-GMAC-SIV
/// The key may be of size 16, 24, or 32 bytes (128, 192, or 256 bits). Any other size will panic.
/// Two keys are required: one for GMAC and one for AES-CTR.
pub fn new(k0: &[u8], k1: &[u8]) -> Self {
if k0.len() != 32 && k0.len() != 24 && k0.len() != 16 {
panic!("AES supports 128, 192, or 256 bits keys");
}
if k1.len() != k0.len() {
panic!("k0 and k1 must be of the same size");
}
let mut c: AesGmacSiv = AesGmacSiv {
tag: [0_u8; 16],
tmp: [0_u8; 16],
ctr: null_mut(),
ecb_enc: null_mut(),
ecb_dec: null_mut(),
gmac: null_mut(),
};
unsafe {
let result = CCCryptorCreateWithMode(
kCCEncrypt,
kCCModeCTR,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k1.as_ptr().cast(),
k1.len(),
null(),
0,
0,
0,
&mut c.ctr,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for CTR mode returned {}", result);
}
let result = CCCryptorCreateWithMode(
kCCEncrypt,
kCCModeECB,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k1.as_ptr().cast(),
k1.len(),
null(),
0,
0,
kCCOptionECBMode,
&mut c.ecb_enc,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for ECB encrypt mode returned {}", result);
}
let result = CCCryptorCreateWithMode(
kCCDecrypt,
kCCModeECB,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k1.as_ptr().cast(),
k1.len(),
null(),
0,
0,
kCCOptionECBMode,
&mut c.ecb_dec,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for ECB decrypt mode returned {}", result);
}
let result = CCCryptorCreateWithMode(
kCCEncrypt,
kCCModeGCM,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k0.as_ptr().cast(),
k0.len(),
null(),
0,
0,
0,
&mut c.gmac,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for GCM (GMAC) mode returned {}", result);
}
}
c
}
/// Reset to prepare for another encrypt or decrypt operation.
#[inline(always)]
pub fn reset(&mut self) {
unsafe {
CCCryptorGCMReset(self.gmac);
}
}
/// Initialize for encryption.
#[inline(always)]
pub fn encrypt_init(&mut self, iv: &[u8]) {
self.tag[0..8].copy_from_slice(iv);
self.tag[8..12].fill(0);
unsafe {
CCCryptorGCMSetIV(self.gmac, self.tag.as_ptr().cast(), 12);
}
}
/// Set additional authenticated data (data to be authenticated but not encrypted).
/// This can currently only be called once. Multiple calls will result in corrupt data.
#[inline(always)]
pub fn encrypt_set_aad(&mut self, data: &[u8]) {
unsafe {
CCCryptorGCMAddAAD(self.gmac, data.as_ptr().cast(), data.len());
}
let pad = data.len() & 0xf;
if pad != 0 {
unsafe {
CCCryptorGCMAddAAD(self.gmac, crate::ZEROES.as_ptr().cast(), 16 - pad);
}
}
}
/// Feed plaintext in for the first encryption pass.
/// This may be called more than once.
#[inline(always)]
pub fn encrypt_first_pass(&mut self, plaintext: &[u8]) {
unsafe {
CCCryptorGCMAddAAD(self.gmac, plaintext.as_ptr().cast(), plaintext.len());
}
}
/// Finish first pass and begin second pass.
#[inline(always)]
pub fn encrypt_first_pass_finish(&mut self) {
unsafe {
CCCryptorGCMFinalize(self.gmac, self.tmp.as_mut_ptr().cast(), 16);
let tmp = self.tmp.as_mut_ptr().cast::<u64>();
*self.tag.as_mut_ptr().cast::<u64>().offset(1) = *tmp ^ *tmp.offset(1);
let mut data_out_written: usize = 0;
CCCryptorUpdate(
self.ecb_enc,
self.tag.as_ptr().cast(),
16,
self.tag.as_mut_ptr().cast(),
16,
&mut data_out_written,
);
}
self.tmp.copy_from_slice(&self.tag);
self.tmp[12] &= 0x7f;
unsafe {
if CCCryptorReset(self.ctr, self.tmp.as_ptr().cast()) != 0 {
panic!("CCCryptorReset for CTR mode failed (old MacOS bug)");
}
}
}
/// Feed plaintext for second pass and write ciphertext to supplied buffer.
/// This may be called more than once.
#[inline(always)]
pub fn encrypt_second_pass(&mut self, plaintext: &[u8], ciphertext: &mut [u8]) {
unsafe {
assert!(ciphertext.len() >= plaintext.len());
let mut data_out_written: usize = 0;
CCCryptorUpdate(
self.ctr,
plaintext.as_ptr().cast(),
plaintext.len(),
ciphertext.as_mut_ptr().cast(),
ciphertext.len(),
&mut data_out_written,
);
}
}
/// Encrypt plaintext in place.
/// This may be called more than once.
#[inline(always)]
pub fn encrypt_second_pass_in_place(&mut self, plaintext_to_ciphertext: &mut [u8]) {
unsafe {
let mut data_out_written: usize = 0;
CCCryptorUpdate(
self.ctr,
plaintext_to_ciphertext.as_ptr().cast(),
plaintext_to_ciphertext.len(),
plaintext_to_ciphertext.as_mut_ptr().cast(),
plaintext_to_ciphertext.len(),
&mut data_out_written,
);
}
}
/// Finish second pass and return a reference to the tag for this message.
/// The tag returned remains valid until reset() is called.
#[inline(always)]
pub fn encrypt_second_pass_finish(&mut self) -> &[u8; 16] {
return &self.tag;
}
#[inline(always)]
fn decrypt_init_internal(&mut self) {
self.tmp[12] &= 0x7f;
unsafe {
if CCCryptorReset(self.ctr, self.tmp.as_ptr().cast()) != 0 {
panic!("CCCryptorReset for CTR mode failed (old MacOS bug)");
}
let mut data_out_written = 0;
CCCryptorUpdate(
self.ecb_dec,
self.tag.as_ptr().cast(),
16,
self.tag.as_mut_ptr().cast(),
16,
&mut data_out_written,
);
let tmp = self.tmp.as_mut_ptr().cast::<u64>();
*tmp = *self.tag.as_mut_ptr().cast::<u64>();
*tmp.add(1) = 0;
CCCryptorGCMSetIV(self.gmac, self.tmp.as_ptr().cast(), 12);
}
}
/// Initialize this cipher for decryption.
/// The supplied tag must be 16 bytes in length. Any other length will panic.
#[inline(always)]
pub fn decrypt_init(&mut self, tag: &[u8]) {
self.tmp.copy_from_slice(tag);
self.tag.copy_from_slice(tag);
self.decrypt_init_internal();
}
/// Set additional authenticated data to be checked.
#[inline(always)]
pub fn decrypt_set_aad(&mut self, data: &[u8]) {
self.encrypt_set_aad(data);
}
/// Decrypt ciphertext and write to plaintext.
/// This may be called more than once.
#[inline(always)]
pub fn decrypt(&mut self, ciphertext: &[u8], plaintext: &mut [u8]) {
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(
self.ctr,
ciphertext.as_ptr().cast(),
ciphertext.len(),
plaintext.as_mut_ptr().cast(),
plaintext.len(),
&mut data_out_written,
);
CCCryptorGCMAddAAD(self.gmac, plaintext.as_ptr().cast(), plaintext.len());
}
}
/// Decrypt ciphertext in place.
/// This may be called more than once.
#[inline(always)]
pub fn decrypt_in_place(&mut self, ciphertext_to_plaintext: &mut [u8]) {
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(
self.ctr,
ciphertext_to_plaintext.as_ptr().cast(),
ciphertext_to_plaintext.len(),
ciphertext_to_plaintext.as_mut_ptr().cast(),
ciphertext_to_plaintext.len(),
&mut data_out_written,
);
CCCryptorGCMAddAAD(
self.gmac,
ciphertext_to_plaintext.as_ptr().cast(),
ciphertext_to_plaintext.len(),
);
}
}
/// Finish decryption and returns the decrypted tag if the message appears valid.
#[inline(always)]
pub fn decrypt_finish(&mut self) -> Option<&[u8; 16]> {
unsafe {
CCCryptorGCMFinalize(self.gmac, self.tmp.as_mut_ptr().cast(), 16);
let tmp = self.tmp.as_mut_ptr().cast::<u64>();
if *self.tag.as_mut_ptr().cast::<u64>().offset(1) == *tmp ^ *tmp.offset(1) {
Some(&self.tag)
} else {
None
}
}
}
}
unsafe impl Send for AesGmacSiv {}
-183
View File
@@ -1,183 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::{ptr, sync::Mutex};
use zssp::crypto::{aes, aes_gcm};
use crate::cipher_ctx::CipherCtx;
/// An OpenSSL AES_GCM context. Automatically frees itself on drop.
/// The current interface is custom made for ZeroTier, but could easily be adapted for other uses.
/// Whether `ENCRYPT` is true or false decides respectively whether this context encrypts or decrypts.
/// Even though OpenSSL lets you set this dynamically almost no operations work when you do this
/// without resetting the context.
///
/// This object cannot be mutated by multiple threads at the same time so wrap it in a Mutex if
/// you need to do this. As far as I have read a Mutex<AesGcm> can safely implement Send and Sync.
pub struct AesGcm<const ENCRYPT: bool>(CipherCtx);
impl<const ENCRYPT: bool> AesGcm<ENCRYPT> {
/// Create an AesGcm context with the given key.
/// OpenSSL internally processes and caches this key, so it is recommended to reuse this context whenever encrypting under the same key. Call `reset_init_gcm` to change the IV for each reuse.
fn new(key: &[u8; aes_gcm::AES_GCM_KEY_SIZE]) -> Self {
let ctx = CipherCtx::new().unwrap();
unsafe {
let t = ffi::EVP_aes_256_gcm();
ctx.cipher_init::<ENCRYPT>(t, key.as_ptr(), ptr::null()).unwrap();
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0);
}
AesGcm(ctx)
}
/// Set the IV of this AesGcm context. This call resets the IV but leaves the key and encryption algorithm alone.
/// This method must be called before any other method on AesGcm.
/// `iv` must be exactly 12 bytes in length, because that is what Aes supports.
fn reset_init_gcm(&mut self, iv: &[u8]) {
unsafe {
self.0
.cipher_init::<ENCRYPT>(ptr::null(), ptr::null(), iv.as_ptr())
.unwrap();
}
}
/// Add additional authentication data to AesGcm (same operation with CTR mode).
#[inline(always)]
fn aad(&mut self, aad: &[u8]) {
unsafe { self.0.update::<ENCRYPT>(aad, ptr::null_mut()).unwrap() };
}
/// Encrypt or decrypt (same operation with CTR mode)
#[inline(always)]
fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
unsafe { self.0.update::<ENCRYPT>(input, output.as_mut_ptr()).unwrap() };
}
/// Encrypt or decrypt in place (same operation with CTR mode).
#[inline(always)]
fn crypt_in_place(&mut self, data: &mut [u8]) {
let ptr = data.as_mut_ptr();
unsafe { self.0.update::<ENCRYPT>(data, ptr).unwrap() }
}
}
impl AesGcm<true> {
/// Produce the gcm authentication tag.
#[inline(always)]
fn finish_encrypt(&mut self, output: &mut [u8; aes_gcm::AES_GCM_TAG_SIZE]) {
unsafe {
self.0.finalize::<true>().unwrap();
self.0.tag(output).unwrap();
}
}
}
impl AesGcm<false> {
/// Check the gcm authentication tag. Outputs true if it matches the just decrypted message, outputs false otherwise.
#[inline(always)]
fn finish_decrypt(&mut self, expected_tag: &[u8; aes_gcm::AES_GCM_TAG_SIZE]) -> bool {
unsafe { self.0.set_tag(expected_tag).is_ok() && self.0.finalize::<false>().is_ok() }
}
}
impl aes_gcm::AesGcmEnc for AesGcm<true> {
fn new(key: &[u8; aes_gcm::AES_GCM_KEY_SIZE]) -> Self {
Self::new(key)
}
fn set_iv(&mut self, iv: &[u8; aes_gcm::AES_GCM_IV_SIZE]) {
self.reset_init_gcm(iv)
}
fn set_aad(&mut self, aad: &[u8]) {
self.aad(aad)
}
fn encrypt(&mut self, input: &[u8], output: &mut [u8]) {
self.crypt(input, output)
}
fn encrypt_in_place(&mut self, data: &mut [u8]) {
self.crypt_in_place(data)
}
fn finish_encrypt(&mut self, output: &mut [u8; aes_gcm::AES_GCM_TAG_SIZE]) {
self.finish_encrypt(output)
}
}
impl aes_gcm::AesGcmDec for AesGcm<false> {
fn new(key: &[u8; aes_gcm::AES_GCM_KEY_SIZE]) -> Self {
Self::new(key)
}
fn set_iv(&mut self, iv: &[u8; aes_gcm::AES_GCM_IV_SIZE]) {
self.reset_init_gcm(iv)
}
fn set_aad(&mut self, aad: &[u8]) {
self.aad(aad)
}
fn decrypt(&mut self, input: &[u8], output: &mut [u8]) {
self.crypt(input, output)
}
fn decrypt_in_place(&mut self, data: &mut [u8]) {
self.crypt_in_place(data)
}
fn finish_decrypt(&mut self, expected_tag: &[u8; aes_gcm::AES_GCM_TAG_SIZE]) -> bool {
self.finish_decrypt(expected_tag)
}
}
/// An OpenSSL AES_ECB context. Automatically frees itself on drop.
/// AES_ECB is very insecure if used incorrectly so its public interface supports only exactly what
/// ZeroTier uses it for.
pub struct Aes<const ENCRYPT: bool>(Mutex<CipherCtx>);
unsafe impl<const ENCRYPT: bool> Send for Aes<ENCRYPT> {}
unsafe impl<const ENCRYPT: bool> Sync for Aes<ENCRYPT> {}
impl<const ENCRYPT: bool> Aes<ENCRYPT> {
fn new(key: &[u8; aes::AES_256_KEY_SIZE]) -> Self {
let ctx = CipherCtx::new().unwrap();
unsafe {
let t = ffi::EVP_aes_256_ecb();
ctx.cipher_init::<ENCRYPT>(t, key.as_ptr(), ptr::null()).unwrap();
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0);
}
Aes(Mutex::new(ctx))
}
fn reset(&self, key: &[u8; aes::AES_256_KEY_SIZE]) {
let ctx = self.0.lock().unwrap();
unsafe {
ctx.cipher_init::<ENCRYPT>(ptr::null(), key.as_ptr(), ptr::null())
.unwrap();
}
}
}
impl aes::AesEnc for Aes<true> {
fn new(key: &[u8; aes::AES_256_KEY_SIZE]) -> Self {
Self::new(key)
}
fn reset(&self, key: &[u8; aes::AES_256_KEY_SIZE]) {
self.reset(key)
}
fn encrypt_in_place(&self, block: &mut [u8; aes::AES_256_BLOCK_SIZE]) {
let ptr = block.as_mut_ptr();
let ctx = self.0.lock().unwrap();
unsafe { ctx.update::<true>(block, ptr).unwrap() }
}
}
impl aes::AesDec for Aes<false> {
fn new(key: &[u8; aes::AES_256_KEY_SIZE]) -> Self {
Self::new(key)
}
fn reset(&self, key: &[u8; aes::AES_256_KEY_SIZE]) {
self.reset(key)
}
fn decrypt_in_place(&self, block: &mut [u8; aes::AES_256_BLOCK_SIZE]) {
let ptr = block.as_mut_ptr();
let ctx = self.0.lock().unwrap();
unsafe { ctx.update::<false>(block, ptr).unwrap() }
}
}
-210
View File
@@ -1,210 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::ptr::{self, NonNull};
use crate::error::{cvt, cvt_p, ErrorStack};
use libc::{c_int, c_void};
extern "C" {
fn EVP_CIPHER_CTX_free(ctx: *mut ffi::EVP_CIPHER_CTX);
fn EVP_CIPHER_CTX_new() -> *mut ffi::EVP_CIPHER_CTX;
fn EVP_EncryptInit_ex(
ctx: *mut ffi::EVP_CIPHER_CTX,
cipher: *const ffi::EVP_CIPHER,
engine: *mut c_void,
key: *const u8,
iv: *const u8,
) -> c_int;
fn EVP_DecryptInit_ex(
ctx: *mut ffi::EVP_CIPHER_CTX,
cipher: *const ffi::EVP_CIPHER,
engine: *mut c_void,
key: *const u8,
iv: *const u8,
) -> c_int;
fn EVP_EncryptUpdate(
ctx: *mut ffi::EVP_CIPHER_CTX,
out: *mut u8,
outl: *mut c_int,
in_: *const u8,
inl: c_int,
) -> c_int;
fn EVP_DecryptUpdate(
ctx: *mut ffi::EVP_CIPHER_CTX,
out: *mut u8,
outl: *mut c_int,
in_: *const u8,
inl: c_int,
) -> c_int;
fn EVP_EncryptFinal_ex(ctx: *mut ffi::EVP_CIPHER_CTX, out: *mut u8, outl: *mut c_int) -> c_int;
fn EVP_DecryptFinal_ex(ctx: *mut ffi::EVP_CIPHER_CTX, out: *mut u8, outl: *mut c_int) -> c_int;
fn EVP_CIPHER_CTX_ctrl(ctx: *mut ffi::EVP_CIPHER_CTX, type_: c_int, arg: c_int, ptr: *mut c_void) -> c_int;
}
pub struct CipherCtx(NonNull<ffi::EVP_CIPHER_CTX>);
impl Drop for CipherCtx {
fn drop(&mut self) {
unsafe {
EVP_CIPHER_CTX_free(self.0.as_ptr());
}
}
}
impl CipherCtx {
/// Creates a new context.
pub fn new() -> Result<Self, ErrorStack> {
unsafe {
let ptr = cvt_p(EVP_CIPHER_CTX_new())?;
Ok(CipherCtx(NonNull::new_unchecked(ptr)))
}
}
}
impl CipherCtx {
/// Initializes the context for encryption or decryption.
/// All pointer fields can be null, in which case the corresponding field in the context is not updated.
pub unsafe fn cipher_init<const ENCRYPT: bool>(
&self,
t: *const ffi::EVP_CIPHER,
key: *const u8,
iv: *const u8,
) -> Result<(), ErrorStack> {
let evp_f = if ENCRYPT {
EVP_EncryptInit_ex
} else {
EVP_DecryptInit_ex
};
// OpenSSL will usually leak a static amount of memory per cipher given here.
cvt(evp_f(self.0.as_ptr(), t, ptr::null_mut(), key, iv))?;
Ok(())
}
/// Writes data into the context.
///
/// Providing no output buffer will cause the input to be considered additional authenticated data (AAD).
///
/// Returns the number of bytes written to `output`.
///
/// This function is the same as [`Self::cipher_update`] but with the
/// output size check removed. It can be used when the exact
/// buffer size control is maintained by the caller.
///
/// SAFETY: The caller is expected to provide `output` buffer
/// large enough to contain correct number of bytes. For streaming
/// ciphers the output buffer size should be at least as big as
/// the input buffer. For block ciphers the size of the output
/// buffer depends on the state of partially updated blocks.
pub unsafe fn update<const ENCRYPT: bool>(&self, input: &[u8], output: *mut u8) -> Result<(), ErrorStack> {
let evp_f = if ENCRYPT {
EVP_EncryptUpdate
} else {
EVP_DecryptUpdate
};
let mut outlen = 0;
cvt(evp_f(
self.0.as_ptr(),
output,
&mut outlen,
input.as_ptr(),
input.len() as c_int,
))?;
Ok(())
}
/// Finalizes the encryption or decryption process.
///
/// Any remaining data will be written to the output buffer.
///
/// Returns the number of bytes written to `output`.
///
/// This function is the same as [`Self::cipher_final`] but with
/// the output buffer size check removed.
pub unsafe fn finalize<const ENCRYPT: bool>(&self) -> Result<(), ErrorStack> {
let evp_f = if ENCRYPT {
EVP_EncryptFinal_ex
} else {
EVP_DecryptFinal_ex
};
let mut outl = 0;
cvt(evp_f(self.0.as_ptr(), ptr::null_mut(), &mut outl))?;
Ok(())
}
/// Retrieves the calculated authentication tag from the context.
///
/// This should be called after [`Self::cipher_final`], and is only supported by authenticated ciphers.
///
/// The size of the buffer indicates the size of the tag. While some ciphers support a range of tag sizes, it is
/// recommended to pick the maximum size.
pub fn tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> {
unsafe {
cvt(EVP_CIPHER_CTX_ctrl(
self.0.as_ptr(),
ffi::EVP_CTRL_GCM_GET_TAG,
tag.len() as c_int,
tag.as_mut_ptr() as *mut _,
))?;
}
Ok(())
}
/// Sets the authentication tag for verification during decryption.
#[allow(unused)]
pub fn set_tag(&self, tag: &[u8]) -> Result<(), ErrorStack> {
unsafe {
cvt(EVP_CIPHER_CTX_ctrl(
self.0.as_ptr(),
ffi::EVP_CTRL_GCM_SET_TAG,
tag.len() as c_int,
tag.as_ptr() as *mut _,
))?;
}
Ok(())
}
pub fn as_ptr(&self) -> *mut ffi::EVP_CIPHER_CTX {
self.0.as_ptr()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn aes_128_ecb() {
let key = [1u8; 16];
let ctx = CipherCtx::new().unwrap();
unsafe {
ctx.cipher_init::<true>(ffi::EVP_aes_128_ecb(), key.as_ptr(), ptr::null())
.unwrap();
ffi::EVP_CIPHER_CTX_set_padding(ctx.as_ptr(), 0);
assert_eq!(ffi::EVP_CIPHER_CTX_get_block_size(ctx.as_ptr()) as usize, 16);
let origin = [2u8; 16];
let mut val = origin;
let p = val.as_mut_ptr();
ctx.update::<true>(&val, p).unwrap();
ctx.cipher_init::<false>(ptr::null(), key.as_ptr(), ptr::null())
.unwrap();
ctx.update::<false>(&val, p).unwrap();
assert_eq!(val, origin);
}
}
}
-364
View File
@@ -1,364 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use cfg_if::cfg_if;
use libc::{c_char, c_int};
use std::borrow::Cow;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::io;
use std::ptr;
use std::str;
type ErrType = libc::c_ulong;
/// Collection of [`Error`]s from OpenSSL.
///
/// [`Error`]: struct.Error.html
#[derive(Debug, Clone)]
pub struct ErrorStack(Vec<Error>);
impl ErrorStack {
/// Returns the contents of the OpenSSL error stack.
#[cold]
#[inline(never)]
pub fn get() -> ErrorStack {
let mut vec = vec![];
while let Some(err) = Error::get() {
vec.push(err);
}
ErrorStack(vec)
}
/// Pushes the errors back onto the OpenSSL error stack.
pub fn put(&self) {
for error in self.errors() {
error.put();
}
}
}
impl ErrorStack {
/// Returns the errors in the stack.
pub fn errors(&self) -> &[Error] {
&self.0
}
}
impl fmt::Display for ErrorStack {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.is_empty() {
return fmt.write_str("OpenSSL error");
}
let mut first = true;
for err in &self.0 {
if !first {
fmt.write_str(", ")?;
}
write!(fmt, "{}", err)?;
first = false;
}
Ok(())
}
}
impl error::Error for ErrorStack {}
impl From<ErrorStack> for io::Error {
fn from(e: ErrorStack) -> io::Error {
io::Error::new(io::ErrorKind::Other, e)
}
}
impl From<ErrorStack> for fmt::Error {
fn from(_: ErrorStack) -> fmt::Error {
fmt::Error
}
}
/// An error reported from OpenSSL.
#[derive(Clone)]
pub struct Error {
code: ErrType,
file: ShimStr,
line: c_int,
func: Option<ShimStr>,
data: Option<Cow<'static, str>>,
}
unsafe impl Sync for Error {}
unsafe impl Send for Error {}
impl Error {
/// Returns the first error on the OpenSSL error stack.
pub fn get() -> Option<Error> {
unsafe {
let mut file = ptr::null();
let mut line = 0;
let mut func = ptr::null();
let mut data = ptr::null();
let mut flags = 0;
match ERR_get_error_all(&mut file, &mut line, &mut func, &mut data, &mut flags) {
0 => None,
code => {
// The memory referenced by data is only valid until that slot is overwritten
// in the error stack, so we'll need to copy it off if it's dynamic
let data = if flags & ffi::ERR_TXT_STRING != 0 {
let bytes = CStr::from_ptr(data as *const _).to_bytes();
let data = str::from_utf8(bytes).unwrap();
#[cfg(not(boringssl))]
let data = if flags & ffi::ERR_TXT_MALLOCED != 0 {
Cow::Owned(data.to_string())
} else {
Cow::Borrowed(data)
};
#[cfg(boringssl)]
let data = Cow::Borrowed(data);
Some(data)
} else {
None
};
let file = ShimStr::new(file);
let func = if func.is_null() {
None
} else {
Some(ShimStr::new(func))
};
Some(Error { code, file, line, func, data })
}
}
}
}
/// Pushes the error back onto the OpenSSL error stack.
pub fn put(&self) {
self.put_error();
unsafe {
let data = match self.data {
Some(Cow::Borrowed(data)) => Some((data.as_ptr() as *mut c_char, 0)),
Some(Cow::Owned(ref data)) => {
let ptr = ffi::CRYPTO_malloc(
(data.len() + 1) as _,
concat!(file!(), "\0").as_ptr() as _,
line!() as _,
) as *mut c_char;
if ptr.is_null() {
None
} else {
ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len());
*ptr.add(data.len()) = 0;
Some((ptr, ffi::ERR_TXT_MALLOCED))
}
}
None => None,
};
if let Some((ptr, flags)) = data {
ffi::ERR_set_error_data(ptr, flags | ffi::ERR_TXT_STRING);
}
}
}
#[cfg(ossl300)]
fn put_error(&self) {
unsafe {
ffi::ERR_new();
ffi::ERR_set_debug(
self.file.as_ptr(),
self.line,
self.func.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
);
ffi::ERR_set_error(ffi::ERR_GET_LIB(self.code), ffi::ERR_GET_REASON(self.code), ptr::null());
}
}
/// Returns the raw OpenSSL error code for this error.
pub fn code(&self) -> ErrType {
self.code
}
/// Returns the name of the library reporting the error, if available.
pub fn library(&self) -> Option<&'static str> {
unsafe {
let cstr = ffi::ERR_lib_error_string(self.code);
if cstr.is_null() {
return None;
}
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
Some(str::from_utf8(bytes).unwrap())
}
}
/// Returns the name of the function reporting the error.
pub fn function(&self) -> Option<RetStr<'_>> {
self.func.as_ref().map(|s| s.as_str())
}
/// Returns the reason for the error.
pub fn reason(&self) -> Option<&'static str> {
unsafe {
let cstr = ffi::ERR_reason_error_string(self.code);
if cstr.is_null() {
return None;
}
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
Some(str::from_utf8(bytes).unwrap())
}
}
/// Returns the name of the source file which encountered the error.
pub fn file(&self) -> RetStr<'_> {
self.file.as_str()
}
/// Returns the line in the source file which encountered the error.
pub fn line(&self) -> u32 {
self.line as u32
}
/// Returns additional data describing the error.
#[allow(clippy::option_as_ref_deref)]
pub fn data(&self) -> Option<&str> {
self.data.as_ref().map(|s| &**s)
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = fmt.debug_struct("Error");
builder.field("code", &self.code());
if let Some(library) = self.library() {
builder.field("library", &library);
}
if let Some(function) = self.function() {
builder.field("function", &function);
}
if let Some(reason) = self.reason() {
builder.field("reason", &reason);
}
builder.field("file", &self.file());
builder.field("line", &self.line());
if let Some(data) = self.data() {
builder.field("data", &data);
}
builder.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "error:{:08X}", self.code())?;
match self.library() {
Some(l) => write!(fmt, ":{}", l)?,
None => write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))?,
}
match self.function() {
Some(f) => write!(fmt, ":{}", f)?,
None => write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))?,
}
match self.reason() {
Some(r) => write!(fmt, ":{}", r)?,
None => write!(fmt, ":reason({})", ffi::ERR_GET_REASON(self.code()))?,
}
write!(fmt, ":{}:{}:{}", self.file(), self.line(), self.data().unwrap_or(""))
}
}
impl error::Error for Error {}
cfg_if! {
if #[cfg(ossl300)] {
use std::ffi::{CString};
use ffi::ERR_get_error_all;
type RetStr<'a> = &'a str;
#[derive(Clone)]
struct ShimStr(CString);
impl ShimStr {
unsafe fn new(s: *const c_char) -> Self {
ShimStr(CStr::from_ptr(s).to_owned())
}
fn as_ptr(&self) -> *const c_char {
self.0.as_ptr()
}
fn as_str(&self) -> &str {
self.0.to_str().unwrap()
}
}
} else {
#[allow(bad_style)]
unsafe extern "C" fn ERR_get_error_all(
file: *mut *const c_char,
line: *mut c_int,
func: *mut *const c_char,
data: *mut *const c_char,
flags: *mut c_int,
) -> ErrType {
let code = ffi::ERR_get_error_line_data(file, line, data, flags);
*func = ffi::ERR_func_error_string(code);
code
}
type RetStr<'a> = &'static str;
#[derive(Clone)]
struct ShimStr(*const c_char);
impl ShimStr {
unsafe fn new(s: *const c_char) -> Self {
ShimStr(s)
}
fn as_ptr(&self) -> *const c_char {
self.0
}
fn as_str(&self) -> &'static str {
unsafe {
CStr::from_ptr(self.0).to_str().unwrap()
}
}
}
}
}
#[inline]
pub fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
if r.is_null() {
Err(ErrorStack::get())
} else {
Ok(r)
}
}
#[inline]
pub fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
if r <= 0 {
Err(ErrorStack::get())
} else {
Ok(r)
}
}
#[inline]
pub fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
if r < 0 {
Err(ErrorStack::get())
} else {
Ok(r)
}
}
File diff suppressed because it is too large Load Diff
-156
View File
@@ -1,156 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::sync::Mutex;
use libc::c_int;
use once_cell::unsync::Lazy;
use rand_xoshiro::rand_core::{CryptoRng, Error, RngCore, SeedableRng};
use crate::error::cvt;
/// Fill buffer with cryptographically strong pseudo-random bytes.
#[inline]
pub fn fill_bytes_secure(dest: &mut [u8]) {
unsafe {
debug_assert!(dest.len() <= c_int::max_value() as usize);
cvt(ffi::RAND_bytes(dest.as_mut_ptr(), dest.len() as c_int)).unwrap();
}
}
pub fn next_u32_secure() -> u32 {
let mut tmp = [0u8; 4];
fill_bytes_secure(&mut tmp);
u32::from_ne_bytes(tmp)
}
pub fn next_u64_secure() -> u64 {
let mut tmp = [0u8; 8];
fill_bytes_secure(&mut tmp);
u64::from_ne_bytes(tmp)
}
pub fn next_u128_secure() -> u128 {
let mut tmp = [0u8; 16];
fill_bytes_secure(&mut tmp);
u128::from_ne_bytes(tmp)
}
#[inline(always)]
pub fn get_bytes_secure<const COUNT: usize>() -> [u8; COUNT] {
let mut tmp = [0u8; COUNT];
fill_bytes_secure(&mut tmp);
tmp
}
pub struct SecureRandom;
impl Default for SecureRandom {
#[inline(always)]
fn default() -> Self {
Self
}
}
impl SecureRandom {
#[inline(always)]
pub fn get() -> Self {
Self
}
}
impl RngCore for SecureRandom {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
next_u32_secure()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
next_u64_secure()
}
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
fill_bytes_secure(dest);
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
fill_bytes_secure(dest);
Ok(())
}
}
/// ed25519-dalek still uses rand_core 0.5.1, and that version is incompatible with 0.6.4, so we need to import and implement both.
impl rand_core_051::RngCore for SecureRandom {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
next_u32_secure()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
next_u64_secure()
}
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
fill_bytes_secure(dest);
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_051::Error> {
fill_bytes_secure(dest);
Ok(())
}
}
impl CryptoRng for SecureRandom {}
impl rand_core_051::CryptoRng for SecureRandom {}
unsafe impl Sync for SecureRandom {}
unsafe impl Send for SecureRandom {}
/// This crate contains the most modern, feature rich and high-quality variants of the Xorshift family of random
/// number generators.
/// While they are not cryptographically secure, they are also faster and several times harder to
/// reverse than Xorshift64, so I think we should prefer them.
/// I read the source of this crate and it is low level and efficient.
pub use rand_xoshiro;
/// Xoshiro256** according to my benchmarking is surprisingly twice as fast as vanilla
/// Xorshift64 because there are fewer dependency chains in Xoshiro256** compared to Xorshift64.
pub use rand_xoshiro::Xoshiro256StarStar;
/// A global Xoshiro256** wrapped in a mutex and a OnceCell.
/// Unsync OnceCell is just a wrapped `Option<>` and is very fast.
/// Also OnceCell is about to be stabilized into Rust std.
pub static GLOBAL_XORSHIFT: Mutex<Lazy<Xoshiro256StarStar>> =
Mutex::new(Lazy::new(|| Xoshiro256StarStar::from_rng(SecureRandom).unwrap()));
/// Quickly creates a new Xoshiro256StarStar state that is randomly seeded and fully owned by the
/// caller (does not require dereferencing and locking a global variable).
#[inline]
pub fn new_xorshift_rng() -> Xoshiro256StarStar {
let mut state = GLOBAL_XORSHIFT.lock().unwrap();
let ret = state.clone();
state.jump();
ret
}
/// Generate a random 64-bit number (not cryptographically secure).
#[inline]
pub fn next_u64_xorshift() -> u64 {
GLOBAL_XORSHIFT.lock().unwrap().next_u64()
}
/// Generate a random 32-bit number (not cryptographically secure).
/// Internally this generates a 64-bit number and uses the top-most bits,
/// since they are slightlyhigher quality randomness.
#[inline]
pub fn next_u32_xorshift() -> u32 {
GLOBAL_XORSHIFT.lock().unwrap().next_u32()
}
-137
View File
@@ -1,137 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::{convert::TryInto, ffi::c_void};
extern "C" {
fn OPENSSL_cleanse(ptr: *mut c_void, len: usize);
}
/// Container for secrets that clears them on drop.
///
/// We can't be totally sure that things like libraries are doing this and it's
/// hard to get every use of a secret anywhere, but using this in our code at
/// least reduces the number of secrets that are left lying around in memory.
///
/// This is generally a low-risk thing since it's process memory that's protected,
/// but it's still not a bad idea due to things like swap or obscure side channel
/// attacks that allow memory to be read.
#[derive(Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Secret<const L: usize>(pub [u8; L]);
impl<const L: usize> Secret<L> {
/// Create a new all-zero secret.
#[inline(always)]
pub fn new() -> Self {
Self([0_u8; L])
}
/// Moves bytes into secret, will panic if the slice does not match the size of this secret.
#[inline(always)]
pub fn move_bytes(b: [u8; L]) -> Self {
Self(b)
}
/// Copy bytes into secret, then nuke the previous value, will panic if the slice does not match the size of this secret.
#[inline(always)]
pub fn from_bytes_then_nuke(b: &mut [u8]) -> Self {
let ret = Self(b.try_into().unwrap());
unsafe { OPENSSL_cleanse(b.as_mut_ptr().cast(), L) };
ret
}
#[inline(always)]
pub unsafe fn from_bytes(b: &[u8]) -> Self {
Self(b.try_into().unwrap())
}
#[inline(always)]
pub fn as_bytes(&self) -> &[u8; L] {
&self.0
}
#[inline(always)]
pub fn as_ptr(&self) -> *const u8 {
self.0.as_ptr()
}
#[inline(always)]
pub fn as_bytes_mut(&mut self) -> &mut [u8; L] {
&mut self.0
}
/// Get the first N bytes of this secret as a fixed length array.
#[inline(always)]
pub fn first_n<const N: usize>(&self) -> &[u8; N] {
assert!(N <= L);
unsafe { &*self.0.as_ptr().cast() }
}
/// Clone the first N bytes of this secret as another secret.
#[inline(always)]
pub fn first_n_clone<const N: usize>(&self) -> Secret<N> {
Secret::<N>(*self.first_n())
}
pub fn overwrite(&mut self, src: &Self) {
self.0.copy_from_slice(&src.0);
}
pub fn overwrite_first_n<const N: usize>(&mut self, src: &Secret<N>) {
let amount = N.min(L);
self.0[..amount].copy_from_slice(&src.0[..amount]);
}
/// Destroy the contents of this secret, ignoring normal Rust mutability constraints.
///
/// This can be used to force a secret to be forgotten under e.g. key lifetime exceeded or error conditions.
#[inline(always)]
pub fn nuke(&self) {
unsafe { OPENSSL_cleanse(self.0.as_ptr().cast_mut().cast(), L) };
}
}
impl<const L: usize> Drop for Secret<L> {
#[inline(always)]
fn drop(&mut self) {
unsafe { OPENSSL_cleanse(self.0.as_mut_ptr().cast(), L) };
}
}
impl<const L: usize> Default for Secret<L> {
#[inline(always)]
fn default() -> Self {
Self([0_u8; L])
}
}
impl<const L: usize> AsRef<[u8]> for Secret<L> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl<const L: usize> AsRef<[u8; L]> for Secret<L> {
#[inline(always)]
fn as_ref(&self) -> &[u8; L] {
&self.0
}
}
impl<const L: usize> AsMut<[u8]> for Secret<L> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl<const L: usize> AsMut<[u8; L]> for Secret<L> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8; L] {
&mut self.0
}
}
-181
View File
@@ -1,181 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::convert::TryInto;
use std::io::Write;
use ed25519_dalek::Digest;
use crate::random::SecureRandom;
use crate::secret::Secret;
pub const C25519_PUBLIC_KEY_SIZE: usize = 32;
pub const C25519_SECRET_KEY_SIZE: usize = 32;
pub const C25519_SHARED_SECRET_SIZE: usize = 32;
pub const ED25519_PUBLIC_KEY_SIZE: usize = 32;
pub const ED25519_SECRET_KEY_SIZE: usize = 32;
pub const ED25519_SIGNATURE_SIZE: usize = 64;
/// Curve25519 key pair for ECDH key agreement.
pub struct X25519KeyPair(x25519_dalek::StaticSecret, Secret<32>, x25519_dalek::PublicKey);
impl X25519KeyPair {
pub fn generate() -> X25519KeyPair {
let sk = x25519_dalek::StaticSecret::new(SecureRandom::get());
let sk2 = Secret(sk.to_bytes());
let pk = x25519_dalek::PublicKey::from(&sk);
X25519KeyPair(sk, sk2, pk)
}
pub fn from_bytes(public_key: &[u8], secret_key: &[u8]) -> Option<X25519KeyPair> {
if public_key.len() == 32 && secret_key.len() == 32 {
/* NOTE: we keep the original secret separately from x25519_dalek's StaticSecret
* due to how "clamping" is done in the old C++ code vs x25519_dalek. Clamping
* is explained here:
*
* https://www.jcraige.com/an-explainer-on-ed25519-clamping
*
* The old code does clamping at the time of use. In other words the code that
* performs things like key agreement or signing clamps the secret before doing
* the operation. The x25519_dalek code does clamping at generation or when
* from() is used to get a key from a raw byte array.
*
* Unfortunately this introduces issues when interoperating with old code. The
* old system generates secrets that are not clamped (since they're clamped at
* use!) and assumes that these exact binary keys will be preserved in e.g.
* identities. So to preserve this behavior we store the secret separately
* so secret_bytes() will return it as-is.
*
* The new code will still clamp at generation resulting in secrets that are
* pre-clamped, but the old code won't care about this. It's only a problem when
* going the other way.
*
* This has no cryptographic implication since regardless of where, the clamping
* is done. It's just an API thing.
*/
let pk: [u8; 32] = public_key.try_into().unwrap();
let sk_orig: Secret<32> = Secret(secret_key.try_into().unwrap());
let pk = x25519_dalek::PublicKey::from(pk);
let sk = x25519_dalek::StaticSecret::from(sk_orig.0);
Some(X25519KeyPair(sk, sk_orig, pk))
} else {
None
}
}
#[inline(always)]
pub fn public_bytes(&self) -> [u8; C25519_PUBLIC_KEY_SIZE] {
self.2.to_bytes()
}
#[inline(always)]
pub fn secret_bytes(&self) -> &Secret<32> {
&self.1
}
/// Execute ECDH agreement and return a raw (un-hashed) shared secret key.
pub fn agree(&self, their_public: &[u8]) -> Secret<{ C25519_SHARED_SECRET_SIZE }> {
let pk: [u8; 32] = their_public.try_into().unwrap();
let pk = x25519_dalek::PublicKey::from(pk);
let sec = self.0.diffie_hellman(&pk);
Secret(sec.to_bytes())
}
}
impl Clone for X25519KeyPair {
fn clone(&self) -> Self {
Self(
x25519_dalek::StaticSecret::from(self.0.to_bytes()),
self.1.clone(),
x25519_dalek::PublicKey::from(self.1 .0),
)
}
}
/// Ed25519 key pair for EDDSA signatures.
pub struct Ed25519KeyPair(ed25519_dalek::Keypair, Secret<32>);
impl Ed25519KeyPair {
pub fn generate() -> Ed25519KeyPair {
let mut rng = SecureRandom::get();
let kp = ed25519_dalek::Keypair::generate(&mut rng);
let sk2 = Secret(kp.secret.to_bytes());
Ed25519KeyPair(kp, sk2)
}
pub fn from_bytes(public_bytes: &[u8], secret_bytes: &[u8]) -> Option<Ed25519KeyPair> {
if public_bytes.len() == ED25519_PUBLIC_KEY_SIZE && secret_bytes.len() == ED25519_SECRET_KEY_SIZE {
let pk = ed25519_dalek::PublicKey::from_bytes(public_bytes);
let sk = ed25519_dalek::SecretKey::from_bytes(secret_bytes);
if pk.is_ok() && sk.is_ok() {
// See comment in from_bytes() in C25519KeyPair for an explanation of the copy of the secret here.
let pk = pk.unwrap();
let sk = sk.unwrap();
let sk2 = Secret(sk.to_bytes());
Some(Ed25519KeyPair(ed25519_dalek::Keypair { public: pk, secret: sk }, sk2))
} else {
None
}
} else {
None
}
}
#[inline(always)]
pub fn public_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] {
self.0.public.to_bytes()
}
#[inline(always)]
pub fn secret_bytes(&self) -> &Secret<32> {
&self.1
}
pub fn sign(&self, msg: &[u8]) -> [u8; ED25519_SIGNATURE_SIZE] {
let mut h = ed25519_dalek::Sha512::new();
let _ = h.write_all(msg);
self.0.sign_prehashed(h.clone(), None).unwrap().to_bytes()
}
/// Create a signature with the first 32 bytes of the SHA512 hash appended.
/// ZeroTier does this for legacy reasons, but it's ignored in newer versions.
pub fn sign_zt(&self, msg: &[u8]) -> [u8; 96] {
let mut h = ed25519_dalek::Sha512::new();
let _ = h.write_all(msg);
let sig = self.0.sign_prehashed(h.clone(), None).unwrap();
let s = sig.as_ref();
let mut s2 = [0_u8; 96];
s2[0..64].copy_from_slice(s);
let h = h.finalize();
s2[64..96].copy_from_slice(&h.as_slice()[0..32]);
s2
}
}
impl Clone for Ed25519KeyPair {
fn clone(&self) -> Self {
Self(
ed25519_dalek::Keypair::from_bytes(&self.0.to_bytes()).unwrap(),
self.1.clone(),
)
}
}
pub fn ed25519_verify(public_key: &[u8], signature: &[u8], msg: &[u8]) -> bool {
if public_key.len() == 32 && signature.len() >= 64 {
ed25519_dalek::PublicKey::from_bytes(public_key).map_or(false, |pk| {
let mut h = ed25519_dalek::Sha512::new();
let _ = h.write_all(msg);
let sig: [u8; 64] = signature[0..64].try_into().unwrap();
pk.verify_prehashed(h, None, &ed25519_dalek::Signature::from(sig))
.is_ok()
})
} else {
false
}
}
-411
View File
@@ -1,411 +0,0 @@
# Change Log
## [Unreleased]
## [v0.9.80] - 2022-12-20
### Fixed
* Added `NO_DEPRECATED_3_0` cfg checks for more APIs.
### Added
* Added support for LibreSSL 3.7.0.
* Added `SSL_CTRL_CHAIN_CERT` and `SSL_add0_chain_cert`.
* Added `EVP_PKEY_get_security_bits` and `EVP_PKEY_security_bits`.
* Added `OSSL_PROVIDER_set_default_search_path`.
## [v0.9.79] - 2022-12-06
### Added
* Added `EVP_CIPHER_CTX_num`.
* Added `X509_LOOKUP_file` and `X509_load_cert_file`.
## [v0.9.78] - 2022-11-23
### Added
* Added support for LibreSSL 3.6.x.
* Added `NID_brainpoolP256r1`, `NID_brainpoolP384r1`, and `NID_brainpool512r1`.
* Added `EVP_camellia_128_cfb128`, `EVP_camellia_128_ecb`, `EVP_camellia_192_cfb128`, `EVP_camellia_192_ecb`,
`EVP_camellia_256_cfb128`, and `EVP_camellia_256_ecb`.
* Added `EVP_cast5_cfb64` and `EVP_cast5_ecb`.
* Added `EVP_idea_cfb64` and `EVP_idea_ecb`.
* Added `DSA_SIG`, `d2i_DSA_SIG`, `i2d_DSA_SIG`, `DSA_SIG_new`, `DSA_SIG_free`, `DSA_SIG_get0`, and `DSA_SIG_set0`.
* Added `X509_STORE_set1_param`, `X509_VERIFY_PARAM_new`, `X509_VERIFY_PARAM_set_time`, and
`X509_VERIFY_PARAM_set_depth`.
## [v0.9.77] - 2022-10-22
### Added
* Added support for LibreSSL 3.6.0
* Added `assume_init`.
## [v0.9.76] - 2022-09-26
### Added
* Added `SSL_get_psk_identity_hint` and `SSL_get_psk_identity`.
* Added SHA-3 NID constants.
* Added `SSL_OP_PRIORITIZE_CHACHA`.
* Added `X509_REQ_print`.
* Added `EVP_MD_CTX_size` and `EVP_MD_CTX_get_size`
* Added `EVP_MD_CTX_reset`.
* Added experimental, unstable support for BoringSSL.
### Fixed
* Fixed the deprecation note on `SSL_CTX_set_alpn_select_cb`.
## [v0.9.75] - 2022-07-09
### Added
* Added SM4 bindings.
* Added `EC_GROUP_set_generator` and `EC_POINT_set_affine_coordinates_GFp`.
## [v0.9.74] - 2022-06-01
### Added
* Added `EVP_MD_block_size`.
* Added `X509V3_EXT_add_alias`.
* Added `X509_V_ERR_INVALID_CA` back when building against OpenSSL 3.0.
## [v0.9.73] - 2022-05-02
### Added
* Added support for installations that place libraries in `$OPENSSL_DIR/lib64` in addition to `$OPENSSL_DIR/lib`.
* Added `X509_issuer_name_hash`.
* Added `ASN1_string_set`.
* Added `X509_CRL_dup`, `X509_REQ_dup`, `X509_NAME_dup`, and `X509_dup`.
* Added `X509_print`.
* Added support for LibreSSL 3.5.x.
## [v0.9.72] - 2021-12-11
### Changed
* Temporarily downgraded the vendored OpenSSL back to 1.1.1 due to significant performance regressions. We will move
back to 3.0.0 when a future release resolves those issues.
### Added
* Added `PKCS12_set_mac`.
* Added `EVP_PKEY_sign_init`, `EVP_PKEY_sign`, `EVP_PKEY_verify_init`, and `EVP_PKEY_verify`.
* Added support for LibreSSL 3.4.x.
## [v0.9.71]
### Fixed
* Fixed linkage to static OpenSSL 3.0.0 libraries on some 32 bit Android targets.
### Added
* Added support for LibreSSL 3.4.1.
* Added `SSL_get_extms_support` and `SSL_CTRL_GET_EXTMS_SUPPORT`.
* Added `OBJ_create`.
* Added `EVP_CIPHER_CTX_get0_cipher`, `EVP_CIPHER_CTX_get_block_size`, `EVP_CIPHER_CTX_get_key_length`,
`EVP_CIPHER_CTX_get_iv_length`, and `EVP_CIPHER_CTX_get_tag_length`.
* Added `EVP_CIPHER_free`.
* Added `EVP_CIPHER_CTX_rand_key`.
* Added `OSSL_LIB_CTX_new` and `OSSL_LIB_CTX_free`.
* Added `EVP_CIPHER_fetch`.
* Added `EVP_MD_fetch` and `EVP_MD_free`.
* Added `OPENSSL_malloc` and `OPENSSL_free`.
* Added `EVP_DigestSignUpdate` and `EVP_DigestVerifyUpdate`.
## [v0.9.70] - 2021-10-31
### Fixed
* Fixed linkage to static 3.0.0 OpenSSL libraries on some 32 bit architectures.
## [v0.9.69] - 2021-10-31
### Changed
* Upgraded the vendored OpenSSL to 3.0.0.
### Added
* Added support for automatic detection of Homebrew `openssl@3` installs.
* Added `EVP_PKEY_Q_keygen` and `EVP_EC_gen`.
## [v0.9.68] - 2021-10-27
### Added
* Added `BN_bn2binpad`.
* Added `i2d_X509_NAME` and `d2i_X509_NAME`.
* Added `BN_FLG_MALLOCED`, `BN_FLG_STATIC_DATA`, `BN_FLG_CONSTTIME`, and `BN_FLG_SECURE`.
* Added `BN_CTX_secure_new`, `BN_secure_new`, `BN_set_flags`, and `BN_get_flags`.
## [v0.9.67] - 2021-09-21
### Added
* Added support for LibreSSL 3.4.0
## [v0.9.66] - 2021-08-17
### Added
* Added `EVP_seed_cbc`, `EVP_seed_cfb128`, `EVP_seed_ecb`, and `EVP_seed_ofb`.
* Added `OBJ_length` and `OBJ_get0_data`.
* Added `i2d_PKCS8PrivateKey_bio`.
## [v0.9.65] - 2021-06-21
### Fixed
* Restored the accidentally deleted `PEM_read_bio_X509_CRL` function.
## [v0.9.64] - 2021-06-18
### Added
* Added support for OpenSSL 3.x.x.
* Added `SSL_peek`.
* Added `ERR_LIB_ASN1` and `ASN1_R_HEADER_TOO_LONG`.
* Added `d2i_X509_bio`.
* Added `OBJ_nid2obj`.
* Added `RAND_add`.
* Added `SSL_CTX_set_post_handshake_auth`.
* Added `COMP_get_type`.
* Added `X509_get_default_cert_file_env`, `X509_get_default_cert_file`, `X509_get_default_cert_dir_env`, and
`X509_get_default_cirt_dir`.
## [v0.9.63] - 2021-05-06
### Added
* Added support for LibreSSL 3.3.x.
## [v0.9.62] - 2021-04-28
### Added
* Added support for LibreSSL 3.3.2.
* Added `DH_set0_key`.
* Added `EC_POINT_get_affine_coordinates`.
## [v0.9.61] - 2021-03-13
### Added
* Added support for automatic detection of OpenSSL installations via pkgsrc and MacPorts on macOS.
* Added various `V_ASN1_*` constants.
* Added `DH_generate_parameters_ex`.
* Added `EC_POINT_is_at_infinity` and `EC_POINT_is_on_curve`.
* Added `EVP_CIPHER_nid`.
* Added `EVP_sm3`.
* Added `NID_*` constants related to SM3.
* Added `PKCS7_get0_signers`.
* Added `EVP_PKEY_CTX_set0_rsa_oaep_label`.
* Added `ACCESS_DESCRIPTION` and `ACCESS_DESCRIPTION_free`.
## [v0.9.60] - 2020-12-24
### Added
* Added support for the default Homebrew install directory on ARM.
* Added `EVP_PKEY_CTX_set_rsa_oaep_md` and `EVP_PKEY_CTRL_RSA_OAEP_MD`.
## [v0.9.59] - 2020-12-09
### Added
* Added support for LibreSSL 3.2.x, 3.3.0, and 3.3.1.
* Added `DH_generate_parameters`, `DH_generate_key`, `DH_compute_key`, and `DH_size`.
* Added `NID_X25519`, `NID_X448`, `EVP_PKEY_x25519` and `EVP_PKEY_x448`.
* Added `OBJ_txt2obj`.
* Added `d2i_PKCS7` and `i2d_PKCS7`.
* Added `SRTP_AEAD_AES_128_GCM` and `SRTP_AEAD_AES_256_GCM`.
## [v0.9.58] - 2020-06-05
### Added
* Added `SSL_set_mtu`.
* Added support for LibreSSL 3.2.0.
* Added `PEM_read_bio_EC_PUBKEY`, `PEM_write_bio_EC_PUBKEY`, `d2i_EC_PUBKEY`, and `i2d_EC_PUBKEY`.
* Added `EVP_PKEY_encrypt_init`, `EVP_PKEY_encrypt`, `EVP_PKEY_decrypt_init`, `EVP_PKEY_decrypt`,
`EVP_PKEY_get_raw_public_key`, `EVP_PKEY_new_raw_public_key`, `EVP_PKEY_get_raw_private_key`,
and `EVP_PKEY_new_raw_private_key`.
* Added `OBJ_sn2nid`.
## [v0.9.57] - 2020-05-24
### Added
* Added support for LibreSSL 3.1.x.
## [v0.9.56] - 2020-05-07
### Fixed
* Fixed vendored builds on windows-gnu targets.
### Added
* Added support for LibreSSL 3.0.0.
## [v0.9.55] - 2020-04-07
### Fixed
* Fixed windows-msvc library names when using OpenSSL from vcpkg.
### Added
* If the `OPENSSL_NO_VENDOR` environment variable is set, vendoring will not be used even if enabled.
* Added `SSL_CTX_get_verify_mode` and `SSL_get_verify_mode`.
* Added `SSL_is_init_finished`.
* Added `SSL_CTX_set_cert_store`.
* Added `TLS_server_method` and `TLS_client_method`.
* Added `X509_STORE_get0_objects`.
* Added `X509_OBJECT_free`, `X509_OBJECT_get_type`, and `X509_OBJECT_get0_X509`.
## [v0.9.54] - 2020-01-29
### Added
* Added `BIO_CTRL_DGRAM_QUERY_MTU`.
* Added `EVP_EncryptInit_ex`, `EVP_EncryptFinal_ex`, `EVP_DecryptInit_ex`, and `EVP_DecryptFinal_ex`.
* Added `EVP_md_null`.
* Added `EVP_PKCS82PKEY`.
* Added `PKCS8_PRIV_KEY_INFO`, `d2i_PKCS8_PRIV_KEY_INFO`, and `PKCS8_PRIV_KEY_INFO_free`.
* Added `SSL_OP_NO_RENEGOTIATION`.
## [v0.9.53] - 2019-11-22
### Added
* Added `ASN1_TIME_diff`.
* Added `EC_GROUP_order_bits`.
* Added `EVP_EncodeBlock` and `EVP_DecodeBlock`.
* Added `SSL_CTRL_SET_GROUPS_LIST`, `SSL_CTRL_SET_SIGALGS_LIST`, `SSL_CTX_set1_groups_list`, and
`SSL_CTX_set1_sigalgs_list`.
* Added `Clone` implementations to `SHA_CTX`, `SHA256_CTX`, and `SHA512_CTX`.
## [v0.9.52] - 2019-10-19
### Added
* Added support for LibreSSL 3.0.x.
## [v0.9.51] - 2019-10-02
### Added
* Added support for LibreSSL 3.0.1.
## [v0.9.50] - 2019-10-02
### Added
* Added `CRYPTO_LOCK_EVP_PKEY`.
* Added `EVP_PKEY_ED25519` and `EVP_PKEY_ED448`.
* Added `EVP_DigestSign` and `EVP_DigestVerify`.
* Added `EVP_PKEY_up_ref`.
* Added `NID_ED25519` and `NID_ED448`.
## [v0.9.49] - 2019-08-15
### Added
* Added support for LibreSSL 3.0.0.
## [v0.9.48] - 2019-07-19
### Added
* Added `AES_wrap_key` and `AES_unwrap_key`.
* Added `EC_GROUP_get_cofactor`, `EC_GROUP_get0_generator`, and `EC_POINT_dup`.
* Added `EVP_aes_128_ofb`, `EVP_aes_192_ecb`, `EVP_aes_192_cbc`, `EVP_aes_192_cfb1`, `EVP_aes_192_cfb8`,
`EVP_aes_192_cfb_128`, `EVP_aes_192_ctr`, `EVP_aes_192_ccm`, `EVP_aes_192_gcm`, `EVP_aes_192_ofb`, and
`EVP_aes_256_ofb`.
* Added `PEM_read_bio_CMS` and `PEM_write_bio_CMS`.
## [v0.9.47] - 2019-05-18
### Added
* Added `SSL_CTX_add_client_CA`.
## [v0.9.46] - 2019-05-08
### Added
* Added support for the LibreSSL 2.9.x series.
## [v0.9.45] - 2019-05-03
### Fixed
* Reverted a change to windows-gnu library names that caused regressions.
## [v0.9.44] - 2019-04-30
### Added
* The `DEP_OPENSSL_VENDORED` environment variable tells downstream build scripts if the vendored feature was enabled.
* Added `EVP_SealInit`, `EVP_SealFinal`, `EVP_EncryptUpdate`, `EVP_OpenInit`, `EVP_OpenFinal`, and `EVP_DecryptUpdate`.
* Added `EVP_PKEY_size`.
### Fixed
* Fixed library names when targeting windows-gnu and pkg-config fails.
## [v0.9.43] - 2019-03-20
### Added
* Added `d2i_CMS_ContentInfo` and `CMS_encrypt`.
* Added `X509_verify` and `X509_REQ_verify`.
* Added `EVP_MD_type` and `EVP_GROUP_get_curve_name`.
[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.80..master
[v0.9.80]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.79...openssl-sys-v0.9.80
[v0.9.79]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.78...openssl-sys-v0.9.79
[v0.9.78]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.77...openssl-sys-v0.9.78
[v0.9.77]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.76...openssl-sys-v0.9.77
[v0.9.76]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.75...openssl-sys-v0.9.76
[v0.9.75]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.74...openssl-sys-v0.9.75
[v0.9.74]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.73...openssl-sys-v0.9.74
[v0.9.73]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.72...openssl-sys-v0.9.73
[v0.9.72]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.71...openssl-sys-v0.9.72
[v0.9.71]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.70...openssl-sys-v0.9.71
[v0.9.70]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.69...openssl-sys-v0.9.70
[v0.9.69]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.68...openssl-sys-v0.9.69
[v0.9.68]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.67...openssl-sys-v0.9.68
[v0.9.67]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.66...openssl-sys-v0.9.67
[v0.9.66]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.65...openssl-sys-v0.9.66
[v0.9.65]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.64...openssl-sys-v0.9.65
[v0.9.64]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.63...openssl-sys-v0.9.64
[v0.9.63]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.62...openssl-sys-v0.9.63
[v0.9.62]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.61...openssl-sys-v0.9.62
[v0.9.61]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.60...openssl-sys-v0.9.61
[v0.9.60]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.59...openssl-sys-v0.9.60
[v0.9.59]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.58...openssl-sys-v0.9.59
[v0.9.58]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.57...openssl-sys-v0.9.58
[v0.9.57]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.56...openssl-sys-v0.9.57
[v0.9.56]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.55...openssl-sys-v0.9.56
[v0.9.55]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.54...openssl-sys-v0.9.55
[v0.9.54]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.53...openssl-sys-v0.9.54
[v0.9.53]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.52...openssl-sys-v0.9.53
[v0.9.52]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.51...openssl-sys-v0.9.52
[v0.9.51]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.50...openssl-sys-v0.9.51
[v0.9.50]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.49...openssl-sys-v0.9.50
[v0.9.49]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.48...openssl-sys-v0.9.49
[v0.9.48]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.47...openssl-sys-v0.9.48
[v0.9.47]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.46...openssl-sys-v0.9.47
[v0.9.46]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.45...openssl-sys-v0.9.46
[v0.9.45]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.44...openssl-sys-v0.9.45
[v0.9.44]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.43...openssl-sys-v0.9.44
[v0.9.43]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.42...openssl-sys-v0.9.43
-36
View File
@@ -1,36 +0,0 @@
[package]
name = "openssl-sys"
version = "0.9.80"
authors = [
"Alex Crichton <alex@alexcrichton.com>",
"Steven Fackler <sfackler@gmail.com>",
]
license = "MIT"
description = "FFI bindings to OpenSSL"
repository = "https://github.com/sfackler/rust-openssl"
readme = "README.md"
categories = ["cryptography", "external-ffi-bindings"]
links = "openssl"
build = "build/main.rs"
edition = "2018"
[features]
vendored = ['openssl-src']
[dependencies]
libc = "0.2"
#bssl-sys = { version = "0.1.0", optional = true }#package does not seem needed for ZT
[build-dependencies]
bindgen = { version = "0.64.0", optional = true }
cc = "1.0"
openssl-src = { version = "300.0.12", optional = true }
pkg-config = "0.3.9"
autocfg = "1.0"
[target.'cfg(target_env = "msvc")'.build-dependencies]
vcpkg = "0.2.8"
# We don't actually use metadeps for annoying reasons but this is still here for tooling
[package.metadata.pkg-config]
openssl = "1.1.0"
-25
View File
@@ -1,25 +0,0 @@
Copyright (c) 2014 Alex Crichton
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-1
View File
@@ -1 +0,0 @@
../README.md
-94
View File
@@ -1,94 +0,0 @@
pub fn get(openssl_version: Option<u64>, libressl_version: Option<u64>) -> Vec<&'static str> {
let mut cfgs = vec![];
if let Some(libressl_version) = libressl_version {
cfgs.push("libressl");
if libressl_version >= 0x2_05_01_00_0 {
cfgs.push("libressl251");
}
if libressl_version >= 0x2_05_02_00_0 {
cfgs.push("libressl252");
}
if libressl_version >= 0x2_06_01_00_0 {
cfgs.push("libressl261");
}
if libressl_version >= 0x2_07_00_00_0 {
cfgs.push("libressl270");
}
if libressl_version >= 0x2_07_01_00_0 {
cfgs.push("libressl271");
}
if libressl_version >= 0x2_07_03_00_0 {
cfgs.push("libressl273");
}
if libressl_version >= 0x2_08_00_00_0 {
cfgs.push("libressl280");
}
if libressl_version >= 0x2_08_01_00_0 {
cfgs.push("libressl281");
}
if libressl_version >= 0x2_09_01_00_0 {
cfgs.push("libressl291");
}
if libressl_version >= 0x3_02_01_00_0 {
cfgs.push("libressl321");
}
if libressl_version >= 0x3_03_02_00_0 {
cfgs.push("libressl332");
}
if libressl_version >= 0x3_04_00_00_0 {
cfgs.push("libressl340");
}
if libressl_version >= 0x3_05_00_00_0 {
cfgs.push("libressl350");
}
if libressl_version >= 0x3_06_00_00_0 {
cfgs.push("libressl360");
}
if libressl_version >= 0x3_07_00_00_0 {
cfgs.push("libressl370");
}
} else {
let openssl_version = openssl_version.unwrap();
if openssl_version >= 0x3_00_00_00_0 {
cfgs.push("ossl300");
}
if openssl_version >= 0x1_00_01_00_0 {
cfgs.push("ossl101");
}
if openssl_version >= 0x1_00_02_00_0 {
cfgs.push("ossl102");
}
if openssl_version >= 0x1_00_02_06_0 {
cfgs.push("ossl102f");
}
if openssl_version >= 0x1_00_02_08_0 {
cfgs.push("ossl102h");
}
if openssl_version >= 0x1_01_00_00_0 {
cfgs.push("ossl110");
}
if openssl_version >= 0x1_01_00_06_0 {
cfgs.push("ossl110f");
}
if openssl_version >= 0x1_01_00_07_0 {
cfgs.push("ossl110g");
}
if openssl_version >= 0x1_01_00_08_0 {
cfgs.push("ossl110h");
}
if openssl_version >= 0x1_01_01_00_0 {
cfgs.push("ossl111");
}
if openssl_version >= 0x1_01_01_02_0 {
cfgs.push("ossl111b");
}
if openssl_version >= 0x1_01_01_03_0 {
cfgs.push("ossl111c");
}
}
cfgs
}

Some files were not shown because too many files have changed in this diff Show More