quinn-rs / quinn

Async-friendly QUIC implementation in Rust
Apache License 2.0
3.85k stars 394 forks source link

Invalid Peer Certificate: Other(CaUsedAsEndEntity) #1733

Closed sotrh closed 10 months ago

sotrh commented 10 months ago

I'm trying to adapt the client/server mock http example and I'm running into an error when I try to run the client. I've created an SSL certificate using the following script:

#!/bin/bash
set -euo pipefail

mkdir -p certs;
cd certs;

HOST="localhost";
CRT="server.crt";
KEY="server.key";
CRT_DER="$CRT.der";
KEY_DER="$KEY.der";

# Generate KEY and CRT
openssl req -x509 \
    -newkey rsa:4096 \
    -keyout "$KEY" \
    -out "$CRT" \
    -days 365 \
    -sha256 \
    -nodes \
    --subj '/CN=localhost/' \
    -addext "subjectAltName=DNS:localhost";

# Convert PEM into DER
openssl rsa -in "$KEY" -out "$KEY_DER" -outform DER;
openssl x509 -in "$CRT" -out "$CRT_DER" -outform DER;

# Generate sha256 fingerprint
cat "$CRT_DER" | openssl dgst -sha256 > fingerprint.hex;

cd -;

I'm loading the cert in the server as follows:

    let key = fs::read("certs/server.key.der")?;
    let crt = fs::read("certs/server.crt.der")?;

    let cert_chain = vec![rustls::Certificate(crt)];

    let mut server_crypto = rustls::ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_single_cert(cert_chain, rustls::PrivateKey(key))?;
    server_crypto.alpn_protocols = ALPN_QUIC_HTTP.iter().map(|&x| x.into()).collect();

    let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(server_crypto));

In the client I'm loading it like this:

    let remote = (url.host_str().unwrap(), url.port().unwrap_or(4433))
        .to_socket_addrs()?
        .next()
        .ok_or_else(|| anyhow!("Couldn't resolve url to an address"))?;

    let mut roots = rustls::RootCertStore::empty();
    let ca_path = "certs/server.crt.der";
    roots.add(&rustls::Certificate(std::fs::read(ca_path)?))?;

    let mut client_crypto = rustls::ClientConfig::builder()
        .with_safe_defaults()
        .with_root_certificates(roots)
        .with_no_client_auth();

    client_crypto.alpn_protocols = ALPN_QUIC_HTTP.iter().map(|&x| x.into()).collect();

    let client_config = quinn::ClientConfig::new(Arc::new(client_crypto));

There are no errors when the certs are loaded, nor when the server starts. The error occurs when the running the client. Here's the error: "the cryptographic handshake failed: error 46: invalid peer certificate: Other(CaUsedAsEndEntity)"

I've tried adding both server.crt and server.crt.der to /usr/local/share/ca-certificates and running sudo /usr/sbin/update-ca-certificates, and that yielded the same results.

Any help would be greatly appreciated

Ralith commented 10 months ago

This is a TLS certificate management issue and nothing specific to QUIC, much less Quinn. Is your certificate signed? Judging from the error, simply presenting a CA certificate directly isn't permitted. See the examples for how to use rcgen to generate and trust a self-signed certificate that can be used for development purposes. openssl is not the easiest to use in correct ways.

sotrh commented 10 months ago

Ok I'll try rcgen

leejw51 commented 10 months ago

with above openssl, command, quinn not working generate key.pem, cert.pem like this

san.cnf

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
CN = localhost

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost

command

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -config san.cnf -extensions v3_req
openssl x509 -in cert.pem -outform DER -out cert.der
openssl ec -in key.pem -outform DER -out key.der
Ralith commented 10 months ago

with above openssl, command, quinn not working

Yes, that's why the issue was opened. You shouldn't use a command that's known not to work.

generate key.pem, cert.pem like this

I'm not an expert on the openssl command line. As already stated above, we recommend using rcgen instead as it's less error prone. If you must use openssl to generate your certs, reach out to openssl-related support channels; we can't help you here.