Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# Salted Challenge Response Authentication Mechanism (SCRAM)

This implementation provides a client and a server for the SCRAM-SHA-256 mechanism according to
RFC5802 and RFC7677. It doesn't support channel-binding.
RFC5802 and RFC7677. The server implementation supports channel-binding for enhanced security
over TLS connections.

[Read the documentation.](https://docs.rs/scram)

# Limitations

The mandatory SCRAM-SHA-1 authentication mechanism is currently not implemented. This is also true
for the *-PLUS variants, because channel-binding is not supported by this library. If you like to
contribute or maintain them I appreciate that.
The mandatory SCRAM-SHA-1 authentication mechanism is currently not implemented. The client does not
yet support channel-binding (only the server supports it). If you like to contribute or maintain
these features I appreciate that.

# Usage

Expand Down Expand Up @@ -124,3 +125,45 @@ send(&server_final);
// Check if the client successfully authenticated
assert_eq!(status, AuthenticationStatus::Authenticated);
```

## Channel Binding

The server implementation supports channel binding, which cryptographically binds the SCRAM
authentication to the underlying TLS connection. This prevents man-in-the-middle attacks even if
the attacker has a valid TLS certificate.

To use channel binding, obtain the channel binding data from your TLS implementation and create
the server with `ScramServer::new_with_channel_binding`:

```rust
use scram::{ScramServer, AuthenticationProvider, PasswordInfo};

struct ExampleProvider;
impl AuthenticationProvider for ExampleProvider {
fn get_password_for(&self, username: &str) -> Option<PasswordInfo> {
unimplemented!()
}
}

// Get channel binding data from your TLS implementation
let cb_type = "tls-unique".to_string();
let cb_data = get_tls_channel_binding_data(); // From your TLS library

// Create server with channel binding
let scram_server = ScramServer::new_with_channel_binding(
ExampleProvider{},
cb_type,
cb_data
);
```

Common channel binding types:
- `tls-unique`: Uses the TLS Finished message (most common)
- `tls-server-end-point`: Uses a hash of the server's TLS certificate
- `tls-exporter`: Uses the TLS exporter functionality (RFC 5705)

When channel binding is configured, the server will:
1. Accept only clients that use the same channel binding type
2. Validate that the channel binding data from the client matches the server's TLS connection
3. Reject clients that don't support channel binding (for security)
```
41 changes: 39 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//!
//! This implementation currently provides a client and a server for the SCRAM-SHA-256 mechanism
//! according to [RFC5802](https://tools.ietf.org/html/rfc5802) and
//! [RFC7677](https://tools.ietf.org/html/rfc7677). It doesn't support channel-binding.
//! [RFC7677](https://tools.ietf.org/html/rfc7677). The server implementation supports
//! channel-binding for enhanced security over TLS connections.
//!
//! # Usage
//!
Expand Down Expand Up @@ -127,6 +128,40 @@
//! // Check if the client successfully authenticated
//! assert_eq!(status, AuthenticationStatus::Authenticated);
//! ```
//!
//! ## Channel Binding
//!
//! The server can be configured to use channel binding for enhanced security. Channel binding
//! cryptographically binds the SCRAM authentication to the underlying TLS connection, preventing
//! man-in-the-middle attacks. Common channel binding types include:
//!
//! - `tls-unique`: Uses the TLS Finished message
//! - `tls-server-end-point`: Uses the server's TLS certificate
//! - `tls-exporter`: Uses the TLS exporter functionality (RFC 5705)
//!
//! To use channel binding, create the server with [`ScramServer::new_with_channel_binding`]:
//!
//! ```rust,no_run
//! use scram::{ScramServer, AuthenticationProvider, PasswordInfo};
//!
//! struct ExampleProvider;
//! impl AuthenticationProvider for ExampleProvider {
//! fn get_password_for(&self, username: &str) -> Option<PasswordInfo> {
//! unimplemented!()
//! }
//! }
//!
//! // Get channel binding data from your TLS implementation
//! let cb_type = "tls-unique".to_string();
//! let cb_data = vec![0x12, 0x34, 0x56]; // From TLS connection
//!
//! // Create server with channel binding
//! let scram_server = ScramServer::new_with_channel_binding(
//! ExampleProvider{},
//! cb_type,
//! cb_data
//! );
//! ```
extern crate base64;
extern crate rand;
extern crate ring;
Expand All @@ -142,5 +177,7 @@ pub mod server;

pub use client::ScramClient;
pub use error::{Error, Field, Kind};
pub use server::{AuthenticationProvider, AuthenticationStatus, PasswordInfo, ScramServer};
pub use server::{
AuthenticationProvider, AuthenticationStatus, ChannelBinding, PasswordInfo, ScramServer,
};
pub use utils::hash_password;
Loading