10 个版本 (6 个重大更新)

0.8.1 2024 年 8 月 1 日
0.8.0 2024 年 7 月 26 日
0.7.0 2023 年 6 月 28 日
0.6.0 2023 年 3 月 8 日
0.1.0 2020 年 7 月 23 日

#34 in 身份验证

Download history 877/week @ 2024-05-05 662/week @ 2024-05-12 508/week @ 2024-05-19 358/week @ 2024-05-26 589/week @ 2024-06-02 420/week @ 2024-06-09 532/week @ 2024-06-16 587/week @ 2024-06-23 417/week @ 2024-06-30 564/week @ 2024-07-07 314/week @ 2024-07-14 311/week @ 2024-07-21 719/week @ 2024-07-28 480/week @ 2024-08-04 988/week @ 2024-08-11 687/week @ 2024-08-18

2,929 每月下载量
用于 12 个库 (4 个直接使用)

Apache-2.0 和可能 GPL-3.0

1MB
17K SLoC

SSI

SSI 库提供了一个简单且模块化的 API,用于在应用程序之间使用 去中心化标识符 (DID) 签署和验证声明。SSI 作为跨平台的 didkit 库的核心依赖项嵌入。

此库支持可验证声明的两大类

基本用法

SSI 提供了各种函数来解析、验证、创建和签署各种类型的声明。本节展示了如何将这些函数与 JSON Web 签名(或令牌)和可验证凭证结合使用。

验证

最简单加载和验证的声明类型可能是JSON Web签名(JWSs),通常用于编码JSON Web令牌(JWTs)。为了表示此类声明,SSI提供了表示紧凑文本形式的JWS的CompactJWSString类型。可以使用from_string加载JWS,并使用verify验证它。

use ssi::prelude::*;

// Load a JWT from the file system.
let jwt = CompactJWSString::from_string(
  std::fs::read_to_string("examples/files/claims.jwt")
  .expect("unable to load JWT")
).expect("invalid JWS");

// Setup a verification method resolver, in charge of retrieving the
// public key used to sign the JWT.
// Here we use the example `ExampleDIDResolver` resolver, enabled with the
// `example` feature.
let vm_resolver = ExampleDIDResolver::default().into_vm_resolver::<AnyJwkMethod>();

// Verify the JWT.
assert!(jwt.verify(&vm_resolver).await.expect("verification failed").is_ok())

可验证凭证

可验证凭证比简单的声明复杂得多,因为它们需要解释输入声明和证明,例如使用JSON-LD进行数据完整性证明。此操作非常可配置。SSI提供了暴露各种级别实现细节的函数,您可以按需调整。其中最简单的是any_credential_from_json_str,它将从字符串加载VC,假设它使用SSI支持的任何数据完整性证明进行签名。

use ssi::prelude::*;

let vc = ssi::claims::vc::v1::data_integrity::any_credential_from_json_str(
  &std::fs::read_to_string("examples/files/vc.jsonld")
  .expect("unable to load VC")
).await.expect("invalid VC");

// Setup a verification method resolver, in charge of retrieving the
// public key used to sign the JWT.
let vm_resolver = ExampleDIDResolver::default().into_vm_resolver();

assert!(vc.verify(&vm_resolver).await.expect("verification failed").is_ok());

签名和自定义声明

在上一节中,我们了解了如何加载和验证任意声明。本节将展示如何创建和签名自定义声明。使用SSI,任何符合某些条件(如使用serde实现序列化/反序列化函数)的Rust类型都可以作为声明。不要忘记为serde启用derive功能。

以下示例中,我们创建一个自定义类型MyClaims并将其作为JWT进行签名。

use serde::{Serialize, Deserialize};
use ssi::prelude::*;

// Defines the shape of our custom claims.
#[derive(Serialize, Deserialize)]
pub struct MyClaims {
  name: String,
  email: String
}

// Create JWT claims from our custom ("private") claims.
let claims = JWTClaims::from_private_claims(MyClaims {
  name: "John Smith".to_owned(),
  email: "[email protected]".to_owned()
});

// Create a random signing key, and turn its public part into a DID URL.
let mut key = JWK::generate_p256(); // requires the `p256` feature.
let did = DIDJWK::generate_url(&key.to_public());
key.key_id = Some(did.into());

// Sign the claims.
let jwt = claims.sign(&key).await.expect("signature failed");

// Create a verification method resolver, which will be in charge of
// decoding the DID back into a public key.
let vm_resolver = DIDJWK.into_vm_resolver::<AnyJwkMethod>();

// Verify the JWT.
assert!(jwt.verify(&vm_resolver).await.expect("verification failed").is_ok());

// Print the JWT.
println!("{jwt}")

可验证凭证

我们可以使用类似的技术使用自定义声明签名VC。SpecializedJsonCredential类型提供了一个可自定义的VC数据模型实现,您可以自行设置凭证类型。

use static_iref::uri;
use serde::{Serialize, Deserialize};
use ssi::prelude::*;

// Defines the shape of our custom claims.
#[derive(Serialize, Deserialize)]
pub struct MyCredentialSubject {
  #[serde(rename = "https://example.org/#name")]
  name: String,

  #[serde(rename = "https://example.org/#email")]
  email: String
}

let credential = ssi::claims::vc::v1::JsonCredential::<MyCredentialSubject>::new(
  Some(uri!("https://example.org/#CredentialId").to_owned()), // id
  uri!("https://example.org/#Issuer").to_owned().into(), // issuer
  DateTime::now(), // issuance date
  vec![MyCredentialSubject {
    name: "John Smith".to_owned(),
    email: "[email protected]".to_owned()
  }]
);

// Create a random signing key, and turn its public part into a DID URL.
let key = JWK::generate_p256(); // requires the `p256` feature.
let did = DIDJWK::generate_url(&key.to_public());

// Create a verification method resolver, which will be in charge of
// decoding the DID back into a public key.
let vm_resolver = DIDJWK.into_vm_resolver();

// Create a signer from the secret key.
// Here we use the simple `SingleSecretSigner` signer type which always uses
// the same provided secret key to sign messages.
let signer = SingleSecretSigner::new(key.clone());

// Turn the DID URL into a verification method reference.
let verification_method = did.into_iri().into();

// Automatically pick a suitable Data-Integrity signature suite for our key.
let cryptosuite = AnySuite::pick(&key, Some(&verification_method))
  .expect("could not find appropriate cryptosuite");

let vc = cryptosuite.sign(
  credential,
  AnyInputContext::default(),
  &vm_resolver,
  &signer,
  ProofConfiguration::from_method(verification_method)
).await.expect("signature failed");

确保自定义声明可以解释为链接数据至关重要。在上面的示例中,这是通过为MyCredentialSubject的每个字段指定序列化URL来实现的。这也可以通过创建自定义JSON-LD上下文并使用SpecializedJsonCredentialcontext字段或利用其上下文类型参数将其嵌入到credential中来实现。

功能

安全审计

ssi已接受以下安全审查

测试

测试SSI需要RDF规范化测试套件,该套件作为git子模块嵌入。

$ git submodule update --init
$ cargo test --workspace

贡献

我们正在建立接受贡献的过程。请在此期间随意打开问题或PR,但我们不能在建立此过程之前合并外部更改。

依赖关系

~37–62MB
~1M SLoC