4 个版本

0.2.0 2024年8月14日
0.1.2 2024年1月11日
0.1.1 2023年11月20日
0.1.0 2023年6月21日

#265编码

Download history 10/week @ 2024-05-13 23/week @ 2024-05-20 5/week @ 2024-05-27 17/week @ 2024-06-03 13/week @ 2024-06-10 2/week @ 2024-06-24 4/week @ 2024-07-08 15/week @ 2024-07-29 131/week @ 2024-08-12

每月146次下载
ccatoken 中使用

Apache-2.0

155KB
3.5K SLoC

这是对 EAT Attestation ResultsAttestation Results for Secure Interactions (AR4SI) 的实现。

示例

签名

use std::collections::BTreeMap;
use ear::{Ear, VerifierID, Algorithm, Appraisal};

const SIGNING_KEY: &str = "-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPp4XZRnRHSMhGg0t
6yjQCRV35J4TUY4idLgiCu6EyLqhRANCAAQbx8C533c2AKDwL/RtjVipVnnM2WRv
5w2wZNCJrubSK0StYKJ71CikDgkhw8M90ojfRIowqpl0uLA3kW3PEZy9
-----END PRIVATE KEY-----
";

fn main() {
    let token = Ear{
        profile: "test".to_string(),
        iat: 1,
        vid: VerifierID {
            build: "vsts 0.0.1".to_string(),
            developer: "https://veraison-project.org".to_string(),
        },
        raw_evidence: None,
        nonce: None,
        submods: BTreeMap::from([("test".to_string(), Appraisal::new())]),
    };

    let signed = token.sign_jwt_pem(Algorithm::ES256, SIGNING_KEY.as_bytes()).unwrap();
}

验证

use ear::{Ear, Algorithm};

const VERIF_KEY: &str = r#"
{
    "kty":"EC",
    "crv":"P-256",
    "x":"G8fAud93NgCg8C_0bY1YqVZ5zNlkb-cNsGTQia7m0is",
    "y":"RK1gonvUKKQOCSHDwz3SiN9EijCqmXS4sDeRbc8RnL0"
}
"#;

fn main() {
    let signed = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJlYXRfcHJvZmlsZSI6InRlc3QiLCJpYXQiOjEsImVhci52ZXJpZmllci1pZCI6eyJkZXZlbG9wZXIiOiJodHRwczovL3ZlcmFpc29uLXByb2plY3Qub3JnIiwiYnVpbGQiOiJ2c3RzIDAuMC4xIn0sInN1Ym1vZHMiOnsidGVzdCI6eyJlYXIuc3RhdHVzIjoibm9uZSJ9fX0.G25v0j0NDQhSOcK3Jtfq5vqVxnoWuWf-Q0DCNkCwpyB03DGr25ZDJ3IDSAHVPZrr6TVMwj8RcGEzQnCrucem4Q";

    let token = Ear::from_jwt_jwk(signed, Algorithm::ES256, VERIF_KEY.as_bytes()).unwrap();
    println!("EAR profiles: {}", token.profile);
}

扩展和配置文件

EAR 支持在顶层(即 Ear 结构体内部)以及 Appraisal 内部进行扩展。扩展是额外的字段定义。可以通过将它们注册到相应结构体的 extensions 字段来定义扩展。在注册扩展时,您必须提供一个字符串名称(用于 JSON),一个整数键(用于 CBOR),以及一个 ExtensionKind 来指示哪些 ExtensionValue 是有效的。

注册单个扩展

可以直接通过相应结构体的 extensions 字段注册扩展。一旦注册,它们的值就可以设置和查询。

use ear::{Ear, Appraisal, ExtensionKind, ExtensionValue};

let mut ear = Ear::new();
ear.extensions.register("ext.company-name", -65537, ExtensionKind::String).unwrap();

let mut appraisal = Appraisal::new();
// extensions for Ear's and Appraisal's have their own namespaces, so it is
// to use the same key in both.
appraisal.extensions.register("ext.timestamp", -65537, ExtensionKind::Integer).unwrap();

ear.extensions.set_by_name(
    "ext.company-name",
    ExtensionValue::String("Acme Inc.".to_string()),
).unwrap();

appraisal.extensions.set_by_key(
    -65537,
    ExtensionValue::Integer(1723534859),
).unwrap();

ear.submods.insert("road-runner-trap".to_string(), appraisal);

assert_eq!(
   ear.extensions.get_by_key(&-65537).unwrap(),
   ExtensionValue::String("Acme Inc.".to_string()),
);

assert_eq!(
   ear.submods["road-runner-trap"].extensions.get_by_name("ext.timestamp").unwrap(),
   ExtensionValue::Integer(1723534859),
);

注意:如果您通过从 CBOR/JSON 反序列化获得了 Ear,则 Extensions 结构体将缓存任何意外的字段的值,以便在之后注册扩展时,相应的反序列化值将可访问。

使用配置文件

可以在 Profile 中关联扩展集合。可以注册一个 Profile,然后在创建新的 EarAppraisal 时通过其 id 查询。

use ear::{Ear, Appraisal, ExtensionKind, ExtensionValue, Profile, register_profile};

fn init_profile() {
    let mut profile = Profile::new("tag:github.com,2023:veraison/ear#acme-profile");

    profile.register_ear_extension(
        "ext.company-name", -65537, ExtensionKind::String).unwrap();
    profile.register_appraisal_extension(
        "ext.timestamp", -65537, ExtensionKind::Integer).unwrap();

    register_profile(&profile);
}

fn main() {
    init_profile();

    let mut ear = Ear::new_with_profile(
        "tag:github.com,2023:veraison/ear#acme-profile").unwrap();
    // these will apply to all submods/appraisals within a profiled EAR
    let mut appraisal = Appraisal::new_with_profile(
        "tag:github.com,2023:veraison/ear#acme-profile").unwrap();

    ear.extensions.set_by_name(
        "ext.company-name",
        ExtensionValue::String("Acme Inc.".to_string()),
    ).unwrap();

    appraisal.extensions.set_by_key(
        -65537,
        ExtensionValue::Integer(1723534859),
    ).unwrap();

    ear.submods.insert("road-runner-trap".to_string(), appraisal);

    assert_eq!(
       ear.extensions.get_by_key(&-65537).unwrap(),
       ExtensionValue::String("Acme Inc.".to_string()),
    );

    assert_eq!(
       ear.submods["road-runner-trap"]
            .extensions.get_by_name("ext.timestamp").unwrap(),
       ExtensionValue::Integer(1723534859),
    );
}

在反序列化 Ear 时,其 profile 字段将自动用于查找已注册的配置文件并添加关联的扩展。

限制

  • 签名支持 PEM 和 DER 密钥;验证目前仅支持 JWK 密钥。
  • JWT 签名目前仅支持 ES256、ES384、EdDSA、PS256、PS384 和 PS512。
  • COSE 签名目前仅支持 ES256、ES384、ES512 和 EdDSA。

依赖关系

~4–16MB
~252K SLoC