sfackler / rust-native-tls

Apache License 2.0
474 stars 199 forks source link

Example code/tests for mutual authentication. #32

Open creativcoder opened 7 years ago

creativcoder commented 7 years ago

I want to use native tls for client authentication by providing the 1) client cert 2) client key, and 3) a root ca-chain.cert.pem (the root+intermediate) certificate. I combined 1,2 and 3 with the command mentioned on https://docs.rs/native-tls/0.1.2/native_tls/struct.Pkcs12.html#method.from_der, and used identity method on Pkcs12 to add it. But my example code fails with certificate verify failed.

on an `Err` value: Error { repr: Custom(Custom { kind: Other, error: StringError("Ssl(ErrorStack([Error { code: 336134278, library: \"SSL routines\", function: \"ssl3_get_server_certificate\", reason: \"certificate verify failed\", file: \"s3_clnt.c\", line: 1264 }]))") }) }', /checkout/src/libcore/result.rs:860
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Do i also have to use add_root_certificate method ?

The server is an nginx server with verify client settings configured. I have tested my certs and the tls setup with other library and they are working fine.

It would be good to have code example or test case for mutual authentication, i.e., both server and client verifying each other.

sintanial commented 5 years ago

Some update ?

kpp commented 5 years ago

cc @overminder, @mcorbin, @pielco11, @hansjorg, @izolyomi, @hendrikcech

mcorbin commented 5 years ago

1 year later, I still don't know how to do it ;)

wafflespeanut commented 5 years ago

I'm using native-tls for etcd's client cert verification. Once I have X509 and PKey objects, I do something like this:

use hyper::client::{Client, HttpConnector};
use hyper_tls::HttpsConnector;
use native_tls::{Certificate, Identity, TlsConnector};
use openssl::pkcs12::Pkcs12;
use openssl::pkey::{PKey, Private};
use openssl::x509::X509;

let ca_cert: X509 = ...;
let client_cert: X509 = ...;
let client_key: PKey<Private> = ...;

let builder = Pkcs12::builder();
let pass = gen_random_password();
let pkcs12 = builder.build(&pass, "etcd-client", &client_key, &client_cert)?;
let pkcs12_der = pkcs12.to_der()?;
let identity = Identity::from_pkcs12(&pkcs12_der, &pass)?;

let ca_der = ca_cert.to_der()?;
let tls = TlsConnector::builder()
    .identity(identity)
    .add_root_certificate(Certificate::from_der(&ca_der)?)
    .build()?;

let mut http = HttpConnector::new(num_cpus::get());
http.enforce_http(false);
let connector = HttpsConnector::from((http, tls));
let client = Client::builder().build(connector);

It's probably not ideal, but I think this is how we can do it right now?