Internet-Draft | JWS/CT | November 2020 |
Jordan, et al. | Expires 24 May 2021 | [Page] |
This document describes a method for extending the scope of the JSON Web Signature (JWS) standard, called JWS/CT. By combining the detached mode of JWS with the JSON Canonicalization Scheme (JCS), JWS/CT enables JSON objects to remain in the JSON format after being signed (aka "Clear Text" signing).¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 24 May 2021.¶
Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
This specification introduces a method for augmenting data expressed in the JSON [RFC8259] notation, with enveloped signatures, similar to the scheme used in the XML Signature [XMLDSIG] standard. For interoperability reasons this specification constrains JSON objects to the I-JSON [RFC7493] subset.¶
To avoid "reinventing the wheel", this specification leverages the JSON Web Signature (JWS) [RFC7515] standard.¶
By building on the detached mode of JWS in combination with the JSON Canonicalizion Scheme (JCS) [RFC8785], JSON objects to be signed can be kept in the JSON format. This arrangement is here referred to as JWS/CT, where CT stands for "Clear Text" signing.¶
The primary motivations for keeping signed JSON objects in the JSON format include simplified documentation, debugging, and logging, as well as for maintaining a consistent message structure.¶
Another target is HTTP-based signature schemes that currently utilize HTTP header values for holding detached signatures. By rather using the method described herein, signed JSON-formatted HTTP requests and responses may be self-contained and thus be serializable. The latter facilitates such data to be¶
without losing the ability to (at any time) verify signatures.¶
Appendix B outlines different ways to handle multiple signatures including counter-signing using JWS/CT.¶
The intended audiences of this document are JSON tool vendors as well as designers of JSON-based cryptographic solutions.¶
Note that this document is not on the IETF standards track. However, a conformant implementation is supposed to adhere to the specified behavior for security and interoperability reasons. This text uses BCP 14 to describe that necessary behavior.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
This section describes the details related to signing and validating signatures based on this specification.¶
The following characteristics are vital to know for prospective JWS/CT implementers and users:¶
The signature creation and signature validation sections
feature samples using the HS256
JOSE algorithm
[RFC7518]
with a 256-bit key having the following value here expressed as hexadecimal bytes:¶
7f dd 85 1a 3b 9d 2d af c5 f0 d0 00 30 e2 2b 93 43 90 0c d4 2e de 49 48 56 8a 4a 2e e6 55 29 1a¶
The following sub-sections describe how JSON objects can be signed according to the JWS/CT specification.¶
Create or parse the JSON object to be signed.¶
For illustrating the subsequent operations the following sample object is used:¶
{ "statement": "Hello signed world!", "otherProperties": [2000, true] }¶
Use the result of the previous step as input to the canonicalization process described in JCS [RFC8785].¶
Applied to the sample, the following JSON string should be generated:¶
{"otherProperties":[2000,true],"statement":"Hello signed world!"}¶
After encoding the string above in the UTF-8 [UNICODE] format, the following bytes (here in hexadecimal notation) should be generated:¶
7b 22 6f 74 68 65 72 50 72 6f 70 65 72 74 69 65 73 22 3a 5b 32 30 30 30 2c 74 72 75 65 5d 2c 22 73 74 61 74 65 6d 65 6e 74 22 3a 22 48 65 6c 6c 6f 20 73 69 67 6e 65 64 20 77 6f 72 6c 64 21 22 7d¶
Use the result of the previous step as JWS Payload
to the
signature process described in
https://tools.ietf.org/html/rfc7515#appendix-F of JWS.¶
Note: although it is true that using the "Unencoded Payload" mode of RFC7797
[RFC7797] would eliminate an internal-only,
base64url encoding step, the performance hit should be marginal for most real-world applications.
The current design also makes JWS/CT independent of JWS library support for the
"b64":false
and "crit":["b64"]
JWS header items required by RFC7797. However, this specification does not
in any way prohibit the use RFC7797, it rather leaves it as an implementer option.¶
For the sample, the JWS header is assumed to be:¶
{"alg":"HS256"}¶
The resulting JWS string should then after payload removal and using the key specified in Section 3, read as follows:¶
eyJhbGciOiJIUzI1NiJ9..VHVItCBCb8Q5CI-49imarDtJeSxH2uLU0DhqQP5Zjw4¶
Before a complete signed object can be created, a dedicated top-level property for holding the JWS signature string needs to be defined. The only requirement is that this property MUST NOT clash with any other top-level property name. The JWS string itself MUST be supplied as a JSON string argument ("") to the signature property.¶
For the sample, the property name "signature"
is assumed to be the designated holder of the JWS string.
Equipped with a signature property, the JWS string from the previous
section, and the original JSON sample, the process above should result
in the following, now signed JSON object (with line breaks in the "signature" property
for display purposes only):¶
{ "statement": "Hello signed world!", "otherProperties": [2000, true], "signature": "eyJhbGciOiJIUzI1NiJ9..VHVItCBCb8Q5CI-49imar DtJeSxH2uLU0DhqQP5Zjw4" }¶
Note: one could equally well apply the signature to the canonicalized version of the JSON object. However, the rearrangement of properties (performed by JCS), may sometimes be considered an issue from a "human" point of view, while computing-wise the order of JSON properties has no impact on the outcome.¶
The following sub-sections describe how JSON objects signed according to the JWS/CT specification can be validated.¶
Parse the JSON object that is anticipated to be signed. If the parsing is unsuccessful, the operation MUST cause a compliant implementation to terminate with an appropriate error.¶
To illustrate the subsequent operations the signed JSON object featured in Section 3.1.4 is used as sample.¶
After successful parsing, retrieve the designated JSON top-level property holding the JWS string. If the property is missing or its argument is not a JSON string (""), the operation MUST cause a compliant implementation to terminate with an appropriate error.¶
For the sample, where the property named "signature"
is assumed to hold the JWS string,
the operation above should return the following string:¶
eyJhbGciOiJIUzI1NiJ9..VHVItCBCb8Q5CI-49imarDtJeSxH2uLU0DhqQP5Zjw4¶
Since the signature is calculated over the actual JSON object data, the designated signature property and its argument MUST be removed from the signed JSON object.¶
If applied to the sample the resulting JSON object should read as follows:¶
{ "statement": "Hello signed world!", "otherProperties": [2000, true] }¶
Note: JSON tools usually by default remove whitespace. In addition, the original ordering of properties may not always be honored. However, none of this has (due to the canonicalization performed by JCS), any impact on the result.¶
Use the result of the previous step as input to the canonicalization process described in JCS [RFC8785].¶
If applied to the sample the result of the process above should read as follows:¶
{"otherProperties":[2000,true],"statement":"Hello signed world!"}¶
After encoding the string above in the UTF-8 [UNICODE] format, the following bytes (here in hexadecimal notation) should be generated:¶
7b 22 6f 74 68 65 72 50 72 6f 70 65 72 74 69 65 73 22 3a 5b 32 30 30 30 2c 74 72 75 65 5d 2c 22 73 74 61 74 65 6d 65 6e 74 22 3a 22 48 65 6c 6c 6f 20 73 69 67 6e 65 64 20 77 6f 72 6c 64 21 22 7d¶
After extracting the detached mode JWS string and canonicalizing the JSON object
(to retrieve the JWS Payload
),
the JWS string MUST be restored as described in
https://tools.ietf.org/html/rfc7515#appendix-F of JWS
[RFC7515].
The actual JWS validation procedure is not specified
here because it is covered by [RFC7515]
and also depends on application-specific policies like:¶
If the validation process for some reason fails, the operation MUST cause a compliant implementation to terminate with an appropriate error.¶
For the sample, validation is straightforward since both the algorithm and the key to use are predefined (see Section 3). The input string to a JWS validator should after the process step above read as follows (with line breaks for display purposes only):¶
eyJhbGciOiJIUzI1NiJ9.eyJvdGhlclByb3BlcnRpZXMiOlsyMDAwLHRydWVdLCJzdGF0 ZW1lbnQiOiJIZWxsbyBzaWduZWQgd29ybGQhIn0.VHVItCBCb8Q5CI-49imarDtJeSxH2 uLU0DhqQP5Zjw4¶
This document has no IANA actions.¶
This specification inherits all the security considerations of JWS [RFC7515] and JCS [RFC8785].¶
In similarity to any other signature specification, it is crucial that signatures are verified before acting on the signed payload.¶
For usage in a wider community, the name of the designated signature property becomes a critical factor that MUST be documented and communicated. However, in a properly designed system, a faulty or missing signature MUST "only" lead to failed operation, and not to a security breach.¶
Due to the simplicity of this specification, there is hardly a need for specific support software. However, JCS which is (at the time of writing), a relatively new design, may be fetched as a separate component for multiple platforms. The following open-source implementations have been verified to be compatible with JCS:¶
The following application notes are not a part of the JWS/CT core; they show how JWS/CT can be used in contexts involving multiple signatures.¶
Consider the following JWS/CT object showing an imaginary real estate business record:¶
{ "gps": [38.89768255588178, -77.03658644893932], "object": {"type": "house", "price": "$635,000"}, "role": "buyer", "name": "John Smith", "timeStamp": "2020-11-08T13:56:08Z", "signature": "<<Buyer JWS Signature>>" }¶
Adding a notary signature on top of this could be performed by embedding the former object as follows:¶
{ "attesting": { "gps": [38.89768255588178, -77.03658644893932], "object": {"type": "house", "price": "$635,000"}, "role": "buyer", "name": "John Smith", "timeStamp": "2020-11-08T13:56:08Z", "signature": "<<Buyer JWS Signature>>" }, "role": "notary", "name": "Carol Lombardi-Jones", "timeStamp": "2020-11-08T13:58:42Z", "signature": "<<Notary JWS Signature>>" }¶
A side effect of this arrangement is that the notary's signature signs not only the notary data, but the buyer's data and signature as well. In most cases this way of adding signatures is advantageous since it maintains the actual order of signing events which also cannot be tampered with without invalidating the outermost signature.¶
Note that all properties above including "signature"
are
application specific.¶
In the case the signing entities are "peers" or are unrelated to each other, counter-signatures like described in Appendix B.1 are not applicable since they presume a specific flow. For supporting independent or asynchronous signers targeting a common document or data object, an imaginable solution is using a scheme where each signer rather calculates a hash of the target document/data and includes the hash with the signer-specific meta data like the following:¶
{ <<Common Document/Data to Sign...>> "signers": [{ "sha256": "<<Hash of Document/Data to Sign>>", <<Signer-related meta data...>> "signature": "<<Signer JWS Signature>>" },{ "sha256": "<<Hash of Document/Data to Sign>>", <<Signer-related meta data...>> "signature": "<<Signer JWS Signature>>" }] }¶
In this case the object to sign would not be limited to JSON; it could for example be a PDF document hosted on a specific URL. Note that the relying party would have to update the structure for each signature received. In some cases a database would probably be more useful for holding individual signatures since a database can cope with any number of signers as well as keeping track of who have actually signed. The latter is crucial for things like international treaties and company board statements.¶
Note that "signers"
, "sha256"
, and "signature"
are
application specific property names.¶
The following sample shows a possible signature object (with line breaks in the signature strings for display purposes only):¶
{ "statement": "Hello signed world!", "otherProperties": [2000, true], "signers": [{ "sha256": "n-i0HIBJKELoTicCK9c5nqJ8cYH0znGRcEbYKoQfm70", "timeStamp": "2020-11-18T07:45:28Z", "name": "Jane Doe", "signature": "eyJhbGciOiJIUzI1NiJ9..57zPdGh88IgI9kECb1u3O Rhjrbe5mZP4wetM2QCoCBM" },{ "sha256": "n-i0HIBJKELoTicCK9c5nqJ8cYH0znGRcEbYKoQfm70", "timeStamp": "2020-11-18T08:03:40Z", "name": "John Doe", "signature": "eyJhbGciOiJFZERTQSJ9..OQLwF9XHtLru0GYMkG-WS dSdqJkQ-jxTqLJXtV8dqruJe1DVsBLI8ok0IZu8jXibZPow5W1hbBmdYJAYCu5hCA" }] }¶
Notes:¶
"sha256"
properties hold base64url-encoded
[RFC4648], SHA256-hashes
[SHS] of the canonicalized
data created in Section 3.1.2.¶
Another possibility supporting multiple and independent signatures is collecting JWS signature strings in a JSON array object according to the following scheme:¶
{ <<Common Document/Data to Sign...>> "<<Signature property>>": ["<<Signature-1>>", "<<Signature-2>>", . "<<Signature-n>>"] }¶
Processing would follow Section 3, with the addition that each signature is dealt with individually.¶
Compared to Appendix B.2, signature arrays imply that possible signer-specific meta-data is supplied as JWS extensions in the associated signature's base64url-encoded header.¶
By combining the sample used in Section 3 with the test vector in Appendix C, a valid signature array object could be as follows (with line breaks in the signature strings for display purposes only):¶
{ "statement": "Hello signed world!", "otherProperties": [2000, true], "signatures": ["eyJhbGciOiJIUzI1NiJ9..VHVItCBCb8Q5CI-49imar DtJeSxH2uLU0DhqQP5Zjw4", "eyJhbGciOiJFZERTQSJ9..WAyfK782CRkJh4hcP-OQ3 qUYpH6xY3vfFhaRSzNgG5Eu4p54SyTX25-HjNRN8qE5hmMovd8tycp6I9uqRofiBg"] }¶
Note that "signatures"
is not a key word, it was only selected
to highlight the fact that there are multiple signatures.¶
This appendix shows how a signed version of the JSON sample object in
Section 3.1.1 would look like
if applying the Ed25519
algorithm described in RFC 8037
[RFC8037] (with line breaks in the "signature" property
for display purposes only):¶
{ "statement": "Hello signed world!", "otherProperties": [2000, true], "signature": "eyJhbGciOiJFZERTQSJ9..WAyfK782CRkJh4hcP-OQ3 qUYpH6xY3vfFhaRSzNgG5Eu4p54SyTX25-HjNRN8qE5hmMovd8tycp6I9uqRofiBg" }¶
The sample above depends on a JWS header holding the algorithm
{"alg":"EdDSA"}
, and the following private key, here expressed in
the JWK [RFC7517] format:¶
{ "kty": "OKP", "crv": "Ed25519", "x": "_kms9bkrbpI1lPLoM2j2gKySS-k89TOuyvgC43dX-Mk", "d": "0flr-6bXs459f9qwAq20Zs3NizTGIEH5_rTDFoumFV4" }¶
People who have contributed directly and indirectly with valuable input to this specification include Vladimir Dzhuvinov, Freddi Gyara, and Filip Skokan.¶