Home > OS >  converting .pem keys to .der compiles but results in errors
converting .pem keys to .der compiles but results in errors

Time:12-25

Calling my hyper based API now ported to HTTPS, with Python's requests I'm getting

SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)' on every request.

As per the docs for tokio_rustls:

The keys I used in my PKEY and CERT variables are my certbot generated .pem keys converted to .der format using those commands:

openssl x509 -outform der -in /etc/letsencrypt/live/mysite.com/cert.pem -out /etc/letsencrypt/live/mysite.com/cert.der

openssl pkcs8 -topk8 -inform PEM -outform DER -in /etc/letsencrypt/live/mysite.com/privkey.pem -out /etc/letsencrypt/live/mysite.com/privkey.der -nocrypt

And loaded up with include_bytes!() macro.

Well it compiles, polls... and just throws this error on every request Bad connection: cannot decrypt peer's message whilst the caller gets the SSLError mentioned in the beginning.

Here is the script used for the API:

fn tls_acceptor_impl(cert_der: &[u8], key_der: &[u8]) -> tokio_rustls::TlsAcceptor {
    let key = PrivateKey(cert_der.into());
    let cert = Certificate(key_der.into());
    Arc::new(
        ServerConfig::builder()
            .with_safe_defaults()
            .with_no_client_auth()
            .with_single_cert(vec![cert], key)
            .unwrap(),
    )
    .into()
}

fn tls_acceptor() -> tokio_rustls::TlsAcceptor {
    tls_acceptor_impl(PKEY, CERT)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error   Send   Sync>> {
    let addr = SocketAddr::from(...);
    let mut listener = tls_listener::builder(tls_acceptor())
        .max_handshakes(10)
        .listen(AddrIncoming::bind(&addr).unwrap());

    let (tx, mut rx) = mpsc::channel::<tokio_rustls::TlsAcceptor>(1);

    let http = Http::new();
    loop {
        tokio::select! {
            conn = listener.accept() => {
                match conn.expect("Tls listener stream should be infinite") {
                    Ok(conn) => {
                        let http = http.clone();
                        // let tx = tx.clone();
                        // let counter = counter.clone();
                        tokio::spawn(async move {
                            // let svc = service_fn(move |request| handle_request(tx.clone(), counter.clone(), request));
                            if let Err(err) = http.serve_connection(conn, service_fn(my_query_handler)).await {
                                eprintln!("Application error: {}", err);
                            }
                        });
                    },
                    Err(e) => {
                        eprintln!("Bad connection: {}", e);
                    }
                }
            },
            message = rx.recv() => {
                // Certificate is loaded on another task; we don't want to block the listener loop
                let acceptor = message.expect("Channel should not be closed");
            }
        }
    }

How can I make any sense of the errors, when the certificate keys work on Web (as they are the apache2 server's keys)? I've tried various other encodings, that are against the docs, and all fail in the same way.

CodePudding user response:

I'm not familiar enough with rust, but I know that proper configuration of a TLS server (no matter which language) requires the server certificate, the key matching the certificate and all intermediate CA needed to build the trust chain from server certificate to the root CA on the clients machine. These intermediate CA are not provided in your code. That's why the Python code fails to validate the certificate.

What you need is probably something like this:

     ServerConfig::builder()
        ....
        .with_single_cert(vec![cert, intermediate_cert], key)

Where intermediate_cert is the internal representation of the Let’s Encrypt R3 CA, which you can find here.

  • Related