diff --git a/core/src/crypto/cert.rs b/core/src/crypto/cert.rs index 507b6ea6..10c5d6bb 100644 --- a/core/src/crypto/cert.rs +++ b/core/src/crypto/cert.rs @@ -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) -> 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) -> 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) -> 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) -> 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) -> 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()) ); diff --git a/core/src/http/client/mod.rs b/core/src/http/client/mod.rs index b34862fc..8d7230bb 100644 --- a/core/src/http/client/mod.rs +++ b/core/src/http/client/mod.rs @@ -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, +) -> anyhow::Result { + let tls_info_ext = response + .extensions() + .get::() + .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) +} diff --git a/core/src/http/client/v2.rs b/core/src/http/client/v2.rs index 8aa311b9..c1e877c3 100644 --- a/core/src/http/client/v2.rs +++ b/core/src/http/client/v2.rs @@ -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::Result { - let tls_info_ext = response - .extensions() - .get::() - .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 { diff --git a/core/src/http/client/v3.rs b/core/src/http/client/v3.rs index 68a25f19..527c0e40 100644 --- a/core/src/http/client/v3.rs +++ b/core/src/http/client/v3.rs @@ -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, ) -> anyhow::Result { 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) -> anyhow::Result { - let tls_info_ext = response - .extensions() - .get::() - .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) -}