请教关于 QUIC 使用自签名证书的问题

32 天前
 dvorakchen1

我使用 Rust 的 quinn 库写一个简单的 QUIC 连接,本地开发使用自签名证书一直报 Error:

Error: ConnectionClosed(ConnectionClose { error_code: Code::crypto(30), frame_type: None, reason: b"invalid peer certificate: UnknownIssuer" })
error: process didn't exit successfully: `C:\Projects\friends\target\debug\server.exe` (exit code: 1)

Rust version: 1.78 stable OS: Windows 11 OpenSSL: 3.0.11 19

折腾了很久不知道为什么。下面是代码和自签名的细节:

// Server code

use std::{fs, sync::Arc};
use quinn::crypto::rustls::QuicServerConfig;
use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};

pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv::dotenv()?;
    env_logger::init();

    rustls::crypto::ring::default_provider()
        .install_default()
        .expect("Failed to install rustls crypto provider");
    let cert = fs::read("C:/Projects/certificates/certificate.der")?;
    let key = fs::read("C:/Projects/certificates/private_key.der")?;

    let cert = CertificateDer::from(cert);
    let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::try_from(key)?);

    let mut server_config = rustls::ServerConfig::builder()
        .with_no_client_auth()
        .with_single_cert(vec![cert], key)?;
    server_config.alpn_protocols = ALPN_QUIC_HTTP.iter().map(|&x| x.into()).collect();
    let server_config =
        quinn::ServerConfig::with_crypto(Arc::new(QuicServerConfig::try_from(server_config)?));

    let endpoint = quinn::Endpoint::server(server_config, "127.0.0.1:8898".parse()?)?;

    let mut b = [0u8; 1024];

    while let Some(conn) = endpoint.accept().await {
        let (mut send, mut recv) = conn.await?.open_bi().await?;

        while let Ok(_) = recv.read(&mut b).await {
            send.write_all(&mut b).await?;
        }
    }

    Ok(())
}


// Client

use std::fs;
use std::sync::Arc;
use quinn::crypto::rustls::QuicClientConfig;
use rustls::pki_types::CertificateDer;

pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv::dotenv()?;
    env_logger::init();

    rustls::crypto::ring::default_provider()
        .install_default()
        .expect("Failed to install rustls crypto provider");

    let mut roots = rustls::RootCertStore::empty();
    roots.add(CertificateDer::from(fs::read(
        "C:/Projects/certificates/certificate.der",
    )?))?;
    let mut client_crypto = rustls::ClientConfig::builder()
        .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(QuicClientConfig::try_from(client_crypto)?));
    let mut endpoint = quinn::Endpoint::client("0.0.0.0:0".parse()?)?;
    endpoint.set_default_client_config(client_config);

    let conn = endpoint
        .connect("127.0.0.1:8898".parse()?, "localhost")?
        .await?;

    Ok(())
}

代码非常简单,重点在使用证书的那几行:

let cert = fs::read("C:/Projects/certificates/certificate.der")?;
let key = fs::read("C:/Projects/certificates/private_key.der")?;
    
roots.add(CertificateDer::from(fs::read(
        "C:/Projects/certificates/certificate.der",
    )?))?;

使用 openssl 生成证书的步骤按照这篇博客来:How to Create Self-Signed Certificates using OpenSSL

openssl req -x509             -sha256 -days 356             -nodes             -newkey rsa:2048             -subj "/CN=Localhost/C=US/L=San Fransisco"             -keyout rootCA.key -out rootCA.crt

openssl genrsa -out server_key.pem 2048

添加下面内容到 csr.conf:

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = US
ST = California
L = San Fransisco
O = MLopsHub
OU = MlopsHub Dev
CN = Localhost

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = localhost
IP.1 = 127.0.0.1

接着

openssl req -new -key server_key.pem -out server.csr -config csr.conf

添加下面内容到 cert.conf:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost

接着

openssl x509 -req     -in server.csr     -CA rootCA.crt -CAkey rootCA.key     -CAcreateserial -out server_crt.pem     -days 365     -sha256 -extfile cert.conf

将 server_key.pem 转为 private_key.der, 将 server_cert.pem 转为 certificate.der

openssl pkcs8 -topk8 -inform PEM -outform DER -in server_key.pem -out private_key.der -nocrypt

openssl x509 -outform der -in server_cert.pem -out certificate.der

我有将根证书添加信任:

找了很多方法一直不行,求教大佬有没有什么注意

525 次点击
所在节点    问与答
2 条回复
cwaken
32 天前
跟浏览器启动配置有关
cwaken
32 天前
要忽略证书,具体看 zlmdiakit 中 is 关于 http3 提问

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1043715

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX