Skip to main content

Module resolver

Module resolver 

Source
Expand description

DID resolution and production: the DidResolver and DidProducer traits a DID method implements, the Resolver registry that routes a DID to the resolver of its method, an optional TTL DocumentCache, and DID URL dereferencing. Beside DIDs, finding the key a token was signed with: KeyReference and KeyResolver.

The module ships no DID method. Each method is a type implementing DidResolver and/or DidProducer, registered with ResolverBuilder::with; adding one needs no change here.

§Resolution

Resolver::resolve implements the DID Resolution algorithm around the method’s resolver: it reports ResolutionErrorKind::MethodNotSupported for a method nobody registered, turns a result whose metadata reports an error into Err, refuses a document whose id is not the DID being resolved (nor its canonicalId), and serves repeated resolutions from the cache when one is configured. Resolver::resolve_document is the shortcut to the document.

§Dereferencing

Resolver::dereference resolves the DID of a DID URL and then selects the resource the URL names: the document itself, or the verification method or service whose id is the URL (Dereferenced). The versionId and versionTime DID parameters are passed to the method’s resolver as resolution options; a path, any other query parameter and the service/relativeRef parameters are method-specific and reported as DereferenceError::MethodSpecific. Resolver::resolve_public_key goes one step further and returns the Jwk of a verification method, optionally checked to be usable for a verification relationship, decoding publicKeyMultibase material as a Multikey, which is what a JWS verifier needs.

§Key references

A JWT names the key that signed it in one of several ways (ADR 0006), and KeyReference::from_jws reads which, in this order: a kid that is a DID URL (did:…#fragment, without a path or DID parameters); a kid that is a #fragment, joined with a DID iss; another kid with an HTTPS iss, naming a key of the issuer’s key set; the key itself in a jwk header; an x5c certificate chain; a jku key set URL. A KeyResolver turns the reference into a key for a KeyRole, the issuer’s (assertionMethod in a DID document) or the subject’s (authentication):

ReferenceResolved by
KeyReference::DidUrlResolver, dereferencing the verification method
KeyReference::JwkJwkResolver, the key itself
KeyReference::JwksJwksResolver (feature jwks), the JWT VC issuer metadata of the issuer
KeyReference::X509Chain, KeyReference::Jkunothing in the crate yet; an application’s own KeyResolver

CompositeKeyResolver tries several in order. Resolving says nothing about trust: after the signature verifies, KeyReference::binds_to checks that the key belongs to the party the token claims, which the validators of the upper layer do.

§Plain JWTs

JwtValidator validates a JWT that is neither a credential nor a presentation, an OAuth 2.0 access token say, as RFC 7519 §7.2 and RFC 8725 describe: an allowed alg, the expected typ, the signature under the key a KeyResolver finds, that key bound to iss (IssuerBinding), the expected iss and aud, exp, nbf and iat within a leeway, and the claims the JwtValidationOptions require.

§Examples

A method is a type implementing DidResolver; here one that serves documents from memory.

use std::collections::HashMap;

use identity_kit::did::{
    Did, DidDocument, DidUrl, ResolutionError, ResolutionErrorKind, ResolutionOptions,
    ResolutionResult,
};
use identity_kit::resolver::{Dereferenced, DidResolver, Resolver};

struct Static(HashMap<Did, DidDocument>);

#[async_trait::async_trait]
impl DidResolver for Static {
    fn method(&self) -> &'static str {
        "example"
    }

    async fn resolve(
        &self,
        did: &Did,
        _: &ResolutionOptions,
    ) -> Result<ResolutionResult, ResolutionError> {
        self.0.get(did).cloned().map(ResolutionResult::new).ok_or_else(|| {
            ResolutionError::new(ResolutionErrorKind::NotFound)
                .with_detail(format!("no document is stored for `{did}`"))
        })
    }
}

let document: DidDocument = serde_json::from_str(r##"{
  "id": "did:example:123",
  "verificationMethod": [{
    "id": "did:example:123#key-1",
    "type": "JsonWebKey2020",
    "controller": "did:example:123",
    "publicKeyJwk": {
      "kty": "OKP", "crv": "Ed25519", "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
    }
  }],
  "authentication": ["#key-1"]
}"##)?;
let did = document.id.clone();
let resolver = Resolver::builder()
    .with(Static(HashMap::from([(did.clone(), document)])))
    .cache(std::time::Duration::from_secs(60))
    .build();

assert_eq!(resolver.resolve_document(&did).await?.id, did);

let key = DidUrl::parse("did:example:123#key-1")?;
let jwk = resolver.resolve_public_key(&key, None).await?;
assert_eq!(jwk.crv(), Some("Ed25519"));
assert!(matches!(resolver.dereference(&key).await?, Dereferenced::VerificationMethod(_)));

let unknown = Did::parse("did:other:123")?;
let error = resolver.resolve(&unknown).await.unwrap_err();
assert_eq!(error, ResolutionErrorKind::MethodNotSupported);
assert_eq!(error.detail(), Some("no resolver is registered for `did:other`"));

Structs§

CompositeKeyResolver
Resolvers tried in order: the first answer other than Unsupported is the answer, an error included.
DocumentCache
A bounded cache of resolution results, keyed by DID, where every entry expires after the same time to live.
JwkResolver
Resolves a KeyReference::Jwk to its public part; every other reference is Unsupported.
JwksResolverjwks
Resolves a KeyReference::Jwks through the JWT VC issuer metadata of the issuer (SD-JWT VC §3.5); every other reference is Unsupported.
JwtValidationOptions
Options of JwtValidator: what the token must be, and when.
JwtValidator
Validates a compact JWT that is neither a credential nor a presentation: an OAuth 2.0 access token (RFC 9068), an ID token, a request object.
MethodCapabilities
What a DID method can do, declared by its DidProducer so an application can pick a method without knowing it.
Resolver
Routes each DID to the DidResolver registered for its method, with an optional DocumentCache in front.
ResolverBuilder
Builds a Resolver.
ValidatedJwt
A JWT that passed JwtValidator::validate: its header, its claims and the key that signed it.

Enums§

DereferenceError
Why a DID URL could not be dereferenced.
Dereferenced
The resource a DID URL names, as Resolver::dereference returns it.
Hosting
Where the documents of a DID method live, which decides what creating one involves.
IssuerBinding
Whether the key that signed a token must belong to its issuer.
JwksErrorjwks
Why a JwksResolver found no key.
JwtValidationError
Why a JWT did not pass JwtValidator::validate.
KeyReference
Where a token says the key that signed it is (ADR 0006).
KeyReferenceError
Why a token names no key this crate can look for.
KeyResolutionError
Why a KeyResolver found no key.
KeyRole
The role a key plays in a token, which decides what a DID document must say about it.
ProduceError
Why a DidProducer could not produce a document.

Traits§

DidProducer
Produces the DID document of one method from public keys.
DidResolver
Resolves the DIDs of one method (DID Resolution “DID Resolution Algorithm”).
KeyResolver
Finds the public key a KeyReference names.