use rc_crypto::certificate::InvalidDer;
use rc_x509_proto::{
decode,
protocol::v1::{self, server_to_client::Message},
};
use rc_x509_trust::cert::UntrustedCert;
use thiserror::Error;
use tokio_util::bytes::Bytes;
use crate::{
connection::{ReconnectionData, UntrustedConnectionId},
host_runtime::CorrelationId,
};
#[derive(Debug, Error)]
pub enum DecodingError {
#[error("deserialisation error: {0}")]
Wire(#[from] rc_x509_proto::DecodeError),
#[error("no message")]
NoMessage,
#[error("invalid certificate DER bytes: {0}")]
InvalidCert(#[from] InvalidDer),
#[error("dispatch request missing detached signature")]
NoDispatchSignature,
}
#[derive(Debug, PartialEq)]
pub enum ServerToClient {
Ping,
CertificatePush(Box<UntrustedCert>),
Dispatch {
correlation_id: CorrelationId,
payload: Bytes,
signature: Bytes,
signing_cert_id: Bytes,
},
ClientHelloAck {
connection_id: UntrustedConnectionId,
},
SetReconnectionData(ReconnectionData),
}
impl TryFrom<&[u8]> for ServerToClient {
type Error = DecodingError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let got: v1::ServerToClient = decode::<_>(value)?;
Ok(match got.message.ok_or(DecodingError::NoMessage)? {
Message::Ping(_) => Self::Ping,
Message::Dispatch(v) => {
let detached = v.signature.ok_or(DecodingError::NoDispatchSignature)?;
Self::Dispatch {
correlation_id: CorrelationId::new(v.correlation_id),
payload: v.encoded_dispatch_request,
signature: detached.signature,
signing_cert_id: detached.cert_id,
}
}
Message::CertificatePush(cert) => {
Self::CertificatePush(Box::new(UntrustedCert::from_der(cert.der)?))
}
Message::ClientHelloAck(v) => Self::ClientHelloAck {
connection_id: UntrustedConnectionId::new(
v.server_nonce,
v.connection_id.unwrap_or_default().uuid_v8,
),
},
Message::SetReconnectionData(v) => {
Self::SetReconnectionData(ReconnectionData::new(v.opaque))
}
})
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use proptest::prelude::*;
use rc_x509_proto::signature::v1::DetachedSignature;
use tokio_util::bytes::Bytes;
use super::*;
const SAMPLE_CERT_DER: &[u8] = &[
48, 130, 2, 90, 48, 130, 2, 0, 160, 3, 2, 1, 2, 2, 17, 0, 226, 123, 148, 183, 60, 61, 8,
186, 223, 69, 141, 86, 122, 165, 225, 100, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 48,
86, 49, 33, 48, 31, 6, 3, 85, 4, 10, 12, 24, 76, 97, 32, 70, 195, 161, 98, 114, 105, 99,
97, 32, 100, 101, 32, 80, 108, 195, 161, 116, 97, 110, 111, 115, 49, 49, 48, 47, 6, 3, 85,
4, 3, 12, 40, 76, 97, 32, 70, 195, 161, 98, 114, 105, 99, 97, 32, 100, 101, 32, 80, 108,
195, 161, 116, 97, 110, 111, 115, 32, 73, 110, 116, 101, 114, 109, 101, 100, 105, 97, 116,
101, 32, 67, 65, 48, 30, 23, 13, 50, 53, 48, 56, 49, 51, 49, 52, 53, 56, 52, 48, 90, 23,
13, 51, 53, 48, 56, 49, 49, 49, 52, 53, 57, 52, 48, 90, 48, 27, 49, 25, 48, 23, 6, 3, 85,
4, 3, 19, 16, 105, 116, 115, 97, 108, 108, 98, 114, 111, 107, 101, 110, 46, 99, 111, 109,
48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3,
66, 0, 4, 65, 203, 37, 195, 17, 244, 252, 127, 57, 240, 189, 145, 113, 66, 58, 172, 101,
61, 238, 25, 177, 6, 189, 193, 109, 213, 242, 99, 48, 199, 60, 29, 12, 43, 199, 236, 245,
159, 91, 235, 138, 161, 254, 203, 63, 15, 87, 103, 161, 117, 126, 100, 211, 195, 86, 49,
27, 83, 89, 231, 161, 143, 165, 65, 163, 129, 233, 48, 129, 230, 48, 14, 6, 3, 85, 29, 15,
1, 1, 255, 4, 4, 3, 2, 7, 128, 48, 29, 6, 3, 85, 29, 37, 4, 22, 48, 20, 6, 8, 43, 6, 1, 5,
5, 7, 3, 1, 6, 8, 43, 6, 1, 5, 5, 7, 3, 2, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 220,
141, 182, 39, 82, 120, 88, 76, 253, 162, 67, 219, 203, 43, 224, 87, 104, 110, 43, 142, 48,
31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 32, 108, 142, 207, 228, 33, 167, 255, 237,
35, 200, 61, 55, 15, 119, 129, 132, 113, 14, 21, 48, 27, 6, 3, 85, 29, 17, 4, 20, 48, 18,
130, 16, 105, 116, 115, 97, 108, 108, 98, 114, 111, 107, 101, 110, 46, 99, 111, 109, 48,
88, 6, 12, 43, 6, 1, 4, 1, 130, 164, 100, 198, 40, 64, 1, 4, 72, 48, 70, 2, 1, 1, 4, 20,
100, 111, 109, 64, 105, 116, 115, 97, 108, 108, 98, 114, 111, 107, 101, 110, 46, 99, 111,
109, 4, 43, 108, 104, 77, 88, 53, 54, 85, 81, 85, 66, 53, 101, 50, 115, 111, 71, 88, 115,
55, 100, 81, 112, 78, 112, 95, 45, 99, 111, 95, 65, 83, 55, 116, 118, 74, 104, 66, 107, 45,
104, 113, 73, 107, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 32,
13, 66, 176, 173, 88, 141, 30, 140, 88, 114, 201, 215, 41, 178, 186, 144, 230, 244, 165,
47, 110, 143, 33, 96, 99, 186, 177, 44, 23, 184, 189, 39, 2, 33, 0, 196, 215, 99, 22, 117,
28, 241, 129, 103, 141, 230, 96, 70, 132, 116, 196, 120, 237, 137, 80, 148, 220, 48, 43,
238, 55, 201, 48, 193, 70, 7, 123,
];
fn round_trip(v: &v1::ServerToClient) -> Result<ServerToClient, DecodingError> {
ServerToClient::try_from(rc_x509_proto::encode(v).as_slice())
}
#[test]
fn test_bad_wire_encoding() {
let got = ServerToClient::try_from([42].as_slice());
assert_matches!(got, Err(DecodingError::Wire(_)));
}
#[test]
fn test_no_message() {
let got = round_trip(&v1::ServerToClient { message: None });
assert_matches!(got, Err(DecodingError::NoMessage));
}
fn arbitrary_server_to_client() -> impl Strategy<Value = v1::ServerToClient> {
any::<v1::server_to_client::Message>()
.prop_map(|mut v| {
match &mut v {
Message::CertificatePush(certificate) => {
certificate.der = Bytes::from(SAMPLE_CERT_DER);
}
Message::Dispatch(dispatch) => {
if dispatch.signature.is_none() {
dispatch.signature = Some(DetachedSignature::default());
}
}
_ => {}
}
v
})
.prop_map(|v| v1::ServerToClient { message: Some(v) })
}
proptest! {
#[test]
fn prop_valid_message_deserialisation(
a in arbitrary_server_to_client(),
b in arbitrary_server_to_client(),
) {
let a_out = round_trip(&a).unwrap();
let b_out = round_trip(&b).unwrap();
assert_eq!(a_out, round_trip(&a).unwrap());
assert_eq!(b_out, round_trip(&b).unwrap());
let a_msg = a.message.unwrap();
let b_msg = b.message.unwrap();
assert_eq!(
a_msg == b_msg,
a_out == b_out,
);
}
}
}