{"record":{"id":"14749baa2f84a3e3","repo":"gravitational/teleport","slug":"peer-certificate-is-missing","errorCode":null,"errorMessage":"peer certificate is missing","messagePattern":"peer certificate is missing","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/srv/desktop/rdp/rdpclient/src/ssl.rs","lineNumber":55,"sourceCode":"    initial_stream: TcpStream,\n    server_name: &str,\n) -> ClientResult<(TlsStream<TcpStream>, Vec<u8>)> {\n    #[cfg(feature = \"fips\")]\n    {\n        use boring::ssl::{SslConnector, SslMethod, SslVerifyMode};\n        use std::io;\n        use tokio::io::AsyncWriteExt;\n        let mut builder = SslConnector::builder(SslMethod::tls_client())?;\n        builder.set_verify(SslVerifyMode::NONE);\n        builder.set_fips_compliance_policy()?;\n        let configuration = builder.build().configure()?;\n        let mut tls_stream =\n            tokio_boring::connect(configuration, server_name, initial_stream).await?;\n        tls_stream.flush().await?;\n        let cert = tls_stream\n            .ssl()\n            .peer_certificate()\n            .ok_or_else(|| io::Error::new(io::ErrorKind::Other, \"peer certificate is missing\"))?;\n        let public_key = cert.public_key()?;\n        let mut bytes: Vec<u8> = public_key.public_key_to_der()?;\n        // boring uses additional DER element before raw key data compared to rustls, so we have to skip it\n        if bytes.len() >= 24 {\n            bytes.drain(0..24);\n        }\n        Ok((tls_stream, bytes))\n    }\n    #[cfg(not(feature = \"fips\"))]\n    ironrdp_tls::upgrade(initial_stream, server_name)\n        .await\n        .map_err(ClientError::from)\n        .and_then(|upgraded| {\n            // TODO (rhammonds): This is a temporary workaround to get our RDP client\n            // working against the latest changes from IronRDP. We should consider changing\n            // the return value of this function (and the calling code) to handle\n            // a CertificateInner rather than just the raw public key.\n            Ok((","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/srv/desktop/rdp/rdpclient/src/ssl.rs#L37-L73","documentation":"In the RDP client's TLS upgrade, this fires when the server did not present a certificate at all (peer certificate missing) during the non-FIPS verification path — the RDP server closed or misbehaved during the TLS handshake, so identity verification cannot proceed.","triggerScenarios":"Thrown at lib/srv/desktop/rdp/rdpclient/src/ssl.rs:55 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Verify the RDP server supports and is configured for TLS (NLA/TLS)","Check the server address/port and that a firewall is not intercepting the connection","Inspect the RDP server's TLS/certificate configuration"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}