Rust证书管理库deno_native_certs的使用:为Deno提供原生TLS/SSL证书支持

Rust证书管理库deno_native_certs的使用:为Deno提供原生TLS/SSL证书支持

该crate的目的是改善Deno在macOS上的启动时间。

在macOS上,证书是从系统钥匙串加载的。用户、管理员和系统信任设置按照Apple的文档合并在一起。Security框架是通过dlopen动态加载的,以避免初始的dyld开销。

在Linux和Windows上,使用了rustls-native-certs crate。

安装

安装为二进制

cargo install deno_native_certs

运行上述命令将全局安装deno_native_certs_test二进制文件。

安装为库

在项目目录中运行以下Cargo命令:

cargo add deno_native_certs

或者将以下行添加到Cargo.toml:

deno_native_certs = "0.3.1"

使用示例

use deno_native_certs::load_native_certs;
use rustls::{Certificate, RootCertStore};

fn main() {
    // 创建一个根证书存储
    let mut root_store = RootCertStore::empty();
    
    // 加载系统原生证书
    let certs = load_native_certs().expect("Failed to load native certificates");
    
    // 将证书添加到根证书存储
    for cert in certs {
        root_store.add(&Certificate(cert.0))
            .expect("Failed to add certificate to root store");
    }
    
    // 现在root_store包含了系统的根证书,可用于TLS连接
    println!("Loaded {} system certificates", root_store.len());
}

完整示例代码

下面是一个更完整的示例,演示如何使用deno_native_certs创建一个使用系统证书的TLS客户端:

use deno_native_certs::load_native_certs;
use rustls::{ClientConfig, RootCertStore};
use std::io::{Read, Write};
use std::net::TcpStream;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建根证书存储
    let mut root_store = RootCertStore::empty();
    
    // 加载系统原生证书
    let certs = load_native_certs()?;
    
    // 将证书添加到根证书存储
    for cert in certs {
        root_store.add(&rustls::Certificate(cert.0))?;
    }
    
    // 创建TLS客户端配置
    let config = ClientConfig::builder()
        .with_safe_defaults()
        .with_root_certificates(root_store)
        .with_no_client_auth();
    
    // 创建TLS连接
    let server_name = "example.com".try_into()?;
    let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name)?;
    
    // 建立TCP连接
    let mut sock = TcpStream::connect("example.com:443")?;
    
    // 创建TLS流
    let mut tls = rustls::Stream::new(&mut conn, &mut sock);
    
    // 发送HTTP请求
    tls.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n")?;
    
    // 读取响应
    let mut plaintext = Vec::new();
    tls.read_to_end(&mut plaintext)?;
    
    // 打印响应
    println!("{}", String::from_utf8_lossy(&plaintext));
    
    Ok(())
}

特性说明

  1. 跨平台支持:

    • macOS: 使用系统钥匙串加载证书
    • Linux/Windows: 使用rustls-native-certs
  2. 性能优化:

    • 在macOS上通过dlopen动态加载Security框架,减少启动时间
  3. 简单易用的API:

    • 主要提供load_native_certs()函数
    • 返回Result<Vec<Certificate>, Error>

常见问题

  1. 证书加载失败:

    • 检查系统证书存储是否正常
    • 检查是否有足够的权限访问证书存储
  2. 证书验证失败:

    • 确保root_store正确加载了系统证书
    • 检查服务器证书是否由受信任的CA签发

所有者

  • Ryan Dahl
  • Divy

1 回复

以下是基于提供内容整理的完整示例demo,结合了基本使用、Deno集成和reqwest的高级用法:

// 完整示例:使用deno_native_certs进行HTTPS请求
use deno_core::plugin_api::{Interface, Op, ZeroCopyBuf};
use deno_native_certs::load_native_certs;
use reqwest::ClientBuilder;
use rustls::RootCertStore;
use std::sync::Arc;
use tokio::net::TcpStream;
use tokio_rustls::TlsConnector;

// 1. 基本证书加载示例
fn load_system_certificates() {
    let mut root_store = RootCertStore::empty();
    load_native_certs(&mut root_store).expect("加载系统证书失败");
    
    println!("成功加载 {} 个系统根证书", root_store.roots.len());
}

// 2. Deno插件集成
#[no_mangle]
pub fn deno_plugin_init(interface: &mut dyn Interface) {
    interface.register_op("loadNativeCerts", op_load_native_certs);
}

fn op_load_native_certs(
    _interface: &mut dyn Interface,
    _zero_copy: &mut [ZeroCopyBuf],
) -> Op {
    let mut root_store = RootCertStore::empty();
    match load_native_certs(&mut root_store) {
        Ok(_) => Op::Sync(Box::new(root_store.roots.len())),
        Err(e) => Op::Sync(Box::new(format!("错误: {}", e))),
    }
}

// 3. 使用reqwest进行安全请求
async fn secure_http_request(url: &str) -> Result<(), Box<dyn std::error::Error>> {
    let mut root_store = RootCertStore::empty();
    load_native_certs(&mut root_store)?;
    
    let client = ClientBuilder::new()
        .use_preconfigured_tls(root_store)
        .build()?;
    
    let response = client.get(url).send().await?;
    println!("请求状态: {}", response.status());
    println!("响应头: {:?}", response.headers());
    
    Ok(())
}

// 4. 高级用法:使用tokio-rustls建立安全连接
async fn tls_connect(host: &str, port: u16) -> Result<(), Box<dyn std::error::Error>> {
    let mut root_store = RootCertStore::empty();
    load_native_certs(&mut root_store)?;
    
    let config = rustls::ClientConfig::builder()
        .with_safe_defaults()
        .with_root_certificates(root_store)
        .with_no_client_auth();
    
    let connector = TlsConnector::from(Arc::new(config));
    let stream = TcpStream::connect((host, port)).await?;
    let domain = rustls::ServerName::try_from(host)?;
    
    let mut tls_stream = connector.connect(domain, stream).await?;
    // 这里可以添加TLS流的具体读写操作
    println!("成功建立TLS连接到 {}:{}", host, port);
    
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 演示基本功能
    load_system_certificates();
    
    // 执行安全HTTP请求
    secure_http_request("https://example.com").await?;
    
    // 建立TLS连接
    tls_connect("example.com", 443).await?;
    
    Ok(())
}

这个完整示例展示了:

  1. 基本证书加载功能
  2. 如何集成到Deno运行时作为插件
  3. 结合reqwest进行安全HTTPS请求
  4. 使用tokio-rustls建立底层TLS连接

使用前请确保在Cargo.toml中添加以下依赖:

[dependencies]
deno_native_certs = "0.6"
deno_core = "0.142"  # 仅当需要Deno集成时
reqwest = { version = "0.11", features = ["rustls-tls"] }
tokio = { version = "1.0", features = ["full"] }
tokio-rustls = "0.23"
rustls = "0.20"
回到顶部