Skip to content
DevolutionsPublic

About

A Rust implementation of the Security Support Provider Interface (SSPI) API

Topics

Resources

Security policy

Stars

84 stars

Watchers

12 watching

Forks

Latest commit

 

History

665 Commits

Folders and files

Repository files navigation

sspi-rs

sspi-rs is a Rust implementation of Security Support Provider Interface (SSPI). It ships with platform-independent implementations of Security Support Providers (SSP), and is able to utilize native Microsoft libraries when ran under Windows.

The purpose of sspi-rs is to clean the original interface from cluttering and provide users with Rust-friendly SSPs for execution under *nix or any other platform that is able to compile Rust.

Overview

The sspi-rs works in accordance with the MSDN documentation. At the moment, NT LAN Manager (NTLM) is implemented and available for platform independent execution. It is also possible to create your own SSPs by implementing the SspiImpl trait.

Ease of use

Some SSPI functions tend to be cumbersome, that's why sspi-rs allows to use SSPI in a convenient way by utilizing builders.

Example

The usage of the SSPs is as simple as creating an instance of the security provider and calling its functions.

Here is an example of acquiring a credentials handle and a timestamp of their validity:

use sspi::{CredentialUse, Ntlm, Sspi, Username, builders::EmptyInitializeSecurityContext, SecurityBuffer, ClientRequestFlags, DataRepresentation, BufferType, SspiImpl};

fn main() {
    let account_name = "example_user";
    let computer_name = "example_computer";
    let mut ntlm = Ntlm::new();
    let username = Username::new(&account_name, Some(&computer_name)).unwrap();
    let identity = sspi::AuthIdentity {
        username,
        password: String::from("example_password").into(),
    };

    let mut acq_cred_result = ntlm
        .acquire_credentials_handle()
        .with_credential_use(CredentialUse::Outbound)
        .with_auth_data(&identity)
        .execute()
        .unwrap();

    let mut output_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
    // first time calling initialize_security_context, the input buffer should be empty
    let mut input_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];

    // create a builder for the first call to initialize_security_context
    // the target should start with the protocol name, e.g. "HTTP/example.com" or "LDAP/example.com"
    let mut builder = EmptyInitializeSecurityContext::<<Ntlm as SspiImpl>::CredentialsHandle>::new()
        .with_credentials_handle(&mut acq_cred_result.credentials_handle)
        .with_context_requirements(ClientRequestFlags::CONFIDENTIALITY | ClientRequestFlags::ALLOCATE_MEMORY)
        .with_target_data_representation(DataRepresentation::Native)
        .with_target_name("LDAP/example.com")
        .with_input(&mut input_buffer)
        .with_output(&mut output_buffer);

    // call initialize_security_context
    // Note: the initialize_security_context_impl returns a generator, for NTLM, 
    // this generator will never yield as NTLM requires no network communication to a third party
    // but negotiate and kerberos do require network communication, so the generator is used to
    // allow the caller to provide the network information through the generator.resume() method
    // take a look at the examples/kerberos.rs for more information
    let _result = ntlm
        .initialize_security_context_impl(&mut builder)
        .resolve_to_result()
        .unwrap();
    // ... exchange your token in output buffer with the server and repeat the process until either server is satisfied or an error is thrown
}

Example of acquiring an SSP provided by Windows:

let mut negotiate = SecurityPackage::from_package_type(
    SecurityPackageType::Other(String::from("Negotiate"))
);

CredSSP delegation modes

Both CredSspClient::new and, with the tsssp feature, SspiCredSsp::new_client_with_mode accept an explicit CredSspMode. SspiCredSsp::new_client preserves ordinary delegation for compatibility.

Mode Authentication Final credentials
WithCredentials Ordinary configured negotiation Supplied password or smart-card credentials
CredentialLess (Restricted Admin) Ordinary configured negotiation, including Kerberos or NTLM Empty type-1 TSPasswordCreds, regardless of the authentication credential source
RemoteGuard Fresh Kerberos-enabled Negotiate; no NTLM or password-delegation fallback Type-6 TSRemoteGuardCreds; continuing RDPEAR session available after completion

Restricted Admin is non-delegating, not anonymous: the client still authenticates. It does not delegate a password or smart-card PIN and does not create an RDPEAR session. Restricted Admin and Remote Credential Guard reject conflicting DELEGATE requirements. RDP connectors must separately request the selected mode and require the matching server capability; selecting a CredSSP mode does not negotiate RDP flags. These are Rust client APIs, not support for native extended credential structures or server-side type-6 credential import.

Remote Credential Guard keeps reusable TGT keys and the CredSSP protection key client-owned. Ordinary service-ticket session keys are intentionally returned inside protected RDPEAR replies, and retained only for session-authorized operations. TGS authenticators with peer-supplied subkeys fail explicitly because such keys would let the peer decrypt TGT replies outside the client. There is no generic raw-key export API. Remote Credential Guard requires KdcResolution::KdcUrl for direct KDC or KDC-proxy communication; IAKerb proxy negotiation is not supported in this mode.

Bounded Windows integration has verified initial logon and optional redirected NTLMv2 authentication on a fresh target logon; initial authentication still requires Kerberos. Successful outbound Kerberos authentication remains unverified. The service-key and authenticator-skew corrections have local synthetic validation only. Reconnecting to an existing target logon retained an old credential binding in the tested setup; a fresh target logon is required and no credential state is transferred between connections. See sspi::rcg for the specific results and limitations.

Projects using sspi-rs

(Feel free to open a PR if you know about other projects!)

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

A Rust implementation of the Security Support Provider Interface (SSPI) API

Topics

Resources

Security policy

Stars

84 stars

Watchers

12 watching

Forks

Releases

Packages

Used by

Contributors

Languages