V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
dvorakchen1
V2EX  ›  问与答

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

  •  
  •   dvorakchen1 · 23 天前 · 455 次点击

    我使用 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
    
    

    我有将根证书添加信任:

    信任 CA 证书

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

    2 条回复    2024-05-25 09:03:04 +08:00
    cwaken
        1
    cwaken  
       23 天前 via iPhone
    跟浏览器启动配置有关
    cwaken
        2
    cwaken  
       23 天前 via iPhone
    要忽略证书,具体看 zlmdiakit 中 is 关于 http3 提问
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4642 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 01:11 · PVG 09:11 · LAX 18:11 · JFK 21:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.