2个稳定版本
2.0.1 | 2023年8月24日 |
---|---|
1.1.0 | 2023年8月19日 |
1.0.3 |
|
470 在 HTTP客户端
每月 下载 23 次
用于 x509-path-finder
45KB
898 行
X509 Client
X509 Client 是 Rust 的异步 X509 证书传输和解序列化工具。
概述
支持的传输方式
- HTTP/S
- 文件
支持的编码格式
- CER - 单个 DER 编码的证书
- PEM - 一组 PEM 编码的证书
- PKCS7 - DER 编码的 PKCS7 证书包
用法
默认提供基于 RustCrypto 的 DefaultX509Iterator
实现方式。
[dependencies]
x509_client = { version = "1" }
启用 openssl
功能,以访问基于 OpenSSL 的 OpenSSLX509Iterator
解序列化器。
[dependencies]
x509_client = { version = "1", features = ["openssl"] }
X509 客户端与数据模型无关。在构建客户端时,使用 turbofish 表达式选择解序列化器实现。
use x509_client::{X509Client, X509ClientConfiguration};
use x509_client::provided::default::DefaultX509Iterator;
#[tokio::test]
async fn test() {
// default X509 Client with the default DefaultX509Iterator
let client = X509Client::<DefaultX509Iterator>::default();
assert!(client.get(&url::Url::parse("https://127.0.0.1")?).await.is_ok());
// Configured X509 Client with the default DefaultX509Iterator
let client = X509Client::<DefaultX509Iterator>::new(X509ClientConfiguration::default());
assert!(client.get_all(&url::Url::parse("https://127.0.0.1")?)?.into_inter().len() >= 0);
}
示例
使用默认的 DefaultX509Iterator
实现方式传输和解析单个证书和多个证书。
use cms::cert::x509::Certificate;
use x509_client::{X509Client, X509ClientConfiguration, X509ClientResult};
use x509_client::provided::default::DefaultX509Iterator;
use x509_client::reqwest::ClientBuilder;
async fn get_first_certificate(url: &url::Url) -> X509ClientResult<Certificate> {
// default X509 Client with the default DefaultX509Iterator
let client = X509Client::<DefaultX509Iterator>::default();
Ok(client.get(&url).await?)
}
async fn get_all_certificates(url: &url::Url) -> X509ClientResult<Vec<Certificate>> {
// configure reqwest
let config = X509ClientConfiguration {
strict: true,
files: false,
limit: None,
http_client: Some(
ClientBuilder::new()
.redirect(reqwest::redirect::Policy::limited(2))
.build()?,
),
};
// Configured X509 Client with the default DefaultX509Iterator
let client = X509Client::<DefaultX509Iterator>::new(config);
// HTTP GET and parse all certificates, returning all
Ok(client.get_all(&url).await?.into_iter().collect())
}
实例化和配置
可以使用 crate::X509Client::default 特性实现来实例化默认的 X509 客户端。
let client = X509Client::<DefaultX509Iterator>::default();
可以通过传递 X509ClientConfiguration
到客户端构造函数 crate::X509Client::new 来配置 X509 客户端。
let client = X509Client::<DefaultX509Iterator>::new(config);
X509ClientConfiguration
结构体定义为
// Default configuration
X509ClientConfiguration {
strict: false,
files: false,
limit: None,
http_client: None
};
pub struct X509ClientConfiguration {
/// If true, only attempt parse once.
/// Use either filename extension or http header to determine type.
/// If false, attempt to parse from all known formats before returning error.
pub strict: bool,
/// If true, allow `File` transport scheme.
/// If false, transport attempts will fail for `File` scheme.
pub files: bool,
/// Limits max transfer size in bytes. If None, apply no limit.
pub limit: Option<usize>,
/// Optional Reqwest client.
/// If None, a default Reqwest client will be instantiated.
pub http_client: Option<x509_client::reqwest::Client>,
}
传输和解序列化
X509Client::get
方法传输并解析第一个证书,在空时返回错误。
X509Client::get_all
方法传输并解析所有证书。
解序列化
在解析之前,客户端将尝试确定远程证书的编码。
如果启用严格配置,客户端将只尝试解析一次。如果无法确定编码类型,客户端将立即返回错误。
如果禁用严格配置(默认),客户端将在返回错误之前尝试解析所有已知格式(从最佳猜测开始)。
某些反序列化实现可能返回一个空迭代器。PKIX(PEM)文本编码规范RFC 7468指出
解析器必须优雅地处理不符合规范的数据。
并且
文件可以包含多个文本编码实例。例如,当文件包含多个证书时,就会使用这种方法。
这意味着“空”PEM文件是有效的。因此,当禁用严格配置时,X509客户端始终尝试最后解析PEM。
对于HTTP传输,证书类型由Content-Type
http头确定
- application/pkix-cert : CER
- application/pem-certificate-chain : PEM
- application/pkcs7-mime : PKCS7
对于File
方案,证书类型由文件扩展名(.ext)确定
- .cer : CER
- .pem : PEM
- .p7c : PKCS7
API
X509客户端不关心数据模型 - 使用X509Iterator
特性行定义反序列化接口。
use std::fmt::{Debug, Display};
/// X509 Deserializer API
pub trait X509Iterator: IntoIterator
where
Self: Sized,
{
/// Error type
type X509IteratorError: X509IteratorError;
/// Attempt to deserialize, assume input is a single DER-encoded certificate
fn from_cer<T: AsRef<[u8]>>(src: T) -> Result<Self, Self::X509IteratorError>;
/// Attempt to deserialize, assume input is a stack of zero or more PEM-encoded certificates
fn from_pem<T: AsRef<[u8]>>(src: T) -> Result<Self, Self::X509IteratorError>;
/// Attempt to deserialize, assume input is a DER-encoded PKCS7 certificate bundle
fn from_pkcs7<T: AsRef<[u8]>>(src: T) -> Result<Self, Self::X509IteratorError>;
}
/// Error type bounds
pub trait X509IteratorError: Display + Debug {}
错误处理
X509Iterator
实现可以返回由X509Iterator::X509IteratorError
关联类型定义的任何错误类型,该类型由X509IteratorError
特性行绑定。本身X509IteratorError
特性行只由Display + Debug
绑定。
迭代器错误将作为X509ClientError::X509IteratorError
变体呈现给调用者。
错误转换的实现如下
use std::fmt::{Debug, Display, Formatter};
use x509_client::X509ClientError;
use x509_client::api::X509IteratorError;
#[derive(Debug)]
struct MyX509IteratorError;
impl Display for MyX509IteratorError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "")
}
}
impl X509IteratorError for MyX509IteratorError {}
impl From<MyX509IteratorError> for X509ClientError {
fn from(e: MyX509IteratorError) -> Self {
Self::X509IteratorError(Box::new(e))
}
}
实现
默认
如果启用默认功能,则可提供基于RustCrypto的DefaultX509Iterator
实现。
OpenSSL
如果启用OpenSSL功能,则可提供基于OpenSSLX509Iterator
的实现。
调试
调试实现DebugX509Iterator
始终可用。它将服务器返回的字节复制到Once<bytes::Bytes>迭代器。
依赖项
~6–23MB
~308K SLoC