update response to invalid client certificate or no client certificate
This commit is contained in:
parent
be8ec3adfe
commit
c765da33db
7 changed files with 52 additions and 16 deletions
|
|
@ -43,3 +43,12 @@ pub enum RpxyError {
|
|||
#[error(transparent)]
|
||||
Other(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Clone)]
|
||||
pub enum ClientCertsError {
|
||||
#[error("TLS Client Certificate is Required for Given SNI: {0}")]
|
||||
ClientCertRequired(String),
|
||||
|
||||
#[error("Inconsistent TLS Client Certificate for Given SNI: {0}")]
|
||||
InconsistentClientCert(String),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,26 @@ where
|
|||
listen_addr: SocketAddr,
|
||||
tls_enabled: bool,
|
||||
tls_server_name: Option<ServerNameBytesExp>,
|
||||
tls_client_auth_result: Option<std::result::Result<(), ClientCertsError>>,
|
||||
) -> Result<Response<Body>> {
|
||||
////////
|
||||
let mut log_data = MessageLog::from(&req);
|
||||
log_data.client_addr(&client_addr);
|
||||
//////
|
||||
// First check client auth result if exist
|
||||
if let Some(res) = tls_client_auth_result {
|
||||
match res {
|
||||
Err(ClientCertsError::ClientCertRequired(_)) => {
|
||||
// Client cert is required for the TLS server name
|
||||
return self.return_with_error_log(StatusCode::FORBIDDEN, &mut log_data);
|
||||
}
|
||||
Err(ClientCertsError::InconsistentClientCert(_)) => {
|
||||
// Client cert provided was inconsistent to the TLS server name
|
||||
return self.return_with_error_log(StatusCode::BAD_REQUEST, &mut log_data);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Here we start to handle with server_name
|
||||
let server_name = if let Ok(v) = req.parse_host() {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ use x509_parser::prelude::*;
|
|||
// TODO: consider move this function to the layer of handle_request (L7) to return 403
|
||||
pub(super) fn check_client_authentication(
|
||||
client_certs: Option<&[Certificate]>,
|
||||
client_certs_setting_for_sni: Option<&HashSet<Vec<u8>>>,
|
||||
) -> Result<()> {
|
||||
let client_ca_keyids_set = match client_certs_setting_for_sni {
|
||||
client_ca_keyids_set_for_sni: Option<&HashSet<Vec<u8>>>,
|
||||
) -> std::result::Result<(), ClientCertsError> {
|
||||
let client_ca_keyids_set = match client_ca_keyids_set_for_sni {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
// No client cert settings for given server name
|
||||
|
|
@ -23,9 +23,8 @@ pub(super) fn check_client_authentication(
|
|||
c
|
||||
}
|
||||
None => {
|
||||
// TODO: return 403 here
|
||||
error!("Client certificate is needed for given server name");
|
||||
return Err(RpxyError::Proxy(
|
||||
return Err(ClientCertsError::ClientCertRequired(
|
||||
"Client certificate is needed for given server name".to_string(),
|
||||
));
|
||||
}
|
||||
|
|
@ -45,9 +44,8 @@ pub(super) fn check_client_authentication(
|
|||
});
|
||||
|
||||
if !match_server_crypto_and_client_cert {
|
||||
// TODO: return 403 here
|
||||
error!("Inconsistent client certificate was provided for SNI");
|
||||
return Err(RpxyError::Proxy(
|
||||
return Err(ClientCertsError::InconsistentClientCert(
|
||||
"Inconsistent client certificate was provided for SNI".to_string(),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ where
|
|||
match conn.await {
|
||||
Ok(new_conn) => {
|
||||
// Check client certificates
|
||||
// TODO: consider move this function to the layer of handle_request (L7) to return 403
|
||||
let cc = {
|
||||
// https://docs.rs/quinn/latest/quinn/struct.Connection.html
|
||||
let client_certs_setting_for_sni = sni_cc_map.get(&tls_server_name);
|
||||
|
|
@ -34,7 +33,8 @@ where
|
|||
};
|
||||
(client_certs, client_certs_setting_for_sni)
|
||||
};
|
||||
check_client_authentication(cc.0.as_ref().map(AsRef::as_ref), cc.1)?;
|
||||
// TODO: pass this value to the layer of handle_request (L7) to return 403
|
||||
let tls_client_auth_result = check_client_authentication(cc.0.as_ref().map(AsRef::as_ref), cc.1);
|
||||
|
||||
let mut h3_conn = h3::server::Connection::<_, bytes::Bytes>::new(h3_quinn::Connection::new(new_conn)).await?;
|
||||
info!(
|
||||
|
|
@ -61,10 +61,17 @@ where
|
|||
|
||||
let self_inner = self.clone();
|
||||
let tls_server_name_inner = tls_server_name.clone();
|
||||
let tls_client_auth_result_inner = tls_client_auth_result.clone();
|
||||
self.globals.runtime_handle.spawn(async move {
|
||||
if let Err(e) = timeout(
|
||||
self_inner.globals.proxy_timeout + Duration::from_secs(1), // timeout per stream are considered as same as one in http2
|
||||
self_inner.stream_serve_h3(req, stream, client_addr, tls_server_name_inner),
|
||||
self_inner.stream_serve_h3(
|
||||
req,
|
||||
stream,
|
||||
client_addr,
|
||||
tls_server_name_inner,
|
||||
tls_client_auth_result_inner,
|
||||
),
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
|
@ -90,6 +97,7 @@ where
|
|||
stream: RequestStream<S, Bytes>,
|
||||
client_addr: SocketAddr,
|
||||
tls_server_name: ServerNameBytesExp,
|
||||
tls_client_auth_result: std::result::Result<(), ClientCertsError>,
|
||||
) -> Result<()>
|
||||
where
|
||||
S: BidiStream<Bytes> + Send + 'static,
|
||||
|
|
@ -141,6 +149,7 @@ where
|
|||
self.listening_on,
|
||||
self.tls_enabled,
|
||||
Some(tls_server_name),
|
||||
Some(tls_client_auth_result),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ where
|
|||
server: Http<LocalExecutor>,
|
||||
peer_addr: SocketAddr,
|
||||
tls_server_name: Option<ServerNameBytesExp>,
|
||||
tls_client_auth_result: Option<std::result::Result<(), ClientCertsError>>,
|
||||
) where
|
||||
I: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
|
|
@ -74,6 +75,7 @@ where
|
|||
self.listening_on,
|
||||
self.tls_enabled,
|
||||
tls_server_name.clone(),
|
||||
tls_client_auth_result.clone(),
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
|
@ -92,7 +94,9 @@ where
|
|||
let tcp_listener = TcpListener::bind(&self.listening_on).await?;
|
||||
info!("Start TCP proxy serving with HTTP request for configured host names");
|
||||
while let Ok((stream, _client_addr)) = tcp_listener.accept().await {
|
||||
self.clone().client_serve(stream, server.clone(), _client_addr, None);
|
||||
self
|
||||
.clone()
|
||||
.client_serve(stream, server.clone(), _client_addr, None, None);
|
||||
}
|
||||
Ok(()) as Result<()>
|
||||
};
|
||||
|
|
|
|||
|
|
@ -92,13 +92,14 @@ where
|
|||
} else {
|
||||
//////////////////////////////
|
||||
// Check client certificate
|
||||
// TODO: consider move this function to the layer of handle_request (L7) to return 403
|
||||
let client_certs = conn.peer_certificates();
|
||||
let client_certs_setting_for_sni = sni_cc_map.get(&server_name.clone().unwrap());
|
||||
check_client_authentication(client_certs, client_certs_setting_for_sni)?;
|
||||
let client_ca_keyids_set_for_sni = sni_cc_map.get(&server_name.clone().unwrap());
|
||||
// TODO: pass this value to the layer of handle_request (L7) to return 403
|
||||
let client_certs_auth_result = check_client_authentication(client_certs, client_ca_keyids_set_for_sni);
|
||||
//////////////////////////////
|
||||
// this immediately spawns another future to actually handle stream. so it is okay to introduce timeout for handshake.
|
||||
self_inner.client_serve(stream, server_clone, client_addr, server_name); // TODO: don't want to pass copied value...
|
||||
// TODO: don't want to pass copied value...
|
||||
self_inner.client_serve(stream, server_clone, client_addr, server_name, Some(client_certs_auth_result));
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue