feat(core): add QUIC TLS admission transport
This commit is contained in:
+114
@@ -0,0 +1,114 @@
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustls::client::ResolvesClientCert;
|
||||
use rustls::pki_types::CertificateDer;
|
||||
use rustls::sign::{CertifiedKey, Signer, SigningKey};
|
||||
use rustls::{ClientConfig, RootCertStore, SignatureAlgorithm, SignatureScheme};
|
||||
|
||||
use crate::error::{CoreError, Result};
|
||||
use crate::wire::NativeTunnelCredential;
|
||||
|
||||
pub(crate) type SignCallback = dyn Fn(&[u8]) -> Result<[u8; 64]> + Send + Sync;
|
||||
|
||||
pub(crate) struct CallbackSigningKey {
|
||||
callback: Arc<SignCallback>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for CallbackSigningKey {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("CallbackSigningKey")
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackSigningKey {
|
||||
pub(crate) fn new(callback: Arc<SignCallback>) -> Self {
|
||||
Self { callback }
|
||||
}
|
||||
}
|
||||
|
||||
impl SigningKey for CallbackSigningKey {
|
||||
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
|
||||
offered
|
||||
.contains(&SignatureScheme::ED25519)
|
||||
.then(|| Box::new(CallbackSigner(Arc::clone(&self.callback))) as Box<dyn Signer>)
|
||||
}
|
||||
|
||||
fn algorithm(&self) -> SignatureAlgorithm {
|
||||
SignatureAlgorithm::ED25519
|
||||
}
|
||||
}
|
||||
|
||||
struct CallbackSigner(Arc<SignCallback>);
|
||||
|
||||
impl fmt::Debug for CallbackSigner {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("CallbackSigner")
|
||||
}
|
||||
}
|
||||
|
||||
impl Signer for CallbackSigner {
|
||||
fn sign(&self, message: &[u8]) -> std::result::Result<Vec<u8>, rustls::Error> {
|
||||
(self.0)(message)
|
||||
.map(|signature| signature.to_vec())
|
||||
.map_err(|_| rustls::Error::General("client signing failed".to_owned()))
|
||||
}
|
||||
|
||||
fn scheme(&self) -> SignatureScheme {
|
||||
SignatureScheme::ED25519
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ClientIdentity(Arc<CertifiedKey>);
|
||||
|
||||
impl ResolvesClientCert for ClientIdentity {
|
||||
fn resolve(
|
||||
&self,
|
||||
_root_hint_subjects: &[&[u8]],
|
||||
sigschemes: &[SignatureScheme],
|
||||
) -> Option<Arc<CertifiedKey>> {
|
||||
sigschemes
|
||||
.contains(&SignatureScheme::ED25519)
|
||||
.then(|| Arc::clone(&self.0))
|
||||
}
|
||||
|
||||
fn has_certs(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn client_config(
|
||||
credential: &NativeTunnelCredential,
|
||||
callback: Arc<SignCallback>,
|
||||
) -> Result<ClientConfig> {
|
||||
let certificate_chain = rustls_pemfile::certs(&mut Cursor::new(
|
||||
credential.certificate_chain_pem().as_bytes(),
|
||||
))
|
||||
.collect::<std::result::Result<Vec<CertificateDer<'static>>, _>>()
|
||||
.map_err(|_| CoreError::Tls)?;
|
||||
if certificate_chain.is_empty() {
|
||||
return Err(CoreError::Tls);
|
||||
}
|
||||
let mut roots = RootCertStore::empty();
|
||||
let trust_bundle =
|
||||
rustls_pemfile::certs(&mut Cursor::new(credential.trust_bundle_pem().as_bytes()))
|
||||
.collect::<std::result::Result<Vec<CertificateDer<'static>>, _>>()
|
||||
.map_err(|_| CoreError::Tls)?;
|
||||
if trust_bundle.is_empty() || roots.add_parsable_certificates(trust_bundle).1 != 0 {
|
||||
return Err(CoreError::Tls);
|
||||
}
|
||||
let provider = Arc::new(rustls::crypto::ring::default_provider());
|
||||
let mut config = ClientConfig::builder_with_provider(provider)
|
||||
.with_protocol_versions(&[&rustls::version::TLS13])
|
||||
.map_err(|_| CoreError::Tls)?
|
||||
.with_root_certificates(roots)
|
||||
.with_client_cert_resolver(Arc::new(ClientIdentity(Arc::new(CertifiedKey::new(
|
||||
certificate_chain,
|
||||
Arc::new(CallbackSigningKey::new(callback)),
|
||||
)))));
|
||||
config.alpn_protocols = vec![b"versevdi-gateway-v1".to_vec()];
|
||||
config.enable_early_data = false;
|
||||
Ok(config)
|
||||
}
|
||||
Reference in New Issue
Block a user