This document describes a mechanism to add enveloped signatures to JSON objects. This mechanism combines the signing and key management of JWS with a subset of the features of XML Signatures. Unlike JWS, it supports multiple signatures, selective signatures over only part of the information in the document, and canonicalization.
This specification is designed to be usable to sign WoT Thing Descriptions [[WOT-THING-DESCRIPTION]], although it is not limited to this use case. An ontology is also defined so it can be used with JSON-LD. However, it is designed to only require JSON processing, not RDF.
To do. Examples should go here.
This section defines a Signature object and signing process that
can be used to preserve the integrity of all or part of a JSON object.
SignedInfoA collection of information to be protected by a Signature,
including a reference (which may be one of several query types) to
a subset of the enclosing JSON object,
a digest (hash) of the reference result, and
an identification of the digest algorithms used.
| Vocabulary term | Description | Assignment | Type |
|---|---|---|---|
reference |
Pointer or query string identifying the subset of the enclosing JSON object to sign. | mandatory | string |
referenceType |
The type of reference used to define the subset of the enclosing JSON object to sign.
Can be one of jsonpointer, jsonpath, or xpath. |
mandatory | string |
digest |
A digest value computed from the result of the specified reference. | mandatory | string |
digestAlg |
The algorithm used to compute the digest value. One of
sha256, sha384, or sha512.
| mandatory | string |
SignatureA Signature object includes an array of SignedInfo objects and
an encrypted value which can be used to confirm that the
content of this array and the information it references is identical to that which was present
when the Signature object was created.
| Vocabulary term | Description | Assignment | Type |
|---|---|---|---|
signedInfo |
Information to be signed. | mandatory | SignedInfo or Array of SignedInfo |
sig |
JWS [[RFC7515]] signature value computed using the
JSON canonicalized serialization of the signedInfo
field as payload and header set using
corresponding fields from the Signature object. |
mandatory | string |
alg |
The algorithm used to compute the
signature value. Can be any digital signature or MAC algorithm
specified in either [[RFC7518]] or
[[RFC8037]] corresponding to values of alg allowable
in JWS [[RFC7515]].
These include HS256, HS384, HS512, RS256,
RS384, RS512, ES256, ES384, ES512,
PS256, PS384, or PS512 from [[RFC7518]] and
Ed25519 or Ed448 from [[RFC8037]].
Considered part of the JWS header used for computing the signature value. |
mandatory | string |
jku |
A URI referring to a JWK Set [[RFC7517]]. Considered part of the JWS header used for computing the signature value. | mandatory | anyURI |
kid |
An identifier specifying an element of a JWK Set [[RFC7517]]. Considered part of the JWS header used for computing the signature value. | mandatory | string |
Signature objects are used to verify the integrity of
a specified subset of the information contained in a JSON object.
Generally speaking, Signature objects
follow the structure of XML Signatures [[xmldsig-core1]] to enable flexible
extraction of the subset of information to be signed, that is, the payload.
However, signature algorithms are drawn from JSON Web Algorithms (JWA) [[RFC7518]] and extensions [[RFC8037]]
consistent with their use in JSON Web Signatures (JWS) [[RFC7515]].
The signature value itself is computed by constructing a JWS header from
the information contained in the Signature object and using it to sign
the specified payload.
Each Signature object and the array containing all
signatures MUST be computed (and the array extended) as described below:
Signature
object, with all mandatory fields filled in except for digest fields
and sig values. If a key needs to be specfied,
then appropriate values for both
jku and kid fields should be given.
If values for these fields are not given, then the key will have to be known to the Consumer
by context.
Signature object
MUST then be inserted into the JSON object
to be signed, at the end of the signatures array,
creating a new array if necessary.
This allows SignedInfo sections of the template
to optionally refer to (and therefore protect, if necessary) elements
of the Signature object itself, such as the
definition of the signature algorithm.
security or schema refers to an object
defined in a securityDefinition or schemaDefinition,
the string (and its enclosing quotes)
must be replaced with the object it refers to.
@context object should be retained as is.
reference queries
MUST be applied to the output of the previous step
to extract a result for each SignedInfo object.
Each reference
result may be a JSON fragment or a JSON element,
and MUST be
transformed into JSON Canonical Serialization [[RFC8785]] form.
digest value MUST be computed
using the specified digestAlg
from the output of the previous step
for each SignedInfo object.
These values are then inserted into the corresponding
SignedInfo objects.
SignedInfo objects MUST be serialized in JSON Canonical Serialization
[[RFC8785]] form.
This string will be used as the JWS payload.
alg value as well as the
jku and kid values, if specified,
from the Signature object, using corresponding member names,
and then serialized in JSON Canonical Serialization [[RFC8785]] form.
This string will be used as the JWS header.
sig field of the template Signature object, which is now complete,
with all mandatory elements specified.
Signature object MUST be inserted
into the JSON object, replacing the already inserted
template object.
To verify a signature, the following process MUST be followed:
Signature object and all Signature
objects following it in the array associated with the signatures
member MUST be removed from the JSON object.
If the resulting array is empty it should be removed.
Signature object MUST be reconstructed
by deleting the digest and sig fields
and reinserting it at the end of the signatures array,
(re)creating the signatures array if necessary.
Signature
object being incomplete noted above.
reference queries MUST be performed as described for the signing process.
digest computation MUST be performed as described for the signing process.
sig computation MUST be performed as described for the signing process,
and the validation process appropriate for the signature type performed as specified in
JWS [[RFC7515]], JWA [[RFC7518]] and extensions [[RFC8037]].
Note that in general validation is not as simple as comparing signature values.
The specific validation process for each signature
type needs to be followed as specified,
and may require additional inputs, such as keys.
The reference values in SignedInfo objects
can include previous Signature objects,
allowing signatures to be chained.
Inserting the new Signature object at the end of any existing
signatures array makes it easier to stably select existing signatures using
references such as JSON Pointers.
A parallel effort is being made to define signatures for RDF datasets, called Linked Data Signatures (LDS). This can be applied to JSON-LD files. The current LDS proposal, however, would require the conversion of a JSON-LD file into a sorted set of RDF triples, and so would require RDF processing. The current definition of EJS Signatures requires only JSON processing, so we expect both to be useful in different circumstances.
Thanks to Ege Korkan and Oliver Pfaff for providing detailed feedback on the initial draft.
Temporary ReSpec fix regarding non-listed references: [[RFC6068]], [[RFC3966]], [[html]], [[RFC6750]], [[RFC7519]], [[RFC7797]], [[RFC8392]], [[RFC7516]], [[LDML]], [[SEMVER]], [[RFC7617]], [[RFC7616]]