diff --git a/Cargo.lock b/Cargo.lock index 2b42801af1680..66ec879099510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,6 +186,26 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2 1.0.63", + "quote 1.0.29", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.32", +] + [[package]] name = "bit_field" version = "0.10.2" @@ -243,6 +263,31 @@ dependencies = [ "generic-array", ] +[[package]] +name = "boring" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae1aba472e42d3cf45ac6d0a6c8fc3ddf743871209e1b40229aed9fbdf48ece" +dependencies = [ + "bitflags 2.4.1", + "boring-sys", + "foreign-types", + "libc", + "once_cell", +] + +[[package]] +name = "boring-sys" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceced5be0047c7c48d77599535fd7f0a81c1b0f0a1e97e7eece24c45022bb481" +dependencies = [ + "bindgen", + "cmake", + "fs_extra", + "fslock", +] + [[package]] name = "bumpalo" version = "3.11.1" @@ -298,6 +343,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -340,6 +394,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "3.2.23" @@ -364,6 +429,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -765,6 +839,33 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2 1.0.63", + "quote 1.0.29", + "syn 2.0.32", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -774,6 +875,22 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "funty" version = "2.0.0" @@ -910,6 +1027,12 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "group" version = "0.13.0" @@ -1213,9 +1336,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "ironrdp" @@ -1413,7 +1536,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d47365efc3b4c252f8a3384445c0f7e8a4e0ae5c22bf3bedd2dd16f9bb45016a" dependencies = [ - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -1449,12 +1572,28 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + [[package]] name = "libm" version = "0.2.6" @@ -1860,6 +1999,12 @@ dependencies = [ "sha2 0.10.6", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem-rfc7468" version = "0.3.1" @@ -2224,6 +2369,7 @@ name = "rdp-client" version = "0.1.0" dependencies = [ "bitflags 2.4.1", + "boring", "byteorder", "bytes", "cbindgen", @@ -2252,6 +2398,7 @@ dependencies = [ "static_init", "tempfile", "tokio", + "tokio-boring", "utf16string", "uuid", "x509-parser", @@ -2355,17 +2502,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" dependencies = [ "cc", + "getrandom 0.2.8", "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "spin 0.9.4", + "untrusted", + "windows-sys 0.48.0", ] [[package]] @@ -2414,6 +2560,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2461,9 +2613,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring", @@ -2494,12 +2646,12 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", - "untrusted 0.7.1", + "untrusted", ] [[package]] @@ -2525,12 +2677,12 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", - "untrusted 0.7.1", + "untrusted", ] [[package]] @@ -2693,6 +2845,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -3077,6 +3235,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-boring" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961385cffda2112d02c6e17169965ed604b9953078f2ec55740b8cf7b55c122e" +dependencies = [ + "boring", + "boring-sys", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.1.0" @@ -3298,12 +3467,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/lib/srv/desktop/rdp/rdpclient/Cargo.toml b/lib/srv/desktop/rdp/rdpclient/Cargo.toml index abdfcaf69d51b..82e35e1cbe897 100644 --- a/lib/srv/desktop/rdp/rdpclient/Cargo.toml +++ b/lib/srv/desktop/rdp/rdpclient/Cargo.toml @@ -26,7 +26,7 @@ png = "0.17.10" parking_lot = "0.12.1" bytes = "1" -tokio = { version = "1.32", features = ["full"]} +tokio = { version = "1.32", features = ["full"] } x509-parser = "0.14" sspi = { version = "0.10.1", features = ["network_client", "dns_resolver"] } static_init = "1.0.3" @@ -59,7 +59,12 @@ ironrdp-cliprdr = { git = "https://github.com/Devolutions/IronRDP", rev = "20758 # ironrdp-pdu = { path = "/Users/hesperus/work/IronRDP/crates/ironrdp-pdu" } # ironrdp-tokio = { path = "/Users/hesperus/work/IronRDP/crates/ironrdp-tokio" } +tokio-boring = { version = "3.1.0", optional = true } +boring = { version = "3.1.0", optional = true } [build-dependencies] cbindgen = "0.26.0" tempfile = "3.8.1" + +[features] +fips = ["tokio-boring/fips", "boring/fips"] diff --git a/lib/srv/desktop/rdp/rdpclient/src/client.rs b/lib/srv/desktop/rdp/rdpclient/src/client.rs index 11c1e9b1da433..f2b739cb0634f 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/client.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/client.rs @@ -1,10 +1,27 @@ +// Copyright 2023 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + pub mod global; use crate::rdpdr::tdp; use crate::{ - handle_fastpath_pdu, handle_rdp_channel_ids, handle_remote_copy, CGOErrCode, CGOKeyboardEvent, - CGOMousePointerEvent, CGOPointerButton, CGOPointerWheel, CgoHandle, + handle_fastpath_pdu, handle_rdp_channel_ids, handle_remote_copy, ssl, CGOErrCode, + CGOKeyboardEvent, CGOMousePointerEvent, CGOPointerButton, CGOPointerWheel, CgoHandle, }; +use bitflags::Flags; +#[cfg(feature = "fips")] +use boring::error::ErrorStack; use bytes::BytesMut; pub(crate) use global::call_function_on_handle; use ironrdp_cliprdr::{Cliprdr, CliprdrSvcMessages}; @@ -24,7 +41,6 @@ use ironrdp_session::x224::{Processor as X224Processor, Processor}; use ironrdp_session::SessionErrorKind::Reason; use ironrdp_session::{reason_err, SessionError, SessionResult}; use ironrdp_svc::{StaticVirtualChannelProcessor, SvcMessage, SvcProcessorMessages}; -use ironrdp_tls::TlsStream; use ironrdp_tokio::{Framed, TokioStream}; use rand::{Rng, SeedableRng}; use std::fmt::{Debug, Display, Formatter}; @@ -39,6 +55,9 @@ use tokio::task::JoinError; use crate::cliprdr::{ClipboardFn, TeleportCliprdrBackend}; use crate::rdpdr::scard::SCARD_DEVICE_ID; use crate::rdpdr::TeleportRdpdrBackend; +use crate::ssl::TlsStream; +#[cfg(feature = "fips")] +use tokio_boring::{HandshakeError, SslStream}; /// The RDP client on the Rust side of things. Each `Client` /// corresponds with a Go `Client` specified by `cgo_handle`. @@ -130,7 +149,7 @@ impl Client { // Take the stream back out of the framed object for upgrading let initial_stream = framed.into_inner_no_leftover(); let (upgraded_stream, server_public_key) = - ironrdp_tls::upgrade(initial_stream, &server_socket_addr.ip().to_string()).await?; + ssl::upgrade(initial_stream, &server_socket_addr.ip().to_string()).await?; // Upgrade the stream let upgraded = @@ -648,6 +667,10 @@ pub enum ClientError { InternalError, UnknownAddress, InputEventError(InputEventError), + #[cfg(feature = "fips")] + ErrorStack(ErrorStack), + #[cfg(feature = "fips")] + HandshakeError(HandshakeError), } impl Display for ClientError { @@ -667,6 +690,10 @@ impl Display for ClientError { ClientError::InternalError => Display::fmt("Internal error", f), ClientError::UnknownAddress => Display::fmt("Unknown address", f), ClientError::PduError(e) => Display::fmt(e, f), + #[cfg(feature = "fips")] + ClientError::ErrorStack(e) => Display::fmt(e, f), + #[cfg(feature = "fips")] + ClientError::HandshakeError(e) => Display::fmt(e, f), } } } @@ -719,7 +746,21 @@ impl From for ClientError { } } -type ClientResult = Result; +#[cfg(feature = "fips")] +impl From for ClientError { + fn from(e: ErrorStack) -> Self { + ClientError::ErrorStack(e) + } +} + +#[cfg(feature = "fips")] +impl From> for ClientError { + fn from(e: HandshakeError) -> Self { + ClientError::HandshakeError(e) + } +} + +pub type ClientResult = Result; impl From for ClientResult<()> { fn from(value: CGOErrCode) -> Self { diff --git a/lib/srv/desktop/rdp/rdpclient/src/client/global.rs b/lib/srv/desktop/rdp/rdpclient/src/client/global.rs index b1c5230368532..f038fdf3635ed 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/client/global.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/client/global.rs @@ -1,3 +1,17 @@ +// Copyright 2023 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + //! This module contains static structures which are used in common by all //! desktop sessions on a given windows_desktop_service. //! diff --git a/lib/srv/desktop/rdp/rdpclient/src/lib.rs b/lib/srv/desktop/rdp/rdpclient/src/lib.rs index 0df678f48de19..f9ccedfc8e83d 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/lib.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/lib.rs @@ -46,6 +46,7 @@ pub mod client; mod cliprdr; mod piv; mod rdpdr; +mod ssl; mod util; #[no_mangle] diff --git a/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs b/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs index e42d0f4ec3619..c96f3a4e7742d 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs @@ -1,3 +1,17 @@ +// Copyright 2023 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use super::path::UnixPath; use crate::{ util::{self, from_c_string, from_go_array}, diff --git a/lib/srv/desktop/rdp/rdpclient/src/ssl.rs b/lib/srv/desktop/rdp/rdpclient/src/ssl.rs new file mode 100644 index 0000000000000..3eb262b373c26 --- /dev/null +++ b/lib/srv/desktop/rdp/rdpclient/src/ssl.rs @@ -0,0 +1,67 @@ +/* + * + * Copyright 2021 Gravitational, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +use static_init::dynamic; +use tokio::net::TcpStream; + +use crate::client::{ClientError, ClientResult}; + +#[cfg(feature = "fips")] +pub type TlsStream = tokio_boring::SslStream; + +#[cfg(feature = "fips")] +#[dynamic(0)] +static mut FIPS_CHECK: () = unsafe { + // Make sure that we really have FIPS enabled. + // This assert will run at the start of the program and panic if we + // build for FIPS but it's somehow disabled + use boring; + assert!(boring::fips::enabled(), "FIPS mode not enabled"); +}; + +#[cfg(not(feature = "fips"))] +pub type TlsStream = ironrdp_tls::TlsStream; + +pub(crate) async fn upgrade( + initial_stream: TcpStream, + server_name: &str, +) -> ClientResult<(TlsStream, Vec)> { + #[cfg(feature = "fips")] + { + use boring::ssl::{SslConnector, SslMethod, SslVerifyMode}; + use std::io; + use tokio::io::AsyncWriteExt; + let mut builder = SslConnector::builder(SslMethod::tls_client())?; + builder.set_verify(SslVerifyMode::NONE); + let configuration = builder.build().configure()?; + let mut tls_stream = + tokio_boring::connect(configuration, server_name, initial_stream).await?; + tls_stream.flush().await?; + let cert = tls_stream + .ssl() + .peer_certificate() + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "peer certificate is missing"))?; + let public_key = cert.public_key()?; + let bytes = public_key.public_key_to_der()?; + Ok((tls_stream, bytes)) + } + #[cfg(not(feature = "fips"))] + ironrdp_tls::upgrade(initial_stream, server_name) + .await + .map_err(ClientError::from) +} diff --git a/web/packages/teleport/src/ironrdp/src/lib.rs b/web/packages/teleport/src/ironrdp/src/lib.rs index 1172c2a67b2ac..44d2f01878aab 100644 --- a/web/packages/teleport/src/ironrdp/src/lib.rs +++ b/web/packages/teleport/src/ironrdp/src/lib.rs @@ -1,4 +1,18 @@ #![allow(clippy::new_without_default)] // default trait not supported in wasm +// Copyright 2023 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #[macro_use] extern crate log;