10个版本

0.3.5 2023年1月23日
0.3.4 2022年10月18日
0.3.3 2022年8月2日
0.3.2 2021年10月29日
0.1.2 2021年8月30日

#207 in 编码

Download history 12/week @ 2024-03-13 15/week @ 2024-03-20 17/week @ 2024-03-27 169/week @ 2024-04-03 25/week @ 2024-04-10 3/week @ 2024-04-17 10/week @ 2024-04-24 5/week @ 2024-05-01 1/week @ 2024-05-08 2/week @ 2024-05-15 5/week @ 2024-05-22 26/week @ 2024-05-29 318/week @ 2024-06-05 723/week @ 2024-06-12 785/week @ 2024-06-19 232/week @ 2024-06-26

2,069 monthly downloads
用于 2 个 crate (via kmip-protocol)

BSD-3-Clause

255KB
3.5K SLoC

CI Crate Docs

kmip-ttlv - 用于序列化和反序列化KMIP TTLV的库

KMIP:

OASIS密钥管理互操作性协议规范,该规范定义了在密钥管理服务器上操作加密材料的消息格式。

TTLV:

KMIP规范的一个构建块,定义了如何将结构化数据编码/解码为二进制形式,作为Tag-Type-Length-Value(简称TTLV)项的序列。

欢迎

此crate提供KMIP v1.0 TTLV(反)序列化功能的部分实现,供kmip-protocol crate使用。如果您想将自己的产品添加KMIP支持,应使用kmip-protocol crate。TTLV在KMIP中定义,但与KMIP独立,因此理论上也可以用于除KMIP之外的应用程序的(反)序列化。

目的

此crate提供了从/到等效KMIP TTLV字节数表示的Rust原语(例如i32)的低级(反)序列化。它提供了一种基于Serde Derive的单个to_/from_调用风格的(反)序列化整个Rust类型层次结构的API(这最容易被Serde Derive属性驱动),以及一个低级API,用于一次序列化一个TTLV字段(标签、类型、长度或值),以实现完全控制。

目前范围限于二进制TTLV协议。对后续KMIP规范中定义的XML或JSON表示形式的支持不在范围内。

文档

完整的API文档可以在https://docs.rs/kmip-ttlv/查看。

状态

此crate以现状提供,不提供稳定性、质量或正确性的保证。使用风险自负。

请参阅https://github.com/NLnetLabs/kmip-ttlv/blob/main/src/tests/,了解对低级和高级(基于Serde)API的各种自动化测试。已成功对PyKMIP和Kryptus Cloud HSM服务器进行了有限的手动测试。

问题报告、功能请求和贡献可以通过我们的GitHub仓库提交。

本crate的功能以及支持的TTLV和Rust数据类型,是为了为kmip-protocol crate提供基础。因此,本crate目前还不支持所有可能的TTLV或Rust类型。

并非所有TTLV类型都受支持

TTLV类型 TTLV类型代码 受支持?
结构 0x01
整数 0x02
长整数 0x03
大整数 0x04 (序列化仅在低级API中支持,不在Serde中支持)
枚举 0x05
布尔值 0x06
文本字符串 0x07
字节字符串 0x08
日期时间 0x09
间隔 0x0A

设计目标

  • 提供一个强类型接口,防止在高级KMIP接口规范中没有正确意义的低级构建块的错误组合。利用Rust的编译时能力,尽可能防止编写错误的请求,以最大限度地减少运行时对协议的错误使用。
  • 以简洁的方式支持高级KMIP请求结构的组合,并且使编写的代码与KMIP规范明显相关。
  • 使用反序列化数据不应需要详细了解KMIP规范,即应使用Rust类型,而不是TTLV类型,并且与之交互的对象应具有清晰命名的字段,并且只包含与请求相关的响应字段。
  • TTLV标签代码应在它们标记的类型定义附近定义。

示例代码

基于KMIP v1.0规范第3.1.1节中定义的“创建/销毁”用例

以下示例假设客户端代码已定义Rust structs,根据需要将其转换为#[derive(Serialize)]#[derive(Deserialize)],以便Serde基于(反)序列化器知道每个数据结构应使用哪些标签代码。

(可能更改)

请求构建

// serialize the request
let req = RequestMessage(
    RequestHeader(
        request::ProtocolVersion(ProtocolVersionMajor(1), ProtocolVersionMinor(0)),
        Option::<MaximumResponseSize>::None,
        Option::<Authentication>::None,
        BatchCount(1),
    ),
    vec![BatchItem(
        Operation::Create,
        Option::<UniqueBatchItemID>::None,
        RequestPayload::Create(
            ObjectType::SymmetricKey,
            TemplateAttribute::named(
                "Template1".into(),
                vec![
                    Attribute::CryptographicAlgorithm(CryptographicAlgorithm::AES),
                    Attribute::CryptographicLength(128),
                    Attribute::CryptographicUsageMask(
                        CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
                    ),
                ],
            ),
        ),
    )],
);

let ttlv_wire: Vec<u8> = to_vec(&req).unwrap();
// now write the `ttlv_wire` request bytes to an open TLS connection to the server

响应处理

// read the `ttlv_wire` response bytes from an open TLS connection to the server:
let ttlv_wire: Vec<u8> = ...;

// deserialize the response
let res: ResponseMessage = from_slice(ttlv_wire.as_ref()).unwrap();

assert_eq!(res.header.protocol_version.major, 1);
assert_eq!(res.header.protocol_version.minor, 0);
assert_eq!(res.header.timestamp, 0x4AFBE7C5);
assert_eq!(res.header.batch_count, 1);
assert_eq!(res.batch_items.len(), 1);

let item = &res.batch_items[0];
assert!(matches!(item.result_status, ResultStatus::Success));
assert!(matches!(item.operation, Some(Operation::Create)));
assert!(matches!(&item.payload, Some(ResponsePayload::Create(_))));

if let Some(ResponsePayload::Create(payload)) = item.payload.as_ref() {
    assert!(matches!(payload.object_type, ObjectType::SymmetricKey));
    assert_eq!(&payload.unique_identifier, KEY_ID);
} 

处理时间戳

时间戳以TTLV Date-Time格式存储,该格式转换为64位整数,直到您正确并正确地解释它并在正确时区的上下文中,它才具有现实世界的意义。直接处理64位整数值可能不切实际。本crate目前不提供更轻松地处理这些值的方法,但使用Rust生态系统中的现有crate进行此操作相对容易。

例如,对于上面基于官方KMIP用例的示例,用例描述表明 0x4AFBE7C5 的值等同于 Thu Nov 12 11:47:32 CET 2009。以下我们使用 chrono 包来演示这是真实的,并展示如何在您的应用程序中处理 Date-Time 值。

let one_hour_in_seconds = 3600;
let cet_tz = chrono::offset::FixedOffset::east(one_hour_in_seconds);
let cet_ts = cet_tz.timestamp(res.header.timestamp);
assert_eq!(cet_ts, cet_tz.ymd(2009,11,12).and_hms(11,47,32)
assert_eq!(cet_ts.format("%a %b %e %T %Z %Y").to_string(), "Thu Nov 12 11:47:32 +01:00 2009");

依赖关系

~1–12MB
~144K SLoC