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 身份验证
2,929 每月下载量
用于 12 个库 (4 个直接使用)
1MB
17K SLoC
SSI
SSI 库提供了一个简单且模块化的 API,用于在应用程序之间使用 去中心化标识符 (DID) 签署和验证声明。SSI 作为跨平台的 didkit
库的核心依赖项嵌入。
此库支持可验证声明的两大类
- JSON Web Tokens (JWT),其中声明编码到 JSON 中,并使用 JSON Web 签名 进行安全保护;以及
- W3C 的可验证凭证 (VCs),这是一个基于 [链接数据][linked-data] 的模型,其中声明(VC)可以解释为 RDF 数据集。VC 支持SSI提供的多种签名格式。
基本用法
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上下文并使用SpecializedJsonCredential
的context
字段或利用其上下文类型参数将其嵌入到credential
中来实现。
功能
安全审计
ssi已接受以下安全审查
测试
测试SSI需要RDF规范化测试套件,该套件作为git子模块嵌入。
$ git submodule update --init
$ cargo test --workspace
贡献
我们正在建立接受贡献的过程。请在此期间随意打开问题或PR,但我们不能在建立此过程之前合并外部更改。
依赖关系
~37–62MB
~1M SLoC