This commit is contained in:
parent
6e5c985719
commit
eaae9b0d13
41 changed files with 1695 additions and 655 deletions
|
|
@ -14,14 +14,14 @@ pub(crate) fn unexpected_response_type_error(
|
|||
))
|
||||
}
|
||||
|
||||
pub(crate) fn verify_host_challenge(
|
||||
pub(crate) async fn verify_host_challenge(
|
||||
challenge: &CommunicationValue,
|
||||
host_pk: &mtp_crypto::PublicKeyBundle,
|
||||
id: u64,
|
||||
server_challenge: u128,
|
||||
require_pq: bool,
|
||||
) -> Result<(), CommunicationError> {
|
||||
use mtp_crypto::{auth, verify_ed25519, verify_ml_dsa};
|
||||
use mtp_crypto::{auth, verify_ed25519};
|
||||
|
||||
let sig = match challenge.get_data(DataType::Signature) {
|
||||
DataValue::Bytes(b) => b.clone(),
|
||||
|
|
@ -49,18 +49,27 @@ pub(crate) fn verify_host_challenge(
|
|||
}
|
||||
|
||||
let payload = auth::challenge_payload(id, server_challenge);
|
||||
verify_ed25519(&host_pk.sig_cl_public_key, &payload, &sig).map_err(|_| {
|
||||
CommunicationError::AuthenticationFailed("Host challenge signature invalid".into())
|
||||
})?;
|
||||
if !pq_sig.is_empty() && verify_ml_dsa(&host_pk.sig_pq_public_key, &payload, &pq_sig).is_err() {
|
||||
return Err(CommunicationError::AuthenticationFailed(
|
||||
"Host challenge PQ signature invalid".into(),
|
||||
));
|
||||
if pq_sig.is_empty() {
|
||||
verify_ed25519(&host_pk.sig_cl_public_key, &payload, &sig).map_err(|_| {
|
||||
CommunicationError::AuthenticationFailed("Host challenge signature invalid".into())
|
||||
})?;
|
||||
} else {
|
||||
mtp_crypto::sign_parallel::verify_dual_parallel(
|
||||
host_pk.sig_cl_public_key.clone(),
|
||||
host_pk.sig_pq_public_key.clone(),
|
||||
payload,
|
||||
sig,
|
||||
pq_sig,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| {
|
||||
CommunicationError::AuthenticationFailed("Host challenge signature invalid".into())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn verify_host_final(
|
||||
pub(crate) async fn verify_host_final(
|
||||
response: &CommunicationValue,
|
||||
host_pk: &mtp_crypto::PublicKeyBundle,
|
||||
id: u64,
|
||||
|
|
@ -68,7 +77,7 @@ pub(crate) fn verify_host_final(
|
|||
server_challenge: u128,
|
||||
require_pq: bool,
|
||||
) -> Result<(), CommunicationError> {
|
||||
use mtp_crypto::{auth, verify_ed25519, verify_ml_dsa};
|
||||
use mtp_crypto::{auth, verify_ed25519};
|
||||
|
||||
match response.get_data(DataType::ClientNonce) {
|
||||
DataValue::UnsignedNumber(n) if *n == client_nonce => {}
|
||||
|
|
@ -98,12 +107,20 @@ pub(crate) fn verify_host_final(
|
|||
}
|
||||
|
||||
let payload = auth::host_final_payload(id, client_nonce, server_challenge);
|
||||
verify_ed25519(&host_pk.sig_cl_public_key, &payload, &sig)
|
||||
if pq_sig.is_empty() {
|
||||
verify_ed25519(&host_pk.sig_cl_public_key, &payload, &sig).map_err(|_| {
|
||||
CommunicationError::AuthenticationFailed("Host signature invalid".into())
|
||||
})?;
|
||||
} else {
|
||||
mtp_crypto::sign_parallel::verify_dual_parallel(
|
||||
host_pk.sig_cl_public_key.clone(),
|
||||
host_pk.sig_pq_public_key.clone(),
|
||||
payload,
|
||||
sig,
|
||||
pq_sig,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| CommunicationError::AuthenticationFailed("Host signature invalid".into()))?;
|
||||
if !pq_sig.is_empty() && verify_ml_dsa(&host_pk.sig_pq_public_key, &payload, &pq_sig).is_err() {
|
||||
return Err(CommunicationError::AuthenticationFailed(
|
||||
"Host PQ signature invalid".into(),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -141,33 +158,36 @@ pub(crate) fn negotiated_version(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn signed_challenge_response(
|
||||
pub(crate) async fn signed_challenge_response(
|
||||
keys: &mtp_crypto::Keyring,
|
||||
proof_payload: &[u8],
|
||||
proof_payload: Vec<u8>,
|
||||
client_nonce: u128,
|
||||
) -> Result<CommunicationValue, CommunicationError> {
|
||||
use mtp_crypto::{Ed25519Signer, MlDsaSigner, SignatureScheme};
|
||||
|
||||
let signer = Ed25519Signer::new(&keys.sig_cl_secret_key)
|
||||
.map_err(|e| CommunicationError::Other(e.to_string()))?;
|
||||
let signature = signer
|
||||
.sign(proof_payload)
|
||||
.map_err(|e| CommunicationError::Other(e.to_string()))?;
|
||||
|
||||
let mut proof = CommunicationValue::new(CommunicationType::ChallengeResponse)
|
||||
.add_typed_default(
|
||||
DataType::ClientNonce,
|
||||
DataValue::UnsignedNumber(client_nonce),
|
||||
)
|
||||
.add_typed_default(DataType::Signature, DataValue::Bytes(signature));
|
||||
);
|
||||
|
||||
if !keys.sig_pq_secret_key.as_bytes().is_empty() {
|
||||
if keys.sig_pq_secret_key.as_bytes().is_empty() {
|
||||
let signature = signer
|
||||
.sign(&proof_payload)
|
||||
.map_err(|e| CommunicationError::Other(e.to_string()))?;
|
||||
proof = proof.add_typed_default(DataType::Signature, DataValue::Bytes(signature));
|
||||
} else {
|
||||
let pq_signer = MlDsaSigner::new(&keys.sig_pq_secret_key, &keys.sig_pq_public_key)
|
||||
.map_err(|e| CommunicationError::Other(e.to_string()))?;
|
||||
let pq_signature = pq_signer
|
||||
.sign(proof_payload)
|
||||
.map_err(|e| CommunicationError::Other(e.to_string()))?;
|
||||
proof = proof.add_typed_default(DataType::PqSignature, DataValue::Bytes(pq_signature));
|
||||
let (signature, pq_signature) =
|
||||
mtp_crypto::sign_parallel::sign_dual_parallel(signer, pq_signer, proof_payload)
|
||||
.await
|
||||
.map_err(|e| CommunicationError::Other(e.to_string()))?;
|
||||
proof = proof
|
||||
.add_typed_default(DataType::Signature, DataValue::Bytes(signature))
|
||||
.add_typed_default(DataType::PqSignature, DataValue::Bytes(pq_signature));
|
||||
}
|
||||
|
||||
Ok(proof)
|
||||
|
|
@ -212,7 +232,8 @@ pub(crate) async fn receive_verified_challenge(
|
|||
bound_id,
|
||||
server_challenge,
|
||||
require_pq,
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(server_challenge)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ impl MTPClient {
|
|||
CommunicationError::Other("host returned an invalid negotiated version".into())
|
||||
})?,
|
||||
mtp_common::HandshakeOutcome::Rejected { reason } => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(CommunicationError::Other(reason.to_string()));
|
||||
}
|
||||
};
|
||||
|
|
@ -192,7 +192,7 @@ impl MTPClient {
|
|||
ident = ident.add_typed_default(DataType::Description, DataValue::Str(desc.clone()));
|
||||
}
|
||||
if let Err(e) = sender.send(&ident).await {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ impl MTPClient {
|
|||
{
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
|
@ -222,22 +222,23 @@ impl MTPClient {
|
|||
client_nonce,
|
||||
);
|
||||
|
||||
let proof = match crypto::signed_challenge_response(keys, &proof_payload, client_nonce) {
|
||||
let proof = match crypto::signed_challenge_response(keys, proof_payload, client_nonce).await
|
||||
{
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
if let Err(e) = sender.send(&proof).await {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
let response = match receiver.receive().await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
|
@ -249,7 +250,7 @@ impl MTPClient {
|
|||
)
|
||||
})?;
|
||||
if response.get_type() != expected_type {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(crypto::unexpected_response_type_error(
|
||||
"auth_connect",
|
||||
expected_type,
|
||||
|
|
@ -257,7 +258,7 @@ impl MTPClient {
|
|||
));
|
||||
}
|
||||
if let Err(e) = crypto::check_connected(&response, "Server rejected authentication") {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
if let Err(e) = crypto::verify_host_final(
|
||||
|
|
@ -267,8 +268,10 @@ impl MTPClient {
|
|||
client_nonce,
|
||||
server_challenge,
|
||||
config.require_pq,
|
||||
) {
|
||||
sender.close();
|
||||
)
|
||||
.await
|
||||
{
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
|
|
@ -340,7 +343,7 @@ impl MTPClient {
|
|||
register.add_typed_default(DataType::Description, DataValue::Str(desc.clone()));
|
||||
}
|
||||
if let Err(e) = sender.send(®ister).await {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +360,7 @@ impl MTPClient {
|
|||
{
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
|
@ -370,22 +373,23 @@ impl MTPClient {
|
|||
client_nonce,
|
||||
);
|
||||
|
||||
let proof = match crypto::signed_challenge_response(keys, &proof_payload, client_nonce) {
|
||||
let proof = match crypto::signed_challenge_response(keys, proof_payload, client_nonce).await
|
||||
{
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
if let Err(e) = sender.send(&proof).await {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
let response = match receiver.receive().await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
|
@ -395,7 +399,7 @@ impl MTPClient {
|
|||
CommunicationError::Other("RegisterResponse is absent from the type map".into())
|
||||
})?;
|
||||
if response.get_type() != expected_type {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(crypto::unexpected_response_type_error(
|
||||
"auth_register",
|
||||
expected_type,
|
||||
|
|
@ -403,13 +407,13 @@ impl MTPClient {
|
|||
));
|
||||
}
|
||||
if let Err(e) = crypto::check_connected(&response, "Server rejected registration") {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
let assigned_id = match response.get_data(DataType::Id) {
|
||||
DataValue::UnsignedNumber(n) => *n as u64,
|
||||
_ => {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
return Err(CommunicationError::AuthenticationFailed(
|
||||
"Missing assigned ID".into(),
|
||||
));
|
||||
|
|
@ -422,8 +426,10 @@ impl MTPClient {
|
|||
client_nonce,
|
||||
server_challenge,
|
||||
config.require_pq,
|
||||
) {
|
||||
sender.close();
|
||||
)
|
||||
.await
|
||||
{
|
||||
sender.close().await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ pub(crate) fn start_ping_session(
|
|||
}
|
||||
_ = ticker.tick() => {
|
||||
if max_missed_pings > 0 && !pending.is_empty() && pending.len() >= max_missed_pings {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ pub(crate) fn start_ping_session(
|
|||
}
|
||||
let id = ping.get_id();
|
||||
if sender.send(&ping).await.is_err() {
|
||||
sender.close();
|
||||
sender.close().await;
|
||||
break;
|
||||
}
|
||||
pending.insert(id, Instant::now());
|
||||
|
|
|
|||
Loading…
Reference in a new issue