An abstraction over platform-specific TLS implementations

Secure Transport on macOS (via the openssl crate) on all other platforms

rust-native-tls

Documentation

.

Specifically, this crate uses SChannel on Windows (via the schannel crate), Secure Transport on macOS (via the security-framework crate), and OpenSSL (via the openssl crate) on all other platforms.

Installation

# Cargo.toml
[dependencies]
native-tls = "0.2"

Usage

An example client looks like:

extern crate native_tls;

use native_tls::TlsConnector;
use std::io::{Read, Write};
use std::net::TcpStream;

fn main() {
    let connector = TlsConnector::new().unwrap();

    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = connector.connect("google.com", stream).unwrap();

    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut res = vec![];
    stream.read_to_end(&mut res).unwrap();
    println!("{}", String::from_utf8_lossy(&res));
}

To accept connections as a server from remote clients:

extern crate native_tls;

use native_tls::{Identity, TlsAcceptor, TlsStream};
use std::fs::File;
use std::io::{Read};
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;
use std::thread;

fn main() {
    let mut file = File::open("identity.pfx").unwrap();
    let mut identity = vec![];
    file.read_to_end(&mut identity).unwrap();
    let identity = Identity::from_pkcs12(&identity, "hunter2").unwrap();

    let acceptor = TlsAcceptor::new(identity).unwrap();
    let acceptor = Arc::new(acceptor);

    let listener = TcpListener::bind("0.0.0.0:8443").unwrap();

    fn handle_client(stream: TlsStream<TcpStream>) {
        // ...
    }

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let acceptor = acceptor.clone();
                thread::spawn(move || {
                    let stream = acceptor.accept(stream).unwrap();
                    handle_client(stream);
                });
            }
            Err(e) => { /* connection failed */ }
        }
    }
}

License

rust-native-tls is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses.

See LICENSE-APACHE, and LICENSE-MIT for details.

Issues

Collection of the latest Issues

1Dragoon

1Dragoon

3

Given RFC 3546 stipulates that the trailing dot should never be present in a domain name: https://datatracker.ietf.org/doc/html/rfc3546#section-3.1

Could we either automatically detect and remove the trailing dot from domain names passed to native-tls, or have the error message produced show what the expected name(s) was vs what was found?

FWIW here's where I ran into this issue:

https://github.com/inejge/ldap3/issues/84

May or may not be in scope for this project, just wanted to at least bring up the issue.

NinoScript

NinoScript

2

This change added for byte in bytes { which fails with in Rust < 1.53.

Error message

Borrowing the array (for byte in &bytes {) would allow this crate to keep working in older Rust versions. IMO, it's ok if you decide not to work with older Rust versions, but I did want to let you know.

Alvenix

Alvenix

0

RFC3546 disallow using for IP address for server name indication. However it seems that native-tls violate this.

Literal IPv4 and IPv6 addresses are not permitted in "HostName".

I verified this by running the following openssl command: $ openssl s_server -cert private/rsa_sha256_cert.pem -key private/rsa_sha256_key.pem -port 8000 -tlsextdebug

and using this example code:

Here is the relevant server output which indicate that native-tls send the IP as part of the server name indication:

I have encountered this bug while using reqwest and have reported here. I am not sure if this a bug in native-tls or incorrect usage from reqwest.

I have tested this on Ubuntu 20.04 only.

MabezDev

MabezDev

16

Without rust-native-tls support, a lot of std crates become partially, or completely unusable. For our std target, riscv32imc-esp-espidf, we have an mbedtls implementation available.

rust-mbedtls is a stable and well maintained crate with bindings to mbedtls. Would you be open to PR's adding support in rust-native-tls?

0xADD1E

0xADD1E

1

When attempting to do peer authentication with a macOS client, an error gets raised corresponding with errSSLPeerAuthCompleted. This shouldn't actually be raised, should it? (For reference, errSSLPeerAuthCompleted is explicitly described as a non-fatal result, and seems to occur as a normal part of peer authentication)

vasishath

vasishath

0

Hello, I am using native_tls for an app and everything is working fine except for one small issue. I have registered multiple TcpStreams in mio poll and want to retrieve the stream back in case the handshake fails so that I can de-register it before the underlying socket closes. I have currently implemented Drop trait for the stream but since it needs a mutable reference to the poll registry, I have to resort to use raw pointer and unsafe code. Is there any better way to do this ?

llacroix

llacroix

4

How does one generate handshake for multiple DNS? I'm trying to make add tls support for a proxy server. The problem I have now is that even though I can get a TlsAcceptor to work based on the examples. I'm not so sure to understand how to get it to validate a provide different certificates for different HostName. Do I have to create an Acceptor for each domain I try to validate and then check against all of the identities until I found one that Accept the connection? Or is the Acceptor handling that itself using the PKCS12 file?

gxtaillon

gxtaillon

9

Hello,

I'm trying to use rust-native-tls to setup a bare tls connection that would require client to provide a certificate, however I have not found a way of doing this with TlsAcceptor. There doesn't seem to be a way to set the verification mode and depth.

Using openssl s_server -accept *:10000 -cert server.pem -key server.pem -verify 10 -CAfile root-ca.crt, I can see that when providing a cert on the TlsConnectorBuilder, the client sends the certificate.

The peer_certificate() on the call always return Ok(None), and the server never requests the certificate.

Looking at the tests, requesting the client's certificate doesn't seem to be supported. https://github.com/sfackler/rust-native-tls/blob/75e43daaf9174916611178419805542a9883bae4/src/test.rs#L140

Would you welcome a PR?

amrx101

amrx101

0

First of all, awesome work on the crate and many thanks for that.

Is it possible to use the crate with a pkcs11 engine exposed by (HSM) or someway to provide hooks for certs that are actually contained inside a HSM.

Thanks.

aloucks

aloucks

1

When I inspect the certificate in any browser, I notice that the full signing chain/hierarchy is missing. Only the server certificate is present. Firefox has an option to download the chain and the resulting file also only contains the server cert.

I'm creating the identity with:

$ openssl pkcs12 -export -out server.p12 -inkey server.key -in server.crt -chain -CAfile ca.crt

And when I inspect it I can see both the server and ca certificates.

$ openssl pkcs12 -info -in server.p12
driftluo

driftluo

5
TimonPost

TimonPost

2

Does this library support DTLS or will it be supported in the feature?

chefsalim

chefsalim

4

The Certificate::from_pem function for OSX restricts the number of certificates that can be in the passed in PEM file. Therefore higher level libraries (like reqwest) will fail with a "One or more parameters passed to the function are not valid." message when a PEM file with a cert chain is used.

  1. It would be great to know more details on the restrictions and recommendation for work around
  2. It would be great to have the limitations removed and the ability to support cert chains added explicitly
mehcode

mehcode

6

I need async. tls for a project I'm working on and was investigating the async support here. I found tokio-tls but I'd like to try and use rustasync/runtime and std futures (as they are soon to be stable).

The binding to tokio for native-tls ( https://github.com/tokio-rs/tokio/blob/master/tokio-tls/src/lib.rs ) doesn't seem that involved and I was wondering if this could be accepted in-tree under a runtime feature ( that uses the runtime crate to be agnostic of the event loop ).

I'd be happy to contribute this if this is something that'd be accepted.

vaffeine

vaffeine

2

Hi,

I need to access server's public key to use it in the NTLM implementation that I am working on.

To do so, I use Certificate::to_der() method and then parse the public key using X509 from OpenSSL. But this, obviously, is not really convenient, because the key is already parsed by native_tls and I need to parse it again with platform dependent code.

I think it would be great to have methods to access certificate fields in a platform-independent way. X509 from OpenSSL provides a lot of methods for it. It is also possible to retrieve some of them with SecCertificateExt on macOS and the PR, that allows to retrieve public certificate, is almost merged into schannel-rs .

I could work on it and create a PR if you don't mind.

izolyomi

izolyomi

7

I'm trying to use native-tls in a non-HTTP scenario with self-signed certificates building a mutually authenticated peer to peer connection. All I want is essentially a Diffie-Hellman key exchange and an encrypted channel. During the handshake I'd like to avoid the usual PKI trust chain and let peers decide programatically if they trust the certificate of the other party.

To achieve this, the usual way is to provide a hook for a callback function where certificate of the peer can be validated. In Java you can set a custom TrustManager while initializing your SslContext. Also, crate rustls nicely supports with ServerCertVerifier::verify_server_cert(). I'd like to have the same programatic control over certificate validation using native-tls + tokio-tls without blocking, but unfortunately this library doesn't seem to support this so far.

Would it be hard to add such a callback feature also to native-tls?

Versions

Find the latest versions by id

v0.2.10 - Mar 28, 2022

v0.2.9 - Mar 27, 2022

v0.2.8 - Aug 11, 2021

v0.2.7 - Dec 29, 2020

v0.2.6 - Nov 10, 2020

v0.2.5 - Nov 06, 2020

v0.2.4 - Mar 06, 2020

v0.2.3 - Apr 27, 2019

v0.2.2 - Oct 22, 2018

v0.2.1 - Aug 05, 2018

v0.2.0 - Jun 26, 2018

v0.1.5 - Jan 11, 2018

  • security-framework is now used on iOS instead of openssl
  • Added the ability to load certificates from PEM (on everything except iOS)

v0.1.2 - Apr 02, 2017

  • Avoid keychain unlock prompts on OSX.
  • Support custom trust roots
  • Allow connection without hostname verification.

v0.1.1 - Jan 12, 2017

  • Add TlsStream::shutdown
  • Support protocol selection
  • Add more extension traits allowing access to platform-specific types.

v0.1.0 - Nov 09, 2016

Initial release

Information - Updated Jun 22, 2022

Stars: 341
Forks: 133
Issues: 34

Kanidm is an identity management platform written in rust

We also publish limited code of conduct

Kanidm is an identity management platform written in rust

Actix Casbin Middleware

Casbin only takes charge of permission control, so you need to implement an Authentication Middleware to identify user

Actix Casbin Middleware

The fastest way to identify anything

Identify any mysterious text or analyze strings from a file, just ask lemmeknow

The fastest way to identify anything
Facebook Instagram Twitter GitHub Dribbble
Privacy