mirror of
https://github.com/zerotier/crypto-glue.git
synced 2026-05-22 16:28:47 -07:00
integrated changes to deps
This commit is contained in:
+25
-11
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
@@ -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.
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 {}
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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 +0,0 @@
|
||||
../README.md
|
||||
@@ -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
Reference in New Issue
Block a user