Skip to content

Commit

Permalink
initial implemention of openssl crypto provider
Browse files Browse the repository at this point in the history
  • Loading branch information
tofay committed Nov 7, 2024
0 parents commit 62b0c76
Show file tree
Hide file tree
Showing 19 changed files with 2,166 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
Cargo.lock
30 changes: 30 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "rustls-openssl"
authors = ["Tom Fay <[email protected]>"]
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "Rustls crypto provider for OpenSSL"
homepage = "https://github.com/tofay/rustls-openssl"
repository = "https://github.com/tofay/rustls-openssl"
readme = "README.md"

[dependencies]
openssl = { version = "0.10.68" }
rustls = { version = "0.23.0", features = [
"tls12",
"std",
], default-features = false }
rustls-webpki = "0.102.2"

[features]
default = []
x25519 = []
chacha = []

[dev-dependencies]
lazy_static = "1.4.0"
once_cell = "1.8.0"
rstest = "0.23.0"
rustls-pemfile = "2"
webpki-roots = "0.26"
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# rustls-openssl
An experimental [rustls Crypto Provider](https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html) that uses OpenSSL for cryptographic operations.

## Usage
The main entry points are the `rustls_openssl::default_provider` and `rustls_openssl::custom_provider` functions.
See the [rustls documentation]((https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html)) for how to use them.
164 changes: 164 additions & 0 deletions src/cipher_suites.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use crate::hash::HashAlgorithm;
use crate::hmac::{HmacSha256, HmacSha384};
use crate::tls12::{AesGcm, Tls12Gcm};
use rustls::crypto::{CipherSuiteCommon, KeyExchangeAlgorithm};
use rustls::{
CipherSuite, SignatureScheme, SupportedCipherSuite, Tls12CipherSuite, Tls13CipherSuite,
};

use rustls::crypto::tls12::PrfUsingHmac;
use rustls::crypto::tls13::HkdfUsingHmac;

use crate::tls13::AeadAlgorithm;

/// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256
#[cfg(feature = "chacha")]
pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls13(&Tls13CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
hash_provider: &HashAlgorithm::SHA256,
confidentiality_limit: u64::MAX,
},
hkdf_provider: &HkdfUsingHmac(&HmacSha256),
aead_alg: &AeadAlgorithm::ChaCha20Poly1305,
quic: None,
});

/// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384
pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite =
SupportedCipherSuite::Tls13(&Tls13CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS13_AES_256_GCM_SHA384,
hash_provider: &HashAlgorithm::SHA384,
confidentiality_limit: 1 << 23,
},
hkdf_provider: &HkdfUsingHmac(&HmacSha384),
aead_alg: &AeadAlgorithm::Aes256Gcm,
quic: None,
});

/// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256
pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls13(&Tls13CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS13_AES_128_GCM_SHA256,
hash_provider: &HashAlgorithm::SHA256,
confidentiality_limit: 1 << 23,
},
hkdf_provider: &HkdfUsingHmac(&HmacSha256),
aead_alg: &AeadAlgorithm::Aes128Gcm,
quic: None,
});

/// TLS 1.2
// /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.
// #[cfg(feature = "chacha")]
// pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
// SupportedCipherSuite::Tls12(&Tls12CipherSuite {
// common: CipherSuiteCommon {
// suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
// hash_provider: &HashAlgorithm::SHA256,
// confidentiality_limit: u64::MAX,
// },
// kx: KeyExchangeAlgorithm::ECDHE,
// sign: TLS12_ECDSA_SCHEMES,
// aead_alg: &crate::tls12::Tls12ChaCha,
// prf_provider: &PrfUsingHmac(&HmacSha256),
// });

/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
#[cfg(feature = "chacha")]
pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: &HashAlgorithm::SHA256,
confidentiality_limit: u64::MAX,
},
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_RSA_SCHEMES,
aead_alg: &crate::tls12::Tls12ChaCha,
prf_provider: &PrfUsingHmac(&HmacSha256),
});

/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
hash_provider: &HashAlgorithm::SHA256,
confidentiality_limit: 1 << 23,
},
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_RSA_SCHEMES,
aead_alg: &Tls12Gcm {
algo_type: AesGcm::Aes128Gcm,
},
prf_provider: &PrfUsingHmac(&HmacSha256),
});

/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
SupportedCipherSuite::Tls12(&Tls12CipherSuite {
common: CipherSuiteCommon {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
hash_provider: &HashAlgorithm::SHA384,
confidentiality_limit: 1 << 23,
},
kx: KeyExchangeAlgorithm::ECDHE,
sign: TLS12_RSA_SCHEMES,
aead_alg: &Tls12Gcm {
algo_type: AesGcm::Aes256Gcm,
},
prf_provider: &PrfUsingHmac(&HmacSha384),
});

// /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
// pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
// SupportedCipherSuite::Tls12(&Tls12CipherSuite {
// common: CipherSuiteCommon {
// suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
// hash_provider: &HashAlgorithm::SHA256,
// confidentiality_limit: 1 << 23,
// },
// kx: KeyExchangeAlgorithm::ECDHE,
// sign: TLS12_ECDSA_SCHEMES,
// aead_alg: &Tls12Gcm {
// algo_type: AesGcm::Aes128Gcm,
// },
// prf_provider: &PrfUsingHmac(&HmacSha256),
// });

// /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
// pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
// SupportedCipherSuite::Tls12(&Tls12CipherSuite {
// common: CipherSuiteCommon {
// suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// hash_provider: &HashAlgorithm::SHA384,
// confidentiality_limit: 1 << 23,
// },
// kx: KeyExchangeAlgorithm::ECDHE,
// sign: TLS12_ECDSA_SCHEMES,
// aead_alg: &Tls12Gcm {
// algo_type: AesGcm::Aes256Gcm,
// },
// prf_provider: &PrfUsingHmac(&HmacSha384),
// });

// static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
// SignatureScheme::ECDSA_NISTP521_SHA512,
// SignatureScheme::ECDSA_NISTP384_SHA384,
// SignatureScheme::ECDSA_NISTP256_SHA256,
// ];

/// RSA schemes in descending order of preference
pub(crate) static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA256,
];
149 changes: 149 additions & 0 deletions src/ecdh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use openssl::bn::BigNumContext;
use openssl::derive::Deriver;
use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
use openssl::nid::Nid;
#[cfg(feature = "x25519")]
use openssl::pkey::Id;
use openssl::pkey::{PKey, Private, Public};
use rustls::crypto::{ActiveKeyExchange, SharedSecret, SupportedKxGroup};
use rustls::{Error, NamedGroup};

/// Supported KeyExchange groups.
/// ```ignore
/// SECP384R1
/// SECP256R1
/// X25519 // Enabled with the `x25519` feature
/// ```
pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
SECP256R1,
SECP384R1,
#[cfg(feature = "x25519")]
X25519,
];

/// KXGroup's that use openssl::ec module with Nid's for key exchange.
#[derive(Debug)]
struct EcKxGroup {
name: NamedGroup,
nid: Nid,
}

struct EcKeyExchange {
priv_key: EcKey<Private>,
name: NamedGroup,
group: EcGroup,
pub_key: Vec<u8>,
}

#[cfg(feature = "x25519")]
/// KXGroup for X25519
#[derive(Debug)]
struct X25519KxGroup {}

#[cfg(feature = "x25519")]
#[derive(Debug)]
struct X25519KeyExchange {
private_key: PKey<Private>,
public_key: Vec<u8>,
}

#[cfg(feature = "x25519")]
pub const X25519: &dyn SupportedKxGroup = &X25519KxGroup {};

pub const SECP256R1: &dyn SupportedKxGroup = &EcKxGroup {
name: NamedGroup::secp256r1,
nid: Nid::X9_62_PRIME256V1,
};

pub const SECP384R1: &dyn SupportedKxGroup = &EcKxGroup {
name: NamedGroup::secp384r1,
nid: Nid::SECP384R1,
};

impl SupportedKxGroup for EcKxGroup {
fn start(&self) -> Result<Box<(dyn ActiveKeyExchange)>, Error> {
let group = EcGroup::from_curve_name(self.nid).unwrap();
let priv_key = EcKey::generate(&group).unwrap();
let mut ctx = BigNumContext::new().unwrap();
let pub_key = priv_key
.public_key()
.to_bytes(&group, PointConversionForm::UNCOMPRESSED, &mut ctx)
.unwrap();

Ok(Box::new(EcKeyExchange {
priv_key,
name: self.name,
group,
pub_key,
}))
}

fn name(&self) -> NamedGroup {
self.name
}
}

impl EcKeyExchange {
fn load_peer_key(&self, peer_pub_key: &[u8]) -> Result<PKey<Public>, Error> {
let mut ctx = BigNumContext::new().unwrap();
let point = EcPoint::from_bytes(&self.group, peer_pub_key, &mut ctx).unwrap();
let peer_key = EcKey::from_public_key(&self.group, &point).unwrap();
peer_key.check_key().unwrap();
let peer_key: PKey<_> = peer_key.try_into().unwrap();
Ok(peer_key)
}
}

impl ActiveKeyExchange for EcKeyExchange {
fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> {
let peer_key = self.load_peer_key(peer_pub_key).unwrap();
let key: PKey<_> = self.priv_key.try_into().unwrap();
let mut deriver = Deriver::new(&key).unwrap();
deriver.set_peer(&peer_key).unwrap();
let secret = deriver.derive_to_vec().unwrap();
Ok(SharedSecret::from(secret.as_slice()))
}

fn pub_key(&self) -> &[u8] {
&self.pub_key
}

fn group(&self) -> NamedGroup {
self.name
}
}

#[cfg(feature = "x25519")]
impl SupportedKxGroup for X25519KxGroup {
fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> {
let private_key = PKey::generate_x25519().unwrap();
let public_key = private_key.raw_public_key().unwrap();
Ok(Box::new(X25519KeyExchange {
private_key,
public_key,
}))
}

fn name(&self) -> NamedGroup {
NamedGroup::X25519
}
}

#[cfg(feature = "x25519")]
impl ActiveKeyExchange for X25519KeyExchange {
fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> {
let peer_public_key = PKey::public_key_from_raw_bytes(peer_pub_key, Id::X25519).unwrap();
let mut deriver = Deriver::new(&self.private_key).unwrap();
deriver.set_peer(&peer_public_key).unwrap();
let secret = deriver.derive_to_vec().unwrap();
Ok(SharedSecret::from(secret.as_slice()))
}

fn pub_key(&self) -> &[u8] {
&self.public_key
}

fn group(&self) -> NamedGroup {
NamedGroup::X25519
}
}
Loading

0 comments on commit 62b0c76

Please sign in to comment.