Skip to main content

Connection

Struct Connection 

Source
pub struct Connection { /* private fields */ }
Expand description

A unified TLS or DTLS connection (client or server, any supported version).

Construct via Connection::client or Connection::server, passing a shared super::Config. The internal engine is picked from config.max_version.

Implementations§

Source§

impl Connection

Source

pub fn client(config: &Config) -> Result<Self, Error>

Build a client connection. Picks the engine from config.max_version.

Source

pub fn server(config: &Config) -> Result<Self, Error>

Build a server connection. Picks the engine from config.max_version. Requires config.identity.is_some().

Source

pub fn handshake(&mut self) -> Result<HandshakeStatus, Error>

Drive the handshake forward. Returns the next HandshakeStatus.

Source

pub fn drive(&mut self) -> Result<Step, Error>

Drive the handshake forward, transparently brokering the identity signature through the HandshakeSigner installed via ConfigBuilder::private_key.

This is the key-agnostic alternative to handshake: the same loop drives an in-process key, a local TPM, or a network HSM, because the signing device is folded into the returned Step. The caller services peer I/O on WantRead/WantWrite exactly as with handshake, and on WantSigner waits on the (opaque) device readiness before calling drive again — it never touches the message, the signature, or the device transport.

use std::io::{Read, Write};
let mut buf = [0u8; 16 * 1024];
loop {
    match conn.drive().map_err(std::io::Error::other)? {
        Step::WantWrite => sock.write_all(&conn.pop().map_err(std::io::Error::other)?)?,
        Step::WantRead => {
            let n = sock.read(&mut buf)?;
            conn.feed(&buf[..n]).map_err(std::io::Error::other)?;
        }
        // Sync: block on the device fd. Async: register
        // `r.as_raw_fd()` with your reactor and `.await` instead.
        Step::WantSigner(Some(r)) => r.wait()?,
        Step::WantSigner(None) => {} // no fd: just loop and re-drive
        Step::Complete => break,
        _ => {} // `Step` is #[non_exhaustive]
    }
}
Source

pub fn signature_request(&self) -> Option<SignatureRequest>

If the handshake is suspended awaiting an external CertificateVerify signature (an SigningKey::External identity), returns the SignatureRequest describing what to sign; otherwise None.

Drive loop: after feed and draining pop, check this before blocking on a peer read. When it is Some, sign request.message under request.scheme (on a TPM/HSM, synchronously or .awaited) and call provide_signature; the engine then emits the rest of its flight.

Source

pub fn provide_signature(&mut self, signature: Vec<u8>) -> Result<(), Error>

Resumes a handshake suspended by signature_request, supplying the externally-produced CertificateVerify signature.

§Errors

Returns Error::InappropriateState if the handshake is not currently awaiting an external signature.

Source

pub fn feed(&mut self, wire_in: &[u8]) -> Result<usize, Error>

Wire bytes from the peer into the engine. Returns the number of bytes consumed.

Source

pub fn pop(&mut self) -> Result<Vec<u8>, Error>

Wire bytes the engine wants to send to the peer. For TLS, this is a contiguous stream slice; for DTLS, this is one datagram per call.

Source

pub fn send(&mut self, app: &[u8]) -> Result<(), Error>

App bytes into the engine (post-handshake).

Source

pub fn recv(&mut self) -> Result<Vec<u8>, Error>

App bytes out (post-handshake).

Source

pub fn take_early_data(&mut self) -> Result<Vec<u8>, Error>

Accepted 0-RTT early-data plaintext out (server side).

Early data is replayable by an active attacker (RFC 8446 §8), so it is quarantined away from recvrecv only ever returns data protected by the completed handshake. Drain the replayable bytes explicitly here and only act on them when doing so is idempotent. Returns an empty vector on client engines, on engines without 0-RTT support, when the server did not accept early data, or once the buffer has been drained.

Source

pub fn tls_exporter( &self, label: &[u8], context: &[u8], out: &mut [u8], ) -> Result<(), Error>

Exports keying material bound to this connection (RFC 8446 §7.5 for TLS 1.3, RFC 5705 for TLS 1.2 / DTLS). label and context namespace the output; out is filled with out.len() bytes derived from the connection’s master/exporter secret. Available once the handshake has completed on every TLS and DTLS engine; an error is returned if called too early.

Source

pub fn write_early_data(&mut self, data: &[u8]) -> Result<(), Error>

Client 0-RTT: queue application data to be sent under the early-traffic key before ServerHello arrives. Valid only on a TLS 1.3 client whose super::ConfigBuilder::resumption_session enabled 0-RTT (the stored session carried a non-zero max_early_data_size); any other engine returns Error::InappropriateState. See the 0-RTT replay caveat in the crate docs — early data is replayable.

Source

pub fn take_session(&mut self) -> Option<ResumptionSession>

Client only: move out a ResumptionSession derived from a NewSessionTicket the server sent, for resumption on a later connection (feed it back via super::ConfigBuilder::resumption_session). Returns None on a server engine, or when the server issued no resumable ticket.

Source

pub fn close(&mut self) -> Result<(), Error>

Close the connection, emitting a close_notify alert if the engine supports it.

Source

pub fn is_handshake_complete(&self) -> bool

True once the handshake has completed.

Source

pub fn received_close_notify(&self) -> bool

True once the peer’s close_notify alert has been processed.

Distinguishes a graceful TLS shutdown from an abrupt transport close: after transport EOF, false here means the peer (or an active attacker injecting a TCP FIN/RST) cut the stream without the RFC 8446 §6.1 / RFC 5246 §7.2.1 closure alert. Callers using EOF-delimited application framing should treat that as a truncation attack and reject the data.

Always false for DTLS engines — purecrypto’s DTLS does not exchange close_notify (datagram transports have no stream EOF to authenticate; an application protocol signals its own end).

Source

pub fn negotiated_version(&self) -> Option<ProtocolVersion>

The negotiated wire version, if the handshake has progressed enough to determine it.

Source

pub fn negotiated_cipher_suite(&self) -> Option<u16>

IANA cipher-suite identifier of the negotiated suite. None until the handshake has advanced far enough to fix the suite (ServerHello processed on the client, ClientHello processed on the server).

Source

pub fn negotiated_cipher_suite_name(&self) -> Option<&'static str>

The IANA name of the negotiated cipher suite, or None until the suite is fixed. Returns the well-known strings for the suites purecrypto negotiates (TLS 1.3 trio + the TLS 1.2 ECDHE-AEAD set); unknown codes resolve to "UNKNOWN".

Source

pub fn alpn_selected(&self) -> Option<&[u8]>

The negotiated ALPN protocol, if any.

Source

pub fn peer_server_name(&self) -> Option<&str>

Server-side: the SNI host_name the client offered in the ClientHello server_name extension (RFC 6066 §3). None for client engines, for DTLS engines (no SNI plumbing yet), or when the peer omitted the extension. Available once the ClientHello has been processed.

Source

pub fn peer_certificates(&self) -> &[Vec<u8>]

The peer’s certificate chain (leaf first, DER).

Source

pub fn next_timeout(&self) -> Option<Duration>

DTLS: next retransmit timeout. None on TLS variants.

Source

pub fn on_timeout(&mut self, now: Duration)

DTLS: notify the engine that the retransmit deadline has elapsed. No-op on TLS variants.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.