Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Devolutions/IronRDP/llms.txt

Use this file to discover all available pages before exploring further.

The Remote Desktop Protocol (RDP) is Microsoft’s proprietary protocol for remote desktop access, enabling graphical session control over network connections. IronRDP provides a robust, security-focused implementation in Rust.

Protocol Architecture

RDP operates as a multi-layered protocol stack, with each layer providing specific functionality:

Transport Layer (TPKT/TPDU)

The foundation uses ISO transport protocols:
  • TPKT (RFC 1006): Provides packet framing over TCP
  • TPDU (ISO 8073): Connection-Oriented Transport Protocol
IronRDP implements these in ironrdp-pdu/src/tpkt.rs and ironrdp-pdu/src/tpdu.rs.

Connection Layer (X.224)

X.224 handles connection establishment and data transfer. The protocol begins with a Connection Request (CR) and Connection Confirm (CC) exchange.
// From ironrdp-connector
let connection_request = nego::ConnectionRequest {
    nego_data: Some(nego::NegoRequestData::cookie(username)),
    flags: nego::RequestFlags::empty(),
    protocol: security_protocol,
};
See ironrdp-pdu/src/x224.rs for the X.224 implementation.

MCS Layer (T.125)

Multipoint Communication Service (MCS) manages multiple channels over a single connection:
  • Domain attachment: Client joins an MCS domain
  • Channel management: Up to 32 static channels (including the mandatory I/O channel)
  • User attachment: Associates users with channels
The MCS layer is implemented in ironrdp-pdu/src/mcs.rs using ASN.1 PER encoding (ironrdp-pdu/src/per.rs).

RDP Layer

The application layer handles:
  • Capability negotiation
  • Graphics rendering
  • Input event processing
  • Virtual channel data

Security Protocols

IronRDP enforces modern security practices by design.

Standard RDP Security (Deprecated)

The legacy RC4-based security is not supported in IronRDP:
if security_protocol.is_standard_rdp_security() {
    return Err(reason_err!("Initiation", "standard RDP security is not supported"));
}
Why? Standard RDP Security exposes significant attack surface:
  • No pre-authentication
  • Full session establishment before credential validation
  • Vulnerable to MITM attacks
  • Exposes static channels (clipboard, drive redirection, etc.) to attackers
See ironrdp-connector/src/connection.rs:266-268.

Enhanced RDP Security (TLS)

TLS wraps the RDP connection after X.224 negotiation:
if self.config.enable_tls {
    security_protocol.insert(nego::SecurityProtocol::SSL);
}
This mode still shows a graphical login screen, initiating the full Windows login subsystem (winlogon.exe, GDI, LogonUI.exe) before authentication completes. While more secure than Standard RDP, it remains vulnerable because:
  • The entire RDP session is established pre-authentication
  • All static channels are joined and active
  • Server and client attack surfaces are exposed
Security Recommendation: Set enable_tls to false to enforce NLA when connecting to CredSSP-capable servers.

Network Level Authentication (CredSSP)

NLA using CredSSP provides authentication before session establishment:
if self.config.enable_credssp {
    security_protocol.insert(
        nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX
    );
}
Benefits:
  • Authentication occurs before RDP session initialization
  • Dramatically reduced attack surface
  • Early user authorization result PDU support (HYBRID_EX)
  • Server can deny access before credentials are fully submitted
IronRDP uses the sspi crate for CredSSP implementation. See ironrdp-connector/src/credssp.rs.

Protocol Phases

RDP connection establishment follows a strict sequence:
1
Connection Initiation
2
Client and server negotiate security protocols via X.224 Connection Request/Confirm.
3
// ironrdp-connector/src/connection.rs:270-279
let connection_request = nego::ConnectionRequest {
    nego_data: self.config.request_data.clone().or_else(|| {
        self.config.credentials.username()
            .map(|username| nego::NegoRequestData::cookie(username.to_owned()))
    }),
    flags: nego::RequestFlags::empty(),
    protocol: security_protocol,
};
4
Enhanced Security Upgrade
5
TLS handshake occurs here (handled externally by user code in IronRDP).
6
CredSSP (Optional)
7
Network Level Authentication via CredSSP if negotiated.
8
Basic Settings Exchange
9
Client and server exchange GCC (Global Conference Control) blocks via MCS Connect-Initial and Connect-Response PDUs:
10
  • Client Core Data: Desktop size, color depth, keyboard layout, client name
  • Client Security Data: Encryption methods
  • Client Network Data: Requested static virtual channels
  • Server Core Data: RDP version, early capability flags
  • Server Security Data: Server random, certificates
  • Server Network Data: Assigned channel IDs
  • 11
    See ironrdp-connector/src/connection.rs:638-738 for GCC block creation.
    12
    Channel Connection
    13
    Each static channel is joined using MCS Channel Join Request/Confirm. The server may skip this step if it advertises SKIP_CHANNELJOIN_SUPPORTED.
    14
    Secure Settings Exchange
    15
    Client sends Client Info PDU containing:
    16
  • Username, password, domain
  • Compression preferences
  • Alternate shell and working directory
  • Client address and timezone
  • Performance flags
  • 17
    See ironrdp-connector/src/connection.rs:741-815.
    18
    Licensing Exchange
    19
    Server sends licensing information. IronRDP supports license caching via the LicenseCache trait.
    20
    Capabilities Exchange
    21
    Server sends Demand Active PDU with capability sets:
    22
  • General capabilities
  • Bitmap capabilities
  • Order capabilities
  • Virtual channel capabilities
  • Pointer capabilities
  • Input capabilities
  • 23
    Client responds with Confirm Active PDU.
    24
    Connection Finalization
    25
    Client and server exchange finalization PDUs:
    26
  • Synchronize PDU
  • Control Cooperate PDU
  • Control Granted Control PDU
  • Font Map PDU
  • PDU Structure

    All RDP PDUs follow this basic structure:
    [ TPKT Header (4 bytes) ]
    [ X.224 Data TPDU (3 bytes) ]
    [ MCS PDU (variable) ]
      [ Security Header (variable) ]
      [ Share Control Header (6 bytes) ]
      [ Share Data Header (variable) ]
      [ PDU-specific data ]
    
    IronRDP uses a trait-based encoding/decoding system:
    pub trait Encode {
        fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()>;
        fn name(&self) -> &'static str;
        fn size(&self) -> usize;
    }
    
    pub trait Decode {
        fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self>;
    }
    
    See ironrdp-core for core encoding primitives.

    Configuration Example

    use ironrdp_connector::{Config, Credentials, DesktopSize};
    
    let config = Config {
        desktop_size: DesktopSize { width: 1920, height: 1080 },
        enable_tls: false,           // Disable TLS to enforce NLA
        enable_credssp: true,        // Enable NLA for security
        credentials: Credentials::UsernamePassword {
            username: "user".to_string(),
            password: "pass".to_string(),
        },
        domain: Some("DOMAIN".to_string()),
        // ... other fields
    };
    

    References

    • [MS-RDPBCGR]: Remote Desktop Protocol: Basic Connectivity and Graphics Remoting
    • [MS-RDPELE]: Remote Desktop Protocol: Licensing Extension
    • [MS-CSSP]: Credential Security Support Provider Protocol
    • IronRDP Architecture: ARCHITECTURE.md in the source repository
    IronRDP enforces strict architectural invariants: core tier crates (including ironrdp-pdu, ironrdp-connector, ironrdp-session) never perform I/O, remain no_std-compatible, and avoid platform-specific code.