mirror of
https://github.com/localsend/localsend.git
synced 2026-06-22 20:00:07 +00:00
refactor: verify_cert_from_res
This commit is contained in:
@@ -4,14 +4,14 @@ use x509_parser::certificate::X509Certificate;
|
||||
use x509_parser::pem::Pem;
|
||||
use x509_parser::x509::SubjectPublicKeyInfo;
|
||||
|
||||
pub fn verify_cert_from_pem(cert: String, public_key: Option<String>) -> anyhow::Result<()> {
|
||||
pub fn verify_cert_from_pem(cert: String, public_key: Option<&str>) -> anyhow::Result<()> {
|
||||
let (cert_pem, _) = Pem::read(Cursor::new(cert.into_bytes()))?;
|
||||
let parsed_cert: X509Certificate = cert_pem.parse_x509()?;
|
||||
|
||||
verify_cert_from_cert(parsed_cert, public_key)
|
||||
}
|
||||
|
||||
pub fn verify_cert_from_der(cert: &[u8], public_key: Option<String>) -> anyhow::Result<()> {
|
||||
pub fn verify_cert_from_der(cert: &[u8], public_key: Option<&str>) -> anyhow::Result<()> {
|
||||
let (_, parsed_cert) = X509Certificate::from_der(&cert)?;
|
||||
|
||||
verify_cert_from_cert(parsed_cert, public_key)
|
||||
@@ -21,7 +21,7 @@ pub fn verify_cert_from_der(cert: &[u8], public_key: Option<String>) -> anyhow::
|
||||
/// - according to the signature
|
||||
/// - according to the time validity
|
||||
/// - according to the public key (if provided)
|
||||
fn verify_cert_from_cert(cert: X509Certificate, public_key: Option<String>) -> anyhow::Result<()> {
|
||||
fn verify_cert_from_cert(cert: X509Certificate, public_key: Option<&str>) -> anyhow::Result<()> {
|
||||
if !cert.validity.is_valid() {
|
||||
return Err(anyhow::anyhow!("Time validity error"));
|
||||
}
|
||||
@@ -29,7 +29,7 @@ fn verify_cert_from_cert(cert: X509Certificate, public_key: Option<String>) -> a
|
||||
if let Some(public_key) = public_key {
|
||||
let cert_public_key = cert.tbs_certificate.subject_pki.parsed()?;
|
||||
|
||||
let (public_key_pem, _) = Pem::read(Cursor::new(public_key.into_bytes()))?;
|
||||
let (public_key_pem, _) = Pem::read(Cursor::new(public_key.as_bytes()))?;
|
||||
let (_, public_key_spki) = SubjectPublicKeyInfo::from_der(&public_key_pem.contents)?;
|
||||
let expected_public_key = public_key_spki.parsed()?;
|
||||
|
||||
@@ -103,7 +103,7 @@ VRus1zGVD8IVpIdPMyz01WJyS7M0fWaHXKWo+Bo=
|
||||
-----END CERTIFICATE-----"
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
verify_cert_from_pem(cert, Some(PUBLIC_KEY.to_owned())).map_err(|e| e.to_string()),
|
||||
verify_cert_from_pem(cert, Some(PUBLIC_KEY)).map_err(|e| e.to_string()),
|
||||
Ok(())
|
||||
);
|
||||
|
||||
@@ -128,7 +128,7 @@ VRus1zGVD8IVpIdPMyz01WJySwAAAAAAAAAAAAA=
|
||||
-----END CERTIFICATE-----"
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
verify_cert_from_pem(cert_invalid_signature, Some(PUBLIC_KEY.to_owned()))
|
||||
verify_cert_from_pem(cert_invalid_signature, Some(PUBLIC_KEY))
|
||||
.map_err(|e| e.to_string()),
|
||||
Err("signature verification error".to_string())
|
||||
);
|
||||
@@ -154,7 +154,7 @@ eVVihnrJ3sdk7nnreAYMse/OipyufRyZ9t3WU8A=
|
||||
-----END CERTIFICATE-----"
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
verify_cert_from_pem(cert_invalid_public_key, Some(PUBLIC_KEY.to_owned()))
|
||||
verify_cert_from_pem(cert_invalid_public_key, Some(PUBLIC_KEY))
|
||||
.map_err(|e| e.to_string()),
|
||||
Err("Public key mismatch".to_string())
|
||||
);
|
||||
@@ -180,7 +180,7 @@ nidU/qXQvBJ7NPUkXXgbcgqxK735iijOqQHmKts=
|
||||
-----END CERTIFICATE-----"
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
verify_cert_from_pem(cert_expired, Some(PUBLIC_KEY.to_owned()))
|
||||
verify_cert_from_pem(cert_expired, Some(PUBLIC_KEY))
|
||||
.map_err(|e| e.to_string()),
|
||||
Err("Time validity error".to_string())
|
||||
);
|
||||
|
||||
@@ -5,7 +5,31 @@ pub mod v3;
|
||||
pub use v2::LsHttpClientV2;
|
||||
pub use v3::LsHttpClientV3;
|
||||
|
||||
use crate::crypto;
|
||||
use reqwest::Response;
|
||||
|
||||
pub enum LsHttpClient {
|
||||
V2(LsHttpClientV2),
|
||||
V3(LsHttpClientV3),
|
||||
}
|
||||
|
||||
/// Verifies the certificate from the response.
|
||||
/// Returns the public key extracted from the certificate.
|
||||
pub(super) fn verify_cert_from_res(
|
||||
response: &Response,
|
||||
public_key: Option<String>,
|
||||
) -> anyhow::Result<String> {
|
||||
let tls_info_ext = response
|
||||
.extensions()
|
||||
.get::<reqwest::tls::TlsInfo>()
|
||||
.ok_or_else(|| anyhow::anyhow!("TLS info not found"))?;
|
||||
let cert = tls_info_ext
|
||||
.peer_certificate()
|
||||
.ok_or_else(|| anyhow::anyhow!("Certificate not found"))?;
|
||||
crypto::cert::verify_cert_from_der(cert, public_key.as_deref())?;
|
||||
let public_key = match public_key {
|
||||
Some(public_key) => public_key,
|
||||
None => crypto::cert::public_key_from_cert_der(cert)?,
|
||||
};
|
||||
Ok(public_key)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::http::dto_v2::{
|
||||
PrepareUploadResponseDtoV2, ProtocolTypeV2, RegisterDtoV2, RegisterResponseDtoV2,
|
||||
};
|
||||
use crate::http::StatusCodeError;
|
||||
use crate::crypto;
|
||||
use futures_util::StreamExt;
|
||||
use reqwest::{Response, StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -120,7 +119,7 @@ impl LsHttpClientV2 {
|
||||
}
|
||||
|
||||
let public_key = match protocol {
|
||||
ProtocolTypeV2::Https => Some(verify_cert_from_res(&res, None)?),
|
||||
ProtocolTypeV2::Https => Some(super::verify_cert_from_res(&res, None)?),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -186,7 +185,7 @@ impl LsHttpClientV2 {
|
||||
.await?;
|
||||
|
||||
if let Some(public_key) = public_key {
|
||||
verify_cert_from_res(&res, Some(public_key))?;
|
||||
super::verify_cert_from_res(&res, Some(public_key))?;
|
||||
}
|
||||
|
||||
if res.status() == StatusCode::NO_CONTENT {
|
||||
@@ -514,23 +513,6 @@ async fn status_code_error_from_res(response: Response) -> anyhow::Result<anyhow
|
||||
}))
|
||||
}
|
||||
|
||||
/// Verifies the certificate from the response.
|
||||
/// Returns the public key extracted from the certificate.
|
||||
fn verify_cert_from_res(response: &Response, public_key: Option<String>) -> anyhow::Result<String> {
|
||||
let tls_info_ext = response
|
||||
.extensions()
|
||||
.get::<reqwest::tls::TlsInfo>()
|
||||
.ok_or_else(|| anyhow::anyhow!("TLS info not found"))?;
|
||||
let cert = tls_info_ext
|
||||
.peer_certificate()
|
||||
.ok_or_else(|| anyhow::anyhow!("Certificate not found"))?;
|
||||
let public_key = match public_key {
|
||||
Some(public_key) => public_key.to_owned(),
|
||||
None => crypto::cert::public_key_from_cert_der(cert)?,
|
||||
};
|
||||
crypto::cert::verify_cert_from_der(cert, Some(public_key.clone()))?;
|
||||
Ok(public_key)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -142,7 +142,7 @@ impl LsHttpClientV3 {
|
||||
.await?;
|
||||
|
||||
let public_key = match protocol {
|
||||
ProtocolType::Https => Some(verify_cert_from_res(&res, None)?),
|
||||
ProtocolType::Https => Some(super::verify_cert_from_res(&res, None)?),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -174,7 +174,7 @@ impl LsHttpClientV3 {
|
||||
.await?;
|
||||
|
||||
if let Some(public_key) = public_key {
|
||||
verify_cert_from_res(&res, Some(public_key))?;
|
||||
super::verify_cert_from_res(&res, Some(public_key))?;
|
||||
}
|
||||
|
||||
if res.status() != StatusCode::OK {
|
||||
@@ -272,7 +272,7 @@ fn to_identifier(
|
||||
public_key: Option<String>,
|
||||
) -> anyhow::Result<String> {
|
||||
match require_cert {
|
||||
true => verify_cert_from_res(response, public_key),
|
||||
true => super::verify_cert_from_res(response, public_key),
|
||||
false => response
|
||||
.remote_addr()
|
||||
.map(|addr| addr.ip().to_string())
|
||||
@@ -280,20 +280,3 @@ fn to_identifier(
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifies the certificate from the response.
|
||||
/// Returns the public key extracted from the certificate.
|
||||
fn verify_cert_from_res(response: &Response, public_key: Option<String>) -> anyhow::Result<String> {
|
||||
let tls_info_ext = response
|
||||
.extensions()
|
||||
.get::<reqwest::tls::TlsInfo>()
|
||||
.ok_or_else(|| anyhow::anyhow!("TLS info not found"))?;
|
||||
let cert = tls_info_ext
|
||||
.peer_certificate()
|
||||
.ok_or_else(|| anyhow::anyhow!("Certificate not found"))?;
|
||||
let public_key = match public_key {
|
||||
Some(public_key) => public_key.to_owned(),
|
||||
None => crypto::cert::public_key_from_cert_der(cert)?,
|
||||
};
|
||||
crypto::cert::verify_cert_from_der(cert, Some(public_key.clone()))?;
|
||||
Ok(public_key)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user