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.
SignedInfo
A 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 |
Signature
A 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]]