A trust schema comprises a set of linked trust rules and one or more trust anchors.
A trust rule is an association of the data name with its signing key name.
It can either associate an application data name with its signing key name, or associate a certificate name with its issuer key name.
One or more trust anchors, i.e. pre-authenticated keys, are included in the trust schema to serve as bootstrapping points of the trust model.
Structural and signing relationships between names.
The language specification is fairly complex and contains certain ambiguity.
The compiler implementation is found to have several limitations.
python-ndn library authors defined Light VerSec (LVS), a lightweight modification of VerSec that focuses on signing key validation.
Its syntax and semantics are similar to VerSec.
For ease of processing, LVS introduced some restrictions on identifier names and token ordering.
The trust schema implementation in this package is inspired by the above documents and projects.
The overall structure is:
TrustSchema
+-TrustSchemaPolicy
| +-patterns = set of
| | id => Pattern
| | +-ConstPattern
| | +-VariablePattern
| | +-CertNamePattern
| | +-ConcatPattern
| | \-AlternatePattern
| |
| \-rules = set of
| packet name pattern id => signer name pattern id
|
\-trust anchors = array of Certificate
TrustSchema type represents a trust schema.
It contains a TrustSchemaPolicy and an array of trust anchor certificates.
TrustSchemaPolicy type represents the policy portion of a trust schema.
It contains a set of patterns, each has a unique id string.
It also contains a set of rules, which indicates a packet matching the first pattern should be signed by a key matching the second pattern.
Pattern type represents a pattern in the trust schema policy.
It must be one of these sub-types:
ConstPattern matches one or more name components specified as a constant in the policy.
VariablePattern matches one or more name components (specified as a range), optionally overlapped with an inner pattern and filtered by a JavaScript function.
It can save matched components to a variable.
When the same variable appears in both packet name pattern and signer name pattern, the matched name component(s) must be the same.
CertNamePattern matches either KEY/key-id or KEY/key-id/issuer-id/version suffix in NDN Certificate Format.
ConcatPattern concatenates two or more other patterns.
AlternatePattern accepts any match among two or more possible patterns.
// Notice the variable name distinction between 'adminName' and 'authorName', which is necessary // to allow them to have different values. Also, the variables cannot be named 'admin' and 'author' // because that would clash with the pattern names that are implicitly declared as variables. admin: _site/"admin"/adminName/_KEY <= root author: _site/_role/authorName/_KEY & { _role: "author" } <= admin
_KEY: "KEY"/_/_/_ `);
versec.print() function prints the policy in VerSec syntax.
You may notice that the output differs from the input, because the library has flattened the patterns for faster execution.
Occasionally, certain features may not print correctly, especially if the policy was imported from a different syntax.
printESM() function prints the policy as ECMAScript module.
It shows how you can define the same policy in code.
However, it cannot automatically convert certain VerSec features, and manual edits would be necessary in such cases.
Writing the policy in code can reduce JavaScript bundle size in a web application, because the VerSec compiler is no longer needed at runtime.
console.group("VerSec policy in ESM"); console.log(printESM(policy)); console.groupEnd();
With the policy in place, we can generate a root key and make the trust schema object.
const [adminPvt, adminPub] = awaitgenerateSigningKey(keyChain, "/a/blog/admin/Lixia"); constadminCert = awaitCertificate.issue({ publicKey:adminPub, validity:ValidityPeriod.daysFromNow(30), issuerId:Component.from("blog"), issuerPrivateKey:schemaSigner, }); awaitkeyChain.insertCert(adminCert); // admin certificate should be signed by root key assert.equal(adminCert.issuer?.toString(), rootCert.name.toString());
const [authorPvt, authorPub] = awaitgenerateSigningKey(keyChain, "/a/blog/author/Yingdi"); constauthorCert = awaitCertificate.issue({ publicKey:authorPub, validity:ValidityPeriod.daysFromNow(30), issuerId:Component.from("blog"), issuerPrivateKey:schemaSigner, }); awaitkeyChain.insertCert(authorCert); // author certificate should be signed by admin key assert.equal(authorCert.issuer?.toString(), adminCert.name.toString());
constarticleData = newData("/a/blog/article/food/2015/1"); awaitschemaSigner.sign(articleData); // article should be signed by author key assert.equal(articleData.sigInfo.keyLocator?.name?.toString(), authorCert.name.toString());
// Data that does not match the policy cannot be signed. constotherData = newData("/a/blog/not-article/poison/2015/13"); awaitassert.rejects(schemaSigner.sign(otherData));
TrustSchemaVerifier type can verify packets according to the trust schema.
It can collect intermediate certificates from a local KeyChain and from the network.
// The article is trusted. awaitschemaVerifier.verify(articleData);
// Although an author could sign the other Data manually, it is not trusted by schema. awaitauthorPvt.sign(otherData); awaitassert.rejects(schemaVerifier.verify(otherData));
@ndn/trust-schema
This package is part of NDNts, Named Data Networking libraries for the modern web.
This package implements trust schemas.
Trust Schema Introduction
Yingdi Yu proposed trust schema in Schematizing Trust in Named Data Networking. According to his definition:
Pollere LLC released Versatile Security Toolkit (VerSec) as part of Data-centric Communications Toolkit (DCT). It has a schema description language that describes constraints on:
The language specification is fairly complex and contains certain ambiguity. The compiler implementation is found to have several limitations.
python-ndn library authors defined Light VerSec (LVS), a lightweight modification of VerSec that focuses on signing key validation. Its syntax and semantics are similar to VerSec. For ease of processing, LVS introduced some restrictions on identifier names and token ordering.
Trust Schema Representation
The trust schema implementation in this package is inspired by the above documents and projects. The overall structure is:
TrustSchema
type represents a trust schema. It contains aTrustSchemaPolicy
and an array of trust anchor certificates.TrustSchemaPolicy
type represents the policy portion of a trust schema. It contains a set of patterns, each has a uniqueid
string. It also contains a set of rules, which indicates a packet matching the first pattern should be signed by a key matching the second pattern.Pattern
type represents a pattern in the trust schema policy. It must be one of these sub-types:ConstPattern
matches one or more name components specified as a constant in the policy.VariablePattern
matches one or more name components (specified as a range), optionally overlapped with an inner pattern and filtered by a JavaScript function. It can save matched components to a variable. When the same variable appears in both packet name pattern and signer name pattern, the matched name component(s) must be the same.CertNamePattern
matches eitherKEY/key-id
orKEY/key-id/issuer-id/version
suffix in NDN Certificate Format.ConcatPattern
concatenates two or more other patterns.AlternatePattern
accepts any match among two or more possible patterns.VerSec Syntax
This package has partial support of the VerSec syntax, including:
timestamp
function: translates to aVariablePattern
that matches a Timestamp name componentseq
function: translates to aVariablePattern
that matches a SequenceNum name componentsysid
,host
,uid
,pid
function: translates to aVariablePattern
that assigns to a variable of the same name upper-casedSome notes and limitations:
CertNamePattern
is created by"KEY"/_/_/_
, which should be included at the end of each certificate name._
cannot be used in signing constraints and signing chains.versec.load()
function imports a policy written in VerSec syntax:versec.print()
function prints the policy in VerSec syntax. You may notice that the output differs from the input, because the library has flattened the patterns for faster execution. Occasionally, certain features may not print correctly, especially if the policy was imported from a different syntax.printESM()
function prints the policy as ECMAScript module. It shows how you can define the same policy in code. However, it cannot automatically convert certain VerSec features, and manual edits would be necessary in such cases. Writing the policy in code can reduce JavaScript bundle size in a web application, because the VerSec compiler is no longer needed at runtime.With the policy in place, we can generate a root key and make the trust schema object.
Trust Schema Signer
TrustSchemaSigner
type can automatically select a signer among available certificates in the KeyChain.Trust Schema Verifier
TrustSchemaVerifier
type can verify packets according to the trust schema. It can collect intermediate certificates from a local KeyChain and from the network.