RFC 7515
JSON Web Signature (JWS)
RFC 7515: JSON Web Signature (JWS) ๐
Okay so this is RFC 7515, and it's called JSON Web Signature (JWS) ๐ It comes from the IETF (Internet Engineering Task Force), and it's dated May 2015 โจ
- Authors: M. Jones (Microsoft), J. Bradley (Ping Identity), and N. Sakimura (NRI) ๐ซถ
- Category: Standards Track ๐ฅ It's an Internet Standards Track document, so this is official, real-deal stuff
- ISSN: 2070-1721 ๐ธ
- Obsoletes / Updates: the title block doesn't list any RFCs that this one obsoletes or updates ๐
Abstract ๐ฆ
JWS is how you wrap up content with digital signatures or Message Authentication Codes (MACs) using JSON-based data structures ๐ The actual cryptographic algorithms and identifiers you'd use with it live in the separate JSON Web Algorithms (JWA) spec and an IANA registry that spec defines. Encryption stuff is handled in the separate JSON Web Encryption (JWE) spec ๐ง
Status of This Memo ๐
This is an Internet Standards Track document โจ
It's a product of the Internet Engineering Task Force (IETF), and it represents the consensus of the IETF community ๐ซถ It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check Section 2 of RFC 5741 ๐
Info about the current status of this document, any errata, and how to send feedback is at http://www.rfc-editor.org/info/rfc7515 ๐
Copyright Notice ๐
Copyright (c) 2015 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 (http://trustee.ietf.org/license-info) as they stand on the date this document was published. Please read these carefully, because they spell out your rights and restrictions for this document ๐ Any Code Components pulled out of this document must include the Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they're provided without warranty as described in the Simplified BSD License ๐
Table of Contents ๐
1. Introduction ....................................................4
1.1. Notational Conventions .....................................4
2. Terminology .....................................................5
3. JSON Web Signature (JWS) Overview ...............................7
3.1. JWS Compact Serialization Overview .........................7
3.2. JWS JSON Serialization Overview ............................8
3.3. Example JWS ................................................8
4. JOSE Header .....................................................9
4.1. Registered Header Parameter Names .........................10
4.1.1. "alg" (Algorithm) Header Parameter .................10
4.1.2. "jku" (JWK Set URL) Header Parameter ...............10
4.1.3. "jwk" (JSON Web Key) Header Parameter ..............11
4.1.4. "kid" (Key ID) Header Parameter ....................11
4.1.5. "x5u" (X.509 URL) Header Parameter .................11
4.1.6. "x5c" (X.509 Certificate Chain) Header Parameter ...11
4.1.7. "x5t" (X.509 Certificate SHA-1 Thumbprint)
Header Parameter ...................................12
4.1.8. "x5t#S256" (X.509 Certificate SHA-256
Thumbprint) Header Parameter .......................12
4.1.9. "typ" (Type) Header Parameter ......................12
4.1.10. "cty" (Content Type) Header Parameter .............13
4.1.11. "crit" (Critical) Header Parameter ................14
4.2. Public Header Parameter Names .............................14
4.3. Private Header Parameter Names ............................14
5. Producing and Consuming JWSs ...................................15
5.1. Message Signature or MAC Computation ......................15
5.2. Message Signature or MAC Validation .......................16
5.3. String Comparison Rules ...................................17
6. Key Identification .............................................18
7. Serializations .................................................19
7.1. JWS Compact Serialization .................................19
7.2. JWS JSON Serialization ....................................19
7.2.1. General JWS JSON Serialization Syntax ..............20
7.2.2. Flattened JWS JSON Serialization Syntax ............21
8. TLS Requirements ...............................................22
9. IANA Considerations ............................................22
9.1. JSON Web Signature and Encryption Header
Parameters Registry .......................................23
9.1.1. Registration Template ..............................23
9.1.2. Initial Registry Contents ..........................24
9.2. Media Type Registration ...................................26
9.2.1. Registry Contents ..................................26
10. Security Considerations .......................................27
10.1. Key Entropy and Random Values ............................27
10.2. Key Protection ...........................................28
10.3. Key Origin Authentication ................................28
10.4. Cryptographic Agility ....................................28
10.5. Differences between Digital Signatures and MACs ..........28
10.6. Algorithm Validation .....................................29
10.7. Algorithm Protection .....................................29
10.8. Chosen Plaintext Attacks .................................30
10.9. Timing Attacks ...........................................30
10.10. Replay Protection .......................................30
10.11. SHA-1 Certificate Thumbprints ...........................30
10.12. JSON Security Considerations ............................31
10.13. Unicode Comparison Security Considerations ..............31
11. References ....................................................32
11.1. Normative References .....................................32
11.2. Informative References ...................................34
Appendix A. JWS Examples .........................................36
A.1. Example JWS Using HMAC SHA-256 ............................36
A.1.1. Encoding ..............................................36
A.1.2. Validating ............................................38
A.2. Example JWS Using RSASSA-PKCS1-v1_5 SHA-256 ...............38
A.2.1. Encoding ..............................................38
A.2.2. Validating ............................................42
A.3. Example JWS Using ECDSA P-256 SHA-256 .....................42
A.3.1. Encoding ..............................................42
A.3.2. Validating ............................................44
A.4. Example JWS Using ECDSA P-521 SHA-512 .....................45
A.4.1. Encoding ..............................................45
A.4.2. Validating ............................................47
A.5. Example Unsecured JWS .....................................47
A.6. Example JWS Using General JWS JSON Serialization ..........48
A.6.1. JWS Per-Signature Protected Headers ...................48
A.6.2. JWS Per-Signature Unprotected Headers .................49
A.6.3. Complete JOSE Header Values ...........................49
A.6.4. Complete JWS JSON Serialization Representation ........50
A.7. Example JWS Using Flattened JWS JSON Serialization ........51
Appendix B. "x5c" (X.509 Certificate Chain) Example ..............52
Appendix C. Notes on Implementing base64url Encoding without
Padding ..............................................54
Appendix D. Notes on Key Selection ...............................55
Appendix E. Negative Test Case for "crit" Header Parameter .......57
Appendix F. Detached Content .....................................57
Acknowledgements ..................................................58
Authors' Addresses ................................................58
1. Introduction โจ
JWS is how you represent content secured with digital signatures or Message Authentication Codes (MACs) using JSON-based [RFC7159] data structures ๐ง The JWS cryptographic mechanisms give you integrity protection for an arbitrary sequence of octets. For the difference between digital signatures and MACs, see Section 10.5 ๐
There are two closely related serializations for JWSs ๐ The JWS Compact Serialization is a compact, URL-safe representation made for space-constrained places like HTTP Authorization headers and URI query parameters ๐ฆ The JWS JSON Serialization represents JWSs as JSON objects and lets you apply multiple signatures and/or MACs to the same content ๐ซถ Both of them share the same cryptographic underpinnings ๐
The cryptographic algorithms and identifiers for this spec are described in the separate JSON Web Algorithms (JWA) [JWA] spec and an IANA registry that spec defines. Related encryption capabilities are described in the separate JSON Web Encryption (JWE) [JWE] spec ๐
Names defined by this spec are short on purpose, because a core goal is for the resulting representations to be compact ๐
1.1. Notational Conventions ๐ง
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 "Key words for use in RFCs to Indicate Requirement Levels" [RFC2119]. The interpretation should only be applied when the terms appear in all capital letters ๐
BASE64URL(OCTETS) denotes the base64url encoding of OCTETS, per Section 2 ๐ธ
UTF8(STRING) denotes the octets of the UTF-8 [RFC3629] representation of STRING, where STRING is a sequence of zero or more Unicode [UNICODE] characters ๐
ASCII(STRING) denotes the octets of the ASCII [RFC20] representation of STRING, where STRING is a sequence of zero or more ASCII characters ๐
The concatenation of two values A and B is denoted as A || B โจ
Okay so I need to flag something real quick, bestie. The paragraphs below are the actual RFC 7515 text, and I have to rewrite them in full with every single MUST, SHOULD, OPTIONAL and every reference and section number kept exactly. So let's get into it! ๐
2. Terminology โจ
Okay so this section is where the spec defines its vocab, and we need these words to be iconic ๐ Every term below is defined by this specification:
JSON Web Signature (JWS) ๐ฆ
A data structure representing a digitally signed or MACed message. Think of it as the whole package. ๐
JOSE Header ๐ธ
A JSON object containing the parameters describing the cryptographic operations and parameters employed. The JOSE (JSON Object Signing and Encryption) Header is comprised of a set of Header Parameters. It's giving organized vibes fr ๐๏ธ
JWS Payload ๐
The sequence of octets to be secured, a.k.a. the message. The payload can contain an arbitrary sequence of octets. Literally anything can go in here ๐ซถ
JWS Signature โ๏ธ
Digital signature or MAC over the JWS Protected Header and the JWS Payload. The signature is the receipt that proves the stuff got locked in ๐
Header Parameter ๐ง
A name/value pair that is a member of the JOSE Header. Cute and simple, no notes ๐
JWS Protected Header ๐ก๏ธ
A JSON object that contains the Header Parameters that are integrity protected by the JWS Signature digital signature or MAC operation. For the JWS Compact Serialization, this comprises the entire JOSE Header. For the JWS JSON Serialization, this is one component of the JOSE Header. Main character energy ๐
JWS Unprotected Header ๐
A JSON object that contains the Header Parameters that are not integrity protected. This can only be present when using the JWS JSON Serialization. So the unprotected stuff is just there, no lock on it ๐
Base64url Encoding ๐
Base64 encoding using the URL- and filename-safe character set defined in Section 5 of RFC 4648 [RFC4648], with all trailing '=' characters omitted (as permitted by Section 3.2) and without the inclusion of any line breaks, whitespace, or other additional characters. Note that the base64url encoding of the empty octet sequence is the empty string. (See Appendix C for notes on implementing base64url encoding without padding.) Ngl this one is a whole vibe ๐ฆ
JWS Signing Input ๐ฅ
The input to the digital signature or MAC computation. Its value is:
ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload))
JWS Compact Serialization ๐
A representation of the JWS as a compact, URL-safe string. Short and sweet ๐ฌ
JWS JSON Serialization ๐ฆ
A representation of the JWS as a JSON object. Unlike the JWS Compact Serialization, the JWS JSON Serialization enables multiple digital signatures and/or MACs to be applied to the same content. This representation is neither optimized for compactness nor URL-safe. It's the extra one, and that's okay ๐
Unsecured JWS ๐ซฅ
A JWS that provides no integrity protection. Unsecured JWSs use the "alg" value "none". No lock, just vibes โจ
Collision-Resistant Name ๐ก๏ธ
A name in a namespace that enables names to be allocated in a manner such that they are highly unlikely to collide with other names. Examples of collision-resistant namespaces include: Domain Names, Object Identifiers (OIDs) as defined in the ITU-T X.660 and X.670 Recommendation series, and Universally Unique IDentifiers (UUIDs) [RFC4122]. When using an administratively delegated namespace, the definer of a name needs to take reasonable precautions to ensure they are in control of the portion of the namespace they use to define the name. Be careful with your names, babe ๐
StringOrURI ๐
A JSON string value, with the additional requirement that while arbitrary string values MAY be used, any value containing a ":" character MUST be a URI [RFC3986]. StringOrURI values are compared as case-sensitive strings with no transformations or canonicalizations applied. Strict but fair, no cap ๐
The terms "JSON Web Encryption (JWE)", "JWE Compact Serialization", and "JWE JSON Serialization" are defined by the JWE specification [JWE].
The terms "Digital Signature" and "Message Authentication Code (MAC)" are defined by the "Internet Security Glossary, Version 2" [RFC4949]. ๐
3. JSON Web Signature (JWS) Overview ๐
JWS represents digitally signed or MACed content using JSON data structures and base64url encoding. These JSON data structures MAY contain whitespace and/or line breaks before or after any JSON values or structural characters, in accordance with Section 2 of RFC 7159 [RFC7159]. A JWS represents these logical values (each of which is defined in Section 2):
- JOSE Header
- JWS Payload
- JWS Signature
For a JWS, the JOSE Header members are the union of the members of these values (each of which is defined in Section 2):
- JWS Protected Header
- JWS Unprotected Header
This document defines two serializations for JWSs: a compact, URL-safe serialization called the JWS Compact Serialization and a JSON serialization called the JWS JSON Serialization. In both serializations, the JWS Protected Header, JWS Payload, and JWS Signature are base64url encoded, since JSON lacks a way to directly represent arbitrary octet sequences. Two flavours, one base64url vibe ๐ธ
3.1. JWS Compact Serialization Overview ๐ฆ
In the JWS Compact Serialization, no JWS Unprotected Header is used. In this case, the JOSE Header and the JWS Protected Header are the same.
In the JWS Compact Serialization, a JWS is represented as the concatenation:
BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
See Section 7.1 for more information about the JWS Compact Serialization. ๐
3.2. JWS JSON Serialization Overview ๐
In the JWS JSON Serialization, one or both of the JWS Protected Header and JWS Unprotected Header MUST be present. In this case, the members of the JOSE Header are the union of the members of the JWS Protected Header and the JWS Unprotected Header values that are present.
In the JWS JSON Serialization, a JWS is represented as a JSON object containing some or all of these four members:
- "protected", with the value BASE64URL(UTF8(JWS Protected Header))
- "header", with the value JWS Unprotected Header
- "payload", with the value BASE64URL(JWS Payload)
- "signature", with the value BASE64URL(JWS Signature)
The three base64url-encoded result strings and the JWS Unprotected Header value are represented as members within a JSON object. The inclusion of some of these values is OPTIONAL. The JWS JSON Serialization can also represent multiple signature and/or MAC values, rather than just one. See Section 7.2 for more information about the JWS JSON Serialization. ๐ซถ
3.3. Example JWS ๐ง
This section provides an example of a JWS. Its computation is described in more detail in Appendix A.1, including specifying the exact octet sequences representing the JSON values used and the key value used.
The following example JWS Protected Header declares that the encoded object is a JSON Web Token [JWT] and the JWS Protected Header and the JWS Payload are secured using the HMAC SHA-256 [RFC2104] [SHS] algorithm:
{"typ":"JWT",
"alg":"HS256"}
Encoding this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) gives this value:
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
The UTF-8 representation of the following JSON object is used as the JWS Payload. (Note that the payload can be any content and need not be a representation of a JSON object.)
{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true}
Encoding this JWS Payload as BASE64URL(JWS Payload) gives this value (with line breaks for display purposes only):
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
Computing the HMAC of the JWS Signing Input ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload)) with the HMAC SHA-256 algorithm using the key specified in Appendix A.1 and base64url-encoding the result yields this BASE64URL(JWS Signature) value:
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Concatenating these values in the order Header.Payload.Signature with period ('.') characters between the parts yields this complete JWS representation using the JWS Compact Serialization (with line breaks for display purposes only):
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
See Appendix A for additional examples, including examples using the JWS JSON Serialization in Sections A.6 and A.7. Go check those out, they're so good ๐
4. JOSE Header ๐
For a JWS, the members of the JSON object(s) representing the JOSE Header describe the digital signature or MAC applied to the JWS Protected Header and the JWS Payload and optionally additional properties of the JWS. The Header Parameter names within the JOSE Header MUST be unique; JWS parsers MUST either reject JWSs with duplicate Header Parameter names or use a JSON parser that returns only the lexically last duplicate member name, as specified in Section 15.12 ("The JSON Object") of ECMAScript 5.1 [ECMAScript]. No doubles allowed, bestie ๐
Implementations are required to understand the specific Header Parameters defined by this specification that are designated as "MUST be understood" and process them in the manner defined in this specification. All other Header Parameters defined by this specification that are not so designated MUST be ignored when not understood. Unless listed as a critical Header Parameter, per Section 4.1.11, all Header Parameters not defined by this specification MUST be ignored when not understood. Unknown stuff gets ignored, iykyk ๐
There are three classes of Header Parameter names: Registered Header Parameter names, Public Header Parameter names, and Private Header Parameter names. Three squad members, all different ๐ซถ
4.1. Registered Header Parameter Names ๐
The following Header Parameter names for use in JWSs are registered in the IANA "JSON Web Signature and Encryption Header Parameters" registry established by Section 9.1, with meanings as defined in the subsections below.
As indicated by the common registry, JWSs and JWEs share a common Header Parameter space; when a parameter is used by both specifications, its usage must be compatible between the specifications. Shared space, shared rules, lowkey important ๐ฆ
4.1.1. "alg" (Algorithm) Header Parameter ๐
The "alg" (algorithm) Header Parameter identifies the cryptographic algorithm used to secure the JWS. The JWS Signature value is not valid if the "alg" value does not represent a supported algorithm or if there is not a key for use with that algorithm associated with the party that digitally signed or MACed the content. "alg" values should either be registered in the IANA "JSON Web Signature and Encryption Algorithms" registry established by [JWA] or be a value that contains a Collision-Resistant Name. The "alg" value is a case-sensitive ASCII string containing a StringOrURI value. This Header Parameter MUST be present and MUST be understood and processed by implementations. This one is the main character, no notes ๐
A list of defined "alg" values for this use can be found in the IANA "JSON Web Signature and Encryption Algorithms" registry established by [JWA]; the initial contents of this registry are the values defined in Section 3.1 of [JWA]. โจ
4.1.2. "jku" (JWK Set URL) Header Parameter ๐
The "jku" (JWK Set URL) Header Parameter is a URI [RFC3986] that refers to a resource for a set of JSON-encoded public keys, one of which corresponds to the key used to digitally sign the JWS. The keys MUST be encoded as a JWK Set [JWK]. The protocol used to acquire the resource MUST provide integrity protection; an HTTP GET request to retrieve the JWK Set MUST use Transport Layer Security (TLS) [RFC2818] [RFC5246]; and the identity of the server MUST be validated, as per Section 6 of RFC 6125 [RFC6125]. Also, see Section 8 on TLS requirements. Use of this Header Parameter is OPTIONAL.
Okay this one is serious, bestie. Getting the key from a URL means the connection has to be locked down with TLS and the server's identity has to be checked. Don't skip it ๐๐
4.1.3. "jwk" (JSON Web Key) Header Parameter ๐
Okay bestie, the "jwk" Header Parameter is giving public key energy ๐. It's the public key that matches the key used to digitally sign the JWS, and it's represented as a JSON Web Key [JWK]. Using it is OPTIONAL โจ.
4.1.4. "kid" (Key ID) Header Parameter ๐ฆ
The "kid" (key ID) Header Parameter is a hint that tells you which key secured the JWS. It's how originators can explicitly signal a key change to recipients, which is so helpful ๐ซถ. The structure of the "kid" value is unspecified, but its value MUST be a case-sensitive string ๐
. Using this Header Parameter is OPTIONAL.
When you use it with a JWK, the "kid" value gets matched against a JWK "kid" parameter value. Iykyk ๐ธ.
4.1.5. "x5u" (X.509 URL) Header Parameter ๐
The "x5u" (X.509 URL) Header Parameter is a URI [RFC3986] pointing to a resource with the X.509 public key certificate or certificate chain [RFC5280] that matches the key used to digitally sign the JWS. Okay, now listen closely, because this one has rules ๐ญ. The identified resource MUST provide a representation of the certificate or certificate chain that conforms to RFC 5280 [RFC5280] in PEM-encoded form, with each certificate delimited as specified in Section 6.1 of RFC 4945 [RFC4945]. The certificate containing the public key for the key used to digitally sign the JWS MUST be the first certificate. This MAY be followed by additional certificates, with each subsequent certificate being the one used to certify the previous one.
The protocol used to acquire the resource MUST provide integrity protection. An HTTP GET request to retrieve the certificate MUST use TLS [RFC2818] [RFC5246], and the identity of the server MUST be validated, as per Section 6 of RFC 6125 [RFC6125]. Also, see Section 8 on TLS requirements ๐ฅ. Using this Header Parameter is OPTIONAL.
4.1.6. "x5c" (X.509 Certificate Chain) Header Parameter ๐
The "x5c" (X.509 certificate chain) Header Parameter carries the X.509 public key certificate or certificate chain [RFC5280] for the key used to digitally sign the JWS. It's represented as a JSON array of certificate value strings. Each string in the array is a base64-encoded (Section 4 of [RFC4648] -- not base64url-encoded) DER [ITU.X690.2008] PKIX certificate value ๐ง. The certificate containing the public key for the key used to digitally sign the JWS MUST be the first certificate. This MAY be followed by additional certificates, with each subsequent certificate being the one used to certify the previous one.
The recipient MUST validate the certificate chain according to RFC 5280 [RFC5280], and it has to consider the certificate or certificate chain to be invalid if any validation failure occurs. Harsh but fair ๐. Using this Header Parameter is OPTIONAL.
See Appendix B for an example "x5c" value. ๐
4.1.7. "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter ๐
The "x5t" (X.509 certificate SHA-1 thumbprint) Header Parameter is a base64url-encoded SHA-1 thumbprint (a.k.a. digest) of the DER encoding of the X.509 certificate [RFC5280] for the key used to digitally sign the JWS. Fun fact: certificate thumbprints are also sometimes called certificate fingerprints ๐. Using this Header Parameter is OPTIONAL.
4.1.8. "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Header Parameter ๐
The "x5t#S256" (X.509 certificate SHA-256 thumbprint) Header Parameter is a base64url-encoded SHA-256 thumbprint (a.k.a. digest) of the DER encoding of the X.509 certificate [RFC5280] for the key used to digitally sign the JWS. Same vibe as the SHA-1 one, just with the upgraded hash ๐. Certificate thumbprints are also sometimes known as certificate fingerprints. Using this Header Parameter is OPTIONAL.
4.1.9. "typ" (Type) Header Parameter ๐
The "typ" (type) Header Parameter is how JWS applications declare the media type [IANA.MediaTypes] of this complete JWS ๐ธ. It's meant for when more than one kind of object could show up in an application data structure that can hold a JWS, so the app can tell the different kinds apart. Usually apps don't bother with it when they already know what kind of object they've got. This parameter is ignored by JWS implementations, so any processing of it is done by the JWS application itself. Using this Header Parameter is OPTIONAL.
Per RFC 2045 [RFC2045], all media type values, subtype values, and parameter names are case insensitive. Parameter values, though, are case sensitive unless the specific parameter says otherwise ๐ฆ.
To keep messages compact in common situations, it is RECOMMENDED that producers omit the "application/" prefix of a media type value in a "typ" Header Parameter when no other / appears in the media type value. A recipient using the media type value MUST treat it as if "application/" were prepended to any "typ" value not containing a /. For instance, a "typ" value of "example" SHOULD be used to represent the application/example media type, whereas the media type application/example;part="1/2" cannot be shortened to example;part="1/2". Not the vibe ๐ญ.
The "typ" value "JOSE" can be used by applications to indicate that this object is a JWS or JWE using the JWS Compact Serialization or the JWE Compact Serialization. The "typ" value "JOSE+JSON" can be used by applications to indicate that this object is a JWS or JWE using the JWS JSON Serialization or the JWE JSON Serialization. Other type values can also be used by applications, so you've got options โจ.
4.1.10. "cty" (Content Type) Header Parameter ๐ง
The "cty" (content type) Header Parameter is used by JWS applications to declare the media type [IANA.MediaTypes] of the secured content, which is the payload ๐. It's meant for when more than one kind of object could be in the JWS Payload, so the application can sort out which kind it's dealing with. Apps typically skip it when the kind of object is already known. This parameter is ignored by JWS implementations, and any processing of it is done by the JWS application. Using this Header Parameter is OPTIONAL.
Per RFC 2045 [RFC2045], all media type values, subtype values, and parameter names are case insensitive. However, parameter values are case sensitive unless otherwise specified for the specific parameter.
To keep messages compact in common situations, it is RECOMMENDED that producers omit the "application/" prefix of a media type value in a "cty" Header Parameter when no other / appears in the media type value. A recipient using the media type value MUST treat it as if "application/" were prepended to any "cty" value not containing a /. For instance, a "cty" value of "example" SHOULD be used to represent the application/example media type, whereas the media type application/example;part="1/2" cannot be shortened to example;part="1/2".
4.1.11. "crit" (Critical) Header Parameter ๐
The "crit" (critical) Header Parameter is the "you MUST understand this or it's game over" flag ๐จ. It says that extensions to this specification and/or [JWA] are being used, and those extensions MUST be understood and processed. Its value is an array listing the Header Parameter names in the JOSE Header that use those extensions. If any of the listed extension Header Parameters are not understood and supported by the recipient, then the JWS is invalid ๐.
Producers MUST NOT include Header Parameter names defined by this specification or [JWA] for use with JWS, duplicate names, or names that do not occur as Header Parameter names within the JOSE Header in the "crit" list. Producers MUST NOT use the empty list "[]" as the "crit" value. Recipients MAY consider the JWS to be invalid if the critical list contains any Header Parameter names defined by this specification or [JWA] for use with JWS, or if any other constraints on its use are violated. When used, this Header Parameter MUST be integrity protected, so it MUST occur only within the JWS Protected Header. Using this Header Parameter is OPTIONAL. This Header Parameter MUST be understood and processed by implementations. Very strict, very iconic ๐
.
An example use, along with a hypothetical "exp" (expiration time) field, looks like this:
{"alg":"ES256",
"crit":["exp"],
"exp":1363284000
}
4.2. Public Header Parameter Names โจ
Additional Header Parameter names can be defined by those using JWSs ๐. To prevent collisions, though, any new Header Parameter name should either be registered in the IANA "JSON Web Signature and Encryption Header Parameters" registry established by Section 9.1, or be a Public Name (a value that contains a Collision-Resistant Name). In each case, the definer of the name or value needs to take reasonable precautions to make sure they are in control of the part of the namespace they use to define the Header Parameter name. Namespace responsibility, bestie ๐ซถ.
New Header Parameters should be introduced sparingly, because they can result in non-interoperable JWSs. Don't be that person ๐.
4.3. Private Header Parameter Names ๐ฆ
A producer and consumer of a JWS may agree to use Header Parameter names that are Private Names (names that are not Registered Header Parameter names (Section 4.1)) or Public Header Parameter names (Section 4.2). Unlike Public Header Parameter names, Private Header Parameter names are subject to collision, so they should be used with caution โ ๏ธ. Mutual agreement only, no cap.
5. Producing and Consuming JWSs ๐
5.1. Message Signature or MAC Computation ๐ฅ
Okay, here's how you actually make a JWS, step by step. The order of the steps doesn't matter when there are no dependencies between the inputs and outputs of the steps ๐ง.
- Create the content to be used as the JWS Payload.
- Compute the encoded payload value
BASE64URL(JWS Payload). - Create the JSON object(s) containing the desired set of Header Parameters, which together make up the JOSE Header (the JWS Protected Header and/or the JWS Unprotected Header).
- Compute the encoded header value
BASE64URL(UTF8(JWS Protected Header)). If the JWS Protected Header is not present (which can only happen when using the JWS JSON Serialization and no"protected"member is present), let this value be the empty string. - Compute the JWS Signature in the manner defined for the particular algorithm being used, over the JWS Signing Input
ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload)). The"alg"(algorithm) Header Parameter MUST be present in the JOSE Header, with the algorithm value accurately representing the algorithm used to construct the JWS Signature. Non-negotiable ๐ . - Compute the encoded signature value
BASE64URL(JWS Signature). - If the JWS JSON Serialization is being used, repeat this process (steps 3-6) for each digital signature or MAC operation being performed. Multi-signature glow-up ๐ธ.
- Create the desired serialized output. The JWS Compact Serialization of this result is
BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) || '.' || BASE64URL(JWS Signature). The JWS JSON Serialization is described in Section 7.2. โจ
5.2. Message Signature or MAC Validation โจ
okay so validating a JWS is a whole checklist, bestie ๐ the steps don't have to happen in a specific order unless one step depends on another step's output. but if ANY step fails, the signature or MAC just can't be validated ๐ญ
when there are multiple JWS Signature values, it's the application's call which of them need to validate for the JWS to get accepted ๐ sometimes ALL of them have to pass or the JWS is invalid, and other times only one specific signature needs to pass. but no matter what, at least one JWS Signature value MUST successfully validate, or the JWS MUST be considered invalid. no exceptions, periodt ๐ฅ
- Parse the JWS representation to pull out the serialized values for the parts of the JWS. with the JWS Compact Serialization, those parts are the base64url-encoded JWS Protected Header, JWS Payload, and JWS Signature. with the JWS JSON Serialization, they also include the unencoded JWS Unprotected Header value. in the Compact Serialization, the three base64url-encoded values show up in that order, each separated from the next by a single period (
.) character, so you get exactly two period delimiters ๐ฆ the JWS JSON Serialization is covered in Section 7.2. - Base64url-decode the encoded JWS Protected Header, and remember the rule: no line breaks, whitespace, or other extra characters allowed ๐ธ
- Check that the resulting octets are a UTF-8-encoded, completely valid JSON object following RFC 7159 [RFC7159]. that object becomes the JWS Protected Header ๐
- If you're using the JWS Compact Serialization, the JOSE Header is just the JWS Protected Header. otherwise, with the JWS JSON Serialization, the JOSE Header is the union of the members of the matching JWS Protected Header and JWS Unprotected Header, and both have to be completely valid JSON objects. during this step, make sure the JOSE Header has no duplicate Header Parameter names ๐ with the JWS JSON Serialization, the same Header Parameter name also MUST NOT show up in different JSON object values that together make up the JOSE Header. not me getting a duplicate name slipping through ๐
- Make sure the implementation understands and can process every field it's required to support. that could be required by this specification, by the algorithm being used, or by the "crit" Header Parameter value. and the values of those parameters need to be understood and supported too ๐ง
- Base64url-decode the encoded JWS Payload, same rule: no line breaks, whitespace, or other additional characters ๐
- Base64url-decode the encoded JWS Signature, same rule: no line breaks, whitespace, or other additional characters โจ
- Validate the JWS Signature against the JWS Signing Input, which is built like this, in the manner defined for the algorithm being used. the "alg" (algorithm) Header Parameter MUST accurately represent that algorithm, and it MUST be present ๐ฅ see Section 10.6 for the security considerations on algorithm validation. record whether the validation succeeded or not.
ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload))
- If you're using the JWS JSON Serialization, repeat this whole process (steps 4-8) for each digital signature or MAC value in the representation ๐
- If none of the validations in step 9 succeeded, then the JWS MUST be considered invalid. otherwise, in the JWS JSON Serialization case, return a result to the application saying which validations passed and which failed. in the JWS Compact Serialization case, the result can just say whether or not the JWS was successfully validated ๐
one last thing, and it's a big one ๐ it's the application's decision which algorithms are allowed in a given context. so even if a JWS validates successfully, if the algorithm(s) used aren't acceptable to the application, it SHOULD consider the JWS to be invalid. main character energy for the app, honestly ๐
5.3. String Comparison Rules ๐ฆ
processing a JWS means comparing known strings against members and values in JSON objects, constantly ๐ญ for example, when checking what the algorithm is, the Unicode string "alg" gets compared against the member names in the JOSE Header to find a matching Header Parameter name. then that same process checks whether the value of the "alg" Header Parameter is a supported algorithm.
the JSON rules for member name comparison are described in Section 8.3 of RFC 7159 [RFC7159]. since the only comparisons happening are equality and inequality, the same rules work for comparing both member names and member values against known strings ๐
these comparison rules MUST be used for all JSON string comparisons, except when the definition of a member explicitly says a different comparison rule applies to that member value. only the "typ" and "cty" member values defined in this specification skip these rules ๐
some applications might include case-insensitive info inside a case-sensitive value, like putting a DNS name inside a "kid" (key ID) value ๐ in those situations, the application may need to define a convention for the canonical case to use for the case-insensitive parts, like lowercasing them, if more than one party might need to produce the same value so they can be compared. (however, if every other party just takes whatever value the producer emitted, verbatim, without comparing it to a value they produced separately, then the producer's case doesn't matter ๐ธ)
also check out the JSON security considerations in Section 10.12 and the Unicode security considerations in Section 10.13 ๐ฅ
6. Key Identification ๐
the recipient of a JWS has to figure out which key was used for the digital signature or MAC operation ๐ซถ the key can be identified with the Header Parameter methods from Section 4.1, or with methods that are outside this specification's scope. specifically, the Header Parameters "jku", "jwk", "kid", "x5u", "x5c", "x5t", and "x5t#S256" can be used to identify the key that was used. these Header Parameters MUST be integrity protected if the info they convey is going to be used in a trust decision. however, if the only info used in the trust decision is a key, these parameters don't need to be integrity protected, since changing them in a way that makes a different key get used will make validation fail anyway ๐ง
the producer SHOULD include enough information in the Header Parameters to identify the key used, unless the application uses another means or convention to figure out the key ๐ validation of the signature or MAC fails when the algorithm used requires a key (which is true of all algorithms except for "none") and the key used can't be determined. so no key, no validation, bestie ๐
the way shared symmetric keys get exchanged is outside the scope of this specification ๐
also, see Appendix D for notes on possible key selection algorithms ๐ฆ
7. Serializations ๐
JWSs use one of two serializations: the JWS Compact Serialization or the JWS JSON Serialization โจ applications using this spec need to say which serialization, and which serialization features, they use. for instance, an app might say only the JWS JSON Serialization is used, or that only JWS JSON Serialization support for a single signature or MAC value is used, or that support for multiple signatures and/or MAC values is used. JWS implementations only need to implement the features their target applications need ๐
7.1. JWS Compact Serialization ๐
the JWS Compact Serialization represents digitally signed or MACed content as a compact, URL-safe string ๐ that string looks like this:
BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
only one signature/MAC is supported by the JWS Compact Serialization, and it has no syntax at all to represent a JWS Unprotected Header value ๐ lowkey limited, but it's compact and that's the whole vibe โจ
7.2. JWS JSON Serialization ๐
the JWS JSON Serialization represents digitally signed or MACed content as a JSON object ๐ this representation is neither optimized for compactness nor URL-safe, so it's giving full-size energy ๐ญ
two closely related syntaxes are defined for the JWS JSON Serialization. the first is a fully general syntax, where content can be secured with more than one digital signature and/or MAC operation ๐ธ the second is a flattened syntax, which is optimized for the single digital signature or MAC case ๐ง
7.2.1. General JWS JSON Serialization Syntax
Okay so the fully general JWS JSON Serialization syntax has a few members that live in the top-level JSON object ๐ Here they are, bestie:
payload ๐ The payload member MUST be present and contain the value BASE64URL(JWS Payload).
signatures ๐ธ The signatures member value MUST be an array of JSON objects. Each object is one signature or MAC over the JWS Payload and the JWS Protected Header. Cute, right? ๐
Inside the objects in that signatures array, there are three more members:
protected ๐ The protected member MUST be present and contain the value BASE64URL(UTF8(JWS Protected Header)) when the JWS Protected Header value is non-empty. Otherwise it MUST be absent. These Header Parameter values are integrity protected, so they're locked down ๐ซถ
header ๐ฆ The header member MUST be present and contain the value JWS Unprotected Header when the JWS Unprotected Header value is non-empty. Otherwise it MUST be absent. This one is an unencoded JSON object, NOT a string, so it sits right there as real JSON. These Header Parameter values are not integrity protected, so keep that in mind ๐
signature โจ The signature member MUST be present and contain the value BASE64URL(JWS Signature).
Now the important bit ๐จ At least one of the protected and header members MUST be present for each signature/MAC computation so that an alg Header Parameter value is conveyed. No alg, no vibes, no verification ๐
Extra members can show up in both of those JSON objects too. If an implementation doesn't understand them, they MUST be ignored. Main character energy: ignore what you don't know ๐
Here's the tea on how the Header Parameter values get pulled together when you're creating or validating each signature or MAC. You take the union of two sets: (1) the JWS Protected Header in the protected member of that signature/MAC's array element, and (2) the JWS Unprotected Header in the header member of that same array element. That union is the JOSE Header. โจ The Header Parameter names in the two locations MUST be disjoint, meaning they can't overlap at all ๐
โโ๏ธ
Each JWS Signature value gets computed using the parameters of the matching JOSE Header value, the same way as in the JWS Compact Serialization. This is honestly so satisfying ๐ญ Each JWS Signature in the signatures array is identical to the value you'd get for the same parameters in the JWS Compact Serialization, as long as the JWS Protected Header for that computation (the integrity-protected Header Parameter values) matches what was used there. Same signature, different outfit ๐ง
Summary of the general syntax, in all its glory:
{
"payload":"<payload contents>",
"signatures":[
{"protected":"<integrity-protected header 1 contents>",
"header":<non-integrity-protected header 1 contents>,
"signature":"<signature 1 contents>"},
...
{"protected":"<integrity-protected header N contents>",
"header":<non-integrity-protected header N contents>,
"signature":"<signature N contents>"}]
}
For an example JWS using the general JWS JSON Serialization syntax, check out Appendix A.6 ๐
7.2.2. Flattened JWS JSON Serialization Syntax
The flattened JWS JSON Serialization syntax is based on the general one, but it flattens it ๐ฅ It's optimized for the single digital signature/MAC situation. The trick is that it removes the signatures member and puts the members that would've lived in the signatures array (protected, header, and signature) right in the top-level JSON object, next to payload. Clean and simple ๐
The signatures member MUST NOT be present when you use this syntax. Other than that little syntax difference, JWS JSON Serialization objects using the flattened syntax are processed exactly the same as ones using the general syntax. No extra rules, bestie ๐
Summary of the flattened syntax:
{
"payload":"<payload contents>",
"protected":"<integrity-protected header contents>",
"header":<non-integrity-protected header contents>,
"signature":"<signature contents>"
}
For an example JWS using the flattened JWS JSON Serialization syntax, see Appendix A.7 โจ
8. TLS Requirements ๐
Implementations that support the jku and/or x5u Header Parameters MUST support TLS. Which TLS version(s) you should implement will change over time, and it depends on what's widely deployed and which security vulnerabilities are known at the time you're building. At the time of this writing, TLS version 1.2 [RFC5246] is the most recent version.
To protect against information disclosure and tampering, confidentiality protection MUST be applied using TLS with a ciphersuite that provides both confidentiality and integrity protection. ๐ก๏ธ For guidance on which ciphersuites are currently considered appropriate, look at current publications by the IETF TLS working group, including RFC 6176 [RFC6176]. You should also check out "Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)" [RFC7525] for ways to level up the security of your software and services that use TLS ๐ช
Whenever TLS is used, the identity of the service provider encoded in the TLS server certificate MUST be verified using the procedures described in Section 6 of RFC 6125 [RFC6125]. No skipping this step, bestie, it's not optional ๐
9. IANA Considerations ๐
The following registration procedure is used for all the registries established by this specification. Every single one of them ๐
Values are registered on a Specification Required [RFC5226] basis, after a three-week review period on the jose-reg-review@ietf.org mailing list, on the advice of one or more Designated Experts. However, to allow values to be allocated before publication, the Designated Experts may approve a registration once they're satisfied that such a specification will be published. Early access, but make it official ๐๏ธ
Registration requests sent to the mailing list for review should use an appropriate subject, for example Request to register header parameter: example ๐ฎ
Within the review period, the Designated Experts will either approve or deny the registration request, and they'll communicate that decision to the review list and IANA. Denials should include an explanation and, if it applies, suggestions for how to make the request successful. It's giving constructive feedback ๐ซถ If a registration request is undetermined for longer than 21 days, it can be brought to the IESG's attention (using the iesg@ietf.org mailing list) for resolution.
The criteria the Designated Experts should apply include figuring out whether the proposed registration duplicates existing functionality, whether it's likely to be of general applicability or only useful for a single application, and whether the registration description is clear. Reviewer brain activated ๐ง
IANA must only accept registry updates from the Designated Experts, and it should direct all registration requests to the review mailing list. Gatekeeping, but iconic ๐
It's suggested that multiple Designated Experts be appointed, and that they can represent the perspectives of the different applications using this specification. That way registration decisions get broadly informed review ๐ In cases where a registration decision could look like a conflict of interest for a particular Expert, that Expert should defer to the judgment of the other Experts. Fair is fair โจ
9.1. JSON Web Signature and Encryption Header Parameters Registry
This specification establishes the IANA "JSON Web Signature and Encryption Header Parameters" registry for Header Parameter names. The registry records the Header Parameter name and a reference to the specification that defines it. The same Header Parameter name can be registered multiple times, as long as the parameter usage is compatible between the specifications. Different registrations of the same Header Parameter name will typically use different Header Parameter Usage Locations values. Same name, different job ๐ฆ
9.1.1. Registration Template
Header Parameter Name: The name requested (for example, "kid"). Because a core goal of this specification is for the resulting representations to be compact, it is RECOMMENDED that the name be short, not exceeding 8 characters without a compelling reason to do so. The name is case sensitive. Names may not match other registered names in a case-insensitive manner, unless the Designated Experts state that there's a compelling reason to allow an exception. Short and sweet, bestie ๐
Header Parameter Description: A brief description of the Header Parameter (for example, "Key ID") โ๏ธ
Header Parameter Usage Location(s): The Header Parameter usage locations, which should be one or more of the values "JWS" or "JWE" ๐
Change Controller: For Standards Track RFCs, list the "IESG". For others, give the name of the responsible party. Other details (for example, postal address, email address, home page URI) may also be included. Who's in charge? Now you know ๐
Specification Document(s): A reference to the document or documents that specify the parameter, preferably including URIs that can be used to retrieve copies of the documents. An indication of the relevant sections may also be included, but it's not required. Receipts, please ๐งพ
9.1.2. Initial Registry Contents โจ
okay so this section is where we officially claim every Header Parameter name from Section 4.1 for this registry ๐ here's the whole lineup ๐
o Header Parameter Name: "alg"
o Header Parameter Description: Algorithm
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.1 of RFC 7515
o Header Parameter Name: "jku"
o Header Parameter Description: JWK Set URL
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.2 of RFC 7515
o Header Parameter Name: "jwk"
o Header Parameter Description: JSON Web Key
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.3 of RFC 7515
o Header Parameter Name: "kid"
o Header Parameter Description: Key ID
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.4 of RFC 7515
o Header Parameter Name: "x5u"
o Header Parameter Description: X.509 URL
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.5 of RFC 7515
o Header Parameter Name: "x5c"
o Header Parameter Description: X.509 Certificate Chain
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.6 of RFC 7515
o Header Parameter Name: "x5t"
o Header Parameter Description: X.509 Certificate SHA-1 Thumbprint
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.7 of RFC 7515
o Header Parameter Name: "x5t#S256"
o Header Parameter Description: X.509 Certificate SHA-256 Thumbprint
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.8 of RFC 7515
o Header Parameter Name: "typ"
o Header Parameter Description: Type
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.9 of RFC 7515
o Header Parameter Name: "cty"
o Header Parameter Description: Content Type
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.10 of RFC 7515
o Header Parameter Name: "crit"
o Header Parameter Description: Critical
o Header Parameter Usage Location(s): JWS
o Change Controller: IESG
o Specification Document(s): Section 4.1.11 of RFC 7515
9.2. Media Type Registration ๐ฆ
9.2.1. Registry Contents ๐ธ
this section registers the "application/jose" media type [RFC2046] in the "Media Types" registry [IANA.MediaTypes], following the process in RFC 6838 [RFC6838] ๐ it's the one you use to say the content is a JWS or JWE in the JWS Compact Serialization or the JWE Compact Serialization. it also registers "application/jose+json" in the same registry, which is for when the content is a JWS or JWE in the JWS JSON Serialization or the JWE JSON Serialization. โจ
o Type name: application
o Subtype name: jose
o Required parameters: n/a
o Optional parameters: n/a
o Encoding considerations: 8bit; application/jose values are encoded
as a series of base64url-encoded values (some of which may be the
empty string), each separated from the next by a single period
('.') character.
o Security considerations: See the Security Considerations section
of RFC 7515.
o Interoperability considerations: n/a
o Published specification: RFC 7515
o Applications that use this media type: OpenID Connect, Mozilla
Persona, Salesforce, Google, Android, Windows Azure, Xbox One,
Amazon Web Services, and numerous others that use JWTs
o Fragment identifier considerations: n/a
o Additional information:
Magic number(s): n/a
File extension(s): n/a
Macintosh file type code(s): n/a
o Person & email address to contact for further information:
Michael B. Jones, mbj@microsoft.com
o Intended usage: COMMON
o Restrictions on usage: none
o Author: Michael B. Jones, mbj@microsoft.com
o Change Controller: IESG
o Provisional registration? No
o Type name: application
o Subtype name: jose+json
o Required parameters: n/a
o Optional parameters: n/a
o Encoding considerations: 8bit; application/jose+json values are
represented as a JSON Object; UTF-8 encoding SHOULD be employed
for the JSON object.
o Security considerations: See the Security Considerations section
of RFC 7515
o Interoperability considerations: n/a
o Published specification: RFC 7515
o Applications that use this media type: Nimbus JOSE + JWT library
o Fragment identifier considerations: n/a
o Additional information:
Magic number(s): n/a
File extension(s): n/a
Macintosh file type code(s): n/a
o Person & email address to contact for further information:
Michael B. Jones, mbj@microsoft.com
o Intended usage: COMMON
o Restrictions on usage: none
o Author: Michael B. Jones, mbj@microsoft.com
o Change Controller: IESG
o Provisional registration? No
10. Security Considerations ๐ฅ
okay this part is seriously important bestie ๐ญ every security issue that applies to any cryptographic app has to be dealt with by JWS, JWE, and JWK agents ๐ซถ that includes protecting the user's asymmetric private keys and symmetric secret keys, plus countering all the different attacks out there ๐
the XML Signature Syntax and Processing Version 2.0 [W3C.NOTE-xmldsig-core2-20130411] security considerations apply to this spec too, except for the XML-specific ones ๐ง same deal for the best practices in XML Signature Best Practices [W3C.NOTE-xmldsig-bestpractices-20130411] โจ
10.1. Key Entropy and Random Values ๐ฒ
keys are only as strong as the entropy that goes into making them ๐ a minimum of 128 bits of entropy should be used for all keys, and depending on the app, more may be required ๐
implementations must randomly generate public/private key pairs, MAC keys, and padding values ๐ using weak PRNGs (pseudorandom number generators) to make crypto keys can end up giving you little or no security ๐ฑ an attacker might find it way easier to recreate the PRNG environment that made the keys and search that small set of possibilities, instead of brute-forcing the whole key space ๐ good quality random numbers are genuinely hard to get right ๐ญ RFC 4086 [RFC4086] has important guidance on this ๐ฆ
10.2. Key Protection ๐ก๏ธ
implementations must protect the signer's private key ๐ if someone gets it, they can pretend to be the signer ๐
implementations must protect the MAC key ๐ if the MAC key gets compromised, someone could change the authenticated content without anyone noticing ๐ญ
10.3. Key Origin Authentication ๐ชช
the key management technique used to get public keys must authenticate where the key came from ๐ซถ otherwise, nobody knows who signed the message ๐ต๏ธโโ๏ธ
same energy for MAC keys: the technique used to distribute them must provide data origin authentication ๐ otherwise, the contents arrive with integrity from some unknown source ๐
10.4. Cryptographic Agility ๐
check out Section 8.1 of [JWA] for the security considerations on cryptographic agility ๐
10.5. Differences between Digital Signatures and MACs โ๏ธ
MACs and digital signatures are both good for integrity checking, but their security properties are really different ๐ธ you have to think about this when you design protocols and pick algorithms ๐
both signatures and MACs check integrity, meaning they verify the message hasn't been changed since the integrity value was computed โจ but MACs only give you origination identification in specific situations ๐ค a signature's private key is usually only held by one entity (maybe a distributed one, like replicated servers) ๐ง a MAC key has to be held by every entity that uses it for computing and checking integrity ๐ validating a MAC just proves the message came from one of the parties who knows the symmetric MAC key ๐ so origination only works if the MAC key is known to just two entities AND the recipient knows it didn't create the message itself ๐ซ MAC validation can't prove origination to a third party, period ๐ซ
10.6. Algorithm Validation ๐งช
some digital signature representations include info about the algorithm inside the signature value ๐ for instance, signatures made with RSASSA-PKCS1-v1_5 [RFC3447] encode the hash function, and lots of libraries actually use the hash algorithm inside the signature when validating ๐ when you use those libraries, implementations MUST ensure that the algorithm info encoded in the signature matches what's specified with the "alg" Header Parameter ๐จ if they don't check this, an attacker could claim a strong hash algorithm but actually use a weak one hidden in the signature value ๐ฑ
10.7. Algorithm Protection ๐ก๏ธ
in some JWS usages, there's a risk of algorithm substitution attacks ๐ต๏ธโโ๏ธ that's where an attacker reuses an existing digital signature value with a different signature algorithm, so it looks like a signer signed something they never signed ๐ these attacks have been discussed in detail for Cryptographic Message Syntax (CMS) [RFC6211] ๐ the risk shows up when ALL of these are true:
- verifiers of a signature support multiple algorithms.
- given an existing signature, an attacker can find another payload that produces the same signature value with a different algorithm.
- the payload the attacker crafts is valid in the application context.
there are a few ways for an app to protect against algorithm substitution attacks ๐ง
- use only digital signature algorithms that aren't vulnerable to substitution attacks. substitution attacks only work if an attacker can compute pre-images for a hash function the recipient accepts. all JWA-defined signature algorithms use SHA-2 hashes, which have no known pre-image attacks as of writing this ๐
- require that the
"alg"Header Parameter be carried in the JWS Protected Header. (this is always the case with the JWS Compact Serialization, and it's the approach CMS [RFC6211] takes ๐) - include a field with the algorithm in the application payload, and require that it gets matched with the
"alg"Header Parameter during verification. (this is the approach PKIX [RFC5280] takes ๐)
10.8. Chosen Plaintext Attacks ๐
creators of JWSs should not let third parties insert arbitrary content into the message unless they add entropy the third party doesn't control ๐ โโ๏ธ this one's a big deal, so don't skip it ๐
10.9. Timing Attacks
okay bestie, timing attacks are lowkey scary ๐ญโฑ๏ธ If a crypto algorithm takes a different amount of time for a successful operation than for an unsuccessful one, an attacker can use that time gap to learn stuff about the keys being used. So those timing differences must be avoided ๐๐
10.10. Replay Protection
not directly in scope for this spec, but you should still know about it ๐ apps using JWS (or JWE) objects can stop replay attacks by putting a unique message identifier inside the integrity-protected content of the JWS (or JWE) message. then the recipient checks that the message hasn't already been received or acted upon. big brain move ๐ง โจ
10.11. SHA-1 Certificate Thumbprints
okay so "x5t" (the X.509 certificate SHA-1 thumbprint) uses a SHA-1 hash, but only for compatibility reasons ๐ฅบ here's the spicy part: if someone figures out a real way to make SHA-1 collisions, an attacker could make a different certificate with the same SHA-1 hash and sneak it into the certificate store of the person they're targeting, so the known certificate gets interfered with ๐ฑ but the attacker would need write access to that victim's certificate store first, so it's not just anyone ๐
โโ๏ธ
the fix is the "x5t#S256" (X.509 certificate SHA-256 thumbprint) Header Parameter, which can be used instead of "x5t". BUT, as of writing, no development platform is known to support SHA-256 certificate thumbprints ๐ so it's kind of a waiting game rn ๐ซ
10.12. JSON Security Considerations
strict JSON [RFC7159] validation is a security requirement, periodt ๐ฅ if malformed JSON shows up, nobody can reliably tell what the producer meant, and that's how you get ambiguous, exploitable situations ๐ฌ so any JSON input that doesn't follow the JSON-text syntax defined in RFC 7159 MUST be rejected in its entirety by JSON parsers. no exceptions, no cap ๐ซ
now here's the tea โ Section 4 of "The JavaScript Object Notation (JSON) Data Interchange Format" [RFC7159] says "The names within an object SHOULD be unique", but this spec goes harder and says:
The Header Parameter names within the JOSE Header MUST be unique; JWS parsers MUST either reject JWSs with duplicate Header Parameter names or use a JSON parser that returns only the lexically last duplicate member name, as specified in Section 15.12 ("The JSON Object") of ECMAScript 5.1 [ECMAScript].
so basically, this spec says the RFC 7159 "SHOULD" should be treated as a MUST by producers ๐ซถ, and consumers have to either treat it as a MUST or follow the ECMAScript 5.1 way. if the JSON parser doesn't enforce unique member names, or gives back a random value for duplicates, that's a whole mess ๐ช๏ธ
some JSON parsers might also accept input with extra significant characters after valid input. for example, {"tag":"value"}ABCD is a valid JSON-text object followed by the extra characters ABCD. implementations MUST consider JWSs with input like that to be invalid ๐
โโ๏ธ๐
10.13. Unicode Comparison Security Considerations
Header Parameter names and algorithm names are Unicode strings, and for security reasons their representations must be compared verbatim after escape processing (as per Section 8.3 of RFC 7159 [RFC7159]) ๐ so, for instance, "sig" and "\u0073ig" must compare as equal โ
, but "SIG", "Sig", and "si\u0047" must all be unequal to the first set and to each other โ (capitalization really does matter, bestie ๐ค)
JSON strings can also hold characters outside the Unicode Basic Multilingual Plane ๐ต for example, the G clef character (U+1D11E) can show up as "\uD834\uDD1E" in a JSON string. ideally, JWS implementations SHOULD preserve those characters and compare them correctly ๐. if that isn't possible because the underlying JSON implementation has limitations with those characters, then any input containing them MUST be rejected ๐
11. References โจ
11.1. Normative References
okay these are the receipts ๐ every one of them, complete:
[ECMAScript]Ecma International, "ECMAScript Language Specification, 5.1 Edition", ECMA 262, June 2011,<http://www.ecma-international.org/ecma-262/5.1/ECMA-262.pdf>.[IANA.MediaTypes]IANA, "Media Types",<http://www.iana.org/assignments/media-types>.[ITU.X690.2008]International Telecommunications Union, "Information Technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)", ITU-T Recommendation X.690, 2008.[JWA]Jones, M., "JSON Web Algorithms (JWA)", RFC 7518, DOI 10.17487/RFC7518, May 2015,<http://www.rfc-editor.org/info/rfc7518>.[JWK]Jones, M., "JSON Web Key (JWK)", RFC 7517, DOI 10.17487/RFC7517, May 2015,<http://www.rfc-editor.org/info/rfc7517>.[RFC20]Cerf, V., "ASCII format for Network Interchange", STD 80, RFC 20, DOI 10.17487/RFC0020, October 1969,<http://www.rfc-editor.org/info/rfc20>.[RFC2045]Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996,<http://www.rfc-editor.org/info/rfc2045>.[RFC2046]Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, DOI 10.17487/RFC2046, November 1996,<http://www.rfc-editor.org/info/rfc2046>.[RFC2119]Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997,<http://www.rfc-editor.org/info/rfc2119>.[RFC2818]Rescorla, E., "HTTP Over TLS", RFC 2818, DOI 10.17487/RFC2818, May 2000,<http://www.rfc-editor.org/info/rfc2818>.[RFC3629]Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 2003,<http://www.rfc-editor.org/info/rfc3629>.[RFC3986]Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005,<http://www.rfc-editor.org/info/rfc3986>.[RFC4648]Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,<http://www.rfc-editor.org/info/rfc4648>.[RFC4945]Korver, B., "The Internet IP Security PKI Profile of IKEv1/ISAKMP, IKEv2, and PKIX", RFC 4945, DOI 10.17487/RFC4945, August 2007,<http://www.rfc-editor.org/info/rfc4945>.[RFC4949]Shirey, R., "Internet Security Glossary, Version 2", FYI 36, RFC 4949, DOI 10.17487/RFC4949, August 2007,<http://www.rfc-editor.org/info/rfc4949>.[RFC5246]Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, DOI 10.17487/RFC5246, August 2008,<http://www.rfc-editor.org/info/rfc5246>.[RFC5280]Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,<http://www.rfc-editor.org/info/rfc5280>.[RFC6125]Saint-Andre, P. and J. Hodges, "Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)", RFC 6125, DOI 10.17487/RFC6125, March 2011,<http://www.rfc-editor.org/info/rfc6125>.[RFC6176]Turner, S. and T. Polk, "Prohibiting Secure Sockets Layer (SSL) Version 2.0", RFC 6176, DOI 10.17487/RFC6176, March 2011,<http://www.rfc-editor.org/info/rfc6176>.[RFC7159]Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March 2014,<http://www.rfc-editor.org/info/rfc7159>.[UNICODE]The Unicode Consortium, "The Unicode Standard",<http://www.unicode.org/versions/latest/>.
11.2. Informative References โจ
Okay bestie, these are the "go read this if you want the deep lore" references ๐๐ซถ Full details below, all still there:
[CanvasApp]Facebook, "Canvas Applications", <http://developers.facebook.com/docs/authentication/canvas>.[JSS]Bradley, J. and N. Sakimura, Ed., "JSON Simple Sign", September 2010, <http://jsonenc.info/jss/1.0/>.[JWE]Jones, M. and J. Hildebrand, "JSON Web Encryption (JWE)", RFC 7516, DOI 10.17487/RFC7516, May 2015, <http://www.rfc-editor.org/info/rfc7516>.[JWT]Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, May 2015, <http://www.rfc-editor.org/info/rfc7519>.[MagicSignatures]Panzer, J., Ed., Laurie, B., and D. Balfanz, "Magic Signatures", January 2011, <http://salmon-protocol.googlecode.com/svn/trunk/draft-panzer-magicsig-01.html>.[RFC2104]Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, DOI 10.17487/RFC2104, February 1997, <http://www.rfc-editor.org/info/rfc2104>.[RFC3447]Jonsson, J. and B. Kaliski, "Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1", RFC 3447, DOI 10.17487/RFC3447, February 2003, <http://www.rfc-editor.org/info/rfc3447>.[RFC4086]Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, DOI 10.17487/RFC4086, June 2005, <http://www.rfc-editor.org/info/rfc4086>.[RFC4122]Leach, P., Mealling, M., and R. Salz, "A Universally Unique IDentifier (UUID) URN Namespace", RFC 4122, DOI 10.17487/RFC4122, July 2005, <http://www.rfc-editor.org/info/rfc4122>.[RFC5226]Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 5226, DOI 10.17487/RFC5226, May 2008, <http://www.rfc-editor.org/info/rfc5226>.[RFC6211]Schaad, J., "Cryptographic Message Syntax (CMS) Algorithm Identifier Protection Attribute", RFC 6211, DOI 10.17487/RFC6211, April 2011, <http://www.rfc-editor.org/info/rfc6211>.[RFC6838]Freed, N., Klensin, J., and T. Hansen, "Media Type Specifications and Registration Procedures", BCP 13, RFC 6838, DOI 10.17487/RFC6838, January 2013, <http://www.rfc-editor.org/info/rfc6838>.[RFC7525]Sheffer, Y., Holz, R., and P. Saint-Andre, "Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May 2015, <http://www.rfc-editor.org/info/rfc7525>.[SHS]National Institute of Standards and Technology, "Secure Hash Standard (SHS)", FIPS PUB 180-4, March 2012, <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>.[W3C.NOTE-xmldsig-bestpractices-20130411]Hirsch, F. and P. Datta, "XML Signature Best Practices", World Wide Web Consortium Note NOTE-xmldsig-bestpractices-20130411, April 2013, <http://www.w3.org/TR/2013/NOTE-xmldsig-bestpractices-20130411/>.[W3C.NOTE-xmldsig-core2-20130411]Eastlake, D., Reagle, J., Solo, D., Hirsch, F., Roessler, T., Yiu, K., Datta, P., and S. Cantor, "XML Signature Syntax and Processing Version 2.0", World Wide Web Consortium Note NOTE-xmldsig-core2-20130411, April 2013, <http://www.w3.org/TR/2013/NOTE-xmldsig-core2-20130411/>.
Appendix A. JWS Examples ๐
This section is the examples corner, and it's giving practical demo energy ๐ There are several JWS examples here. The first three are all JSON Web Tokens (JWTs) [JWT], but the payload can honestly be any octet sequence, which we'll see in Appendix A.4. ๐ง
A.1. Example JWS Using HMAC SHA-256
A.1.1. Encoding
Okay so the JWS Protected Header in this example says the data structure is a JWT [JWT] and that the JWS Signing Input gets secured with the HMAC SHA-256 algorithm ๐
{"typ":"JWT",
"alg":"HS256"}
Now, JSON can be sneaky, so to kill any ambiguity we also show the actual octet sequence for UTF8(JWS Protected Header) ๐ (Quick heads-up: platforms can disagree on line breaks, like CRLF versus LF, plus spacing at the start and end of lines, and whether the last line ends with a line break. So here's exactly what we used. The first line has no leading or trailing spaces. A CRLF line break (13, 10) sits between line one and line two. Line two has one leading space (32) and no trailing spaces. The last line does not have a terminating line break.)
The octets for UTF8(JWS Protected Header) in this example, written in JSON array notation, are:
[123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32,
34, 97, 108, 103, 34, 58, 34, 72, 83, 50, 53, 54, 34, 125]
Encoding this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) gives us this value โจ
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
The JWS Payload here is the octets of the UTF-8 representation of the JSON object below. (Also, the payload can be any base64url-encoded octet sequence, and it doesn't have to be a base64url-encoded JSON object. Iconic flexibility ๐)
{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true}
This is the octet sequence for the UTF-8 representation of that JSON object, and it's the JWS Payload ๐ธ
[123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10,
32, 34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56,
48, 44, 13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97,
109, 112, 108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111,
111, 116, 34, 58, 116, 114, 117, 101, 125]
Encoding this JWS Payload as BASE64URL(UTF8(JWS Payload)) gives this value. (The line breaks are just for display, not part of the value ๐ฆ)
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
Next, we combine these as BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload). The result is this string, with line breaks just for display ๐
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
The resulting JWS Signing Input value is the ASCII representation of the string above. In octets, using JSON array notation, it looks like this ๐ง
[101, 121, 74, 48, 101, 88, 65, 105, 79, 105, 74, 75, 86, 49, 81,
105, 76, 65, 48, 75, 73, 67, 74, 104, 98, 71, 99, 105, 79, 105, 74,
73, 85, 122, 73, 49, 78, 105, 74, 57, 46, 101, 121, 74, 112, 99, 51,
77, 105, 79, 105, 74, 113, 98, 50, 85, 105, 76, 65, 48, 75, 73, 67,
74, 108, 101, 72, 65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84,
107, 122, 79, 68, 65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100,
72, 65, 54, 76, 121, 57, 108, 101, 71, 70, 116, 99, 71, 120, 108, 76,
109, 78, 118, 98, 83, 57, 112, 99, 49, 57, 121, 98, 50, 57, 48, 73,
106, 112, 48, 99, 110, 86, 108, 102, 81]
HMACs are generated using keys, so this example uses the symmetric key shown below in JSON Web Key [JWK] format. (Line breaks inside the values are just for display ๐)
{"kty":"oct",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75
aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
}
Running the HMAC SHA-256 algorithm on the JWS Signing Input with this key gives us this JWS Signature octet sequence ๐ฅ
[116, 24, 223, 180, 151, 153, 224, 37, 79, 250, 96, 125, 216, 173,
187, 186, 22, 212, 37, 77, 105, 214, 191, 240, 91, 88, 5, 88, 83,
132, 141, 121]
Encoding this JWS Signature as BASE64URL(JWS Signature) gives this value ๐
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Last step, concatenate the values in the order Header.Payload.Signature, with period ('.') characters between the parts. That gives the complete JWS representation using the JWS Compact Serialization. (Line breaks are for display only, bestie ๐)
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
A.1.2. Validating
Since the "alg" Header Parameter is "HS256", we validate the HMAC SHA-256 value in the JWS Signature ๐ซถ
To validate, we redo the same process: take the correct key and the JWS Signing Input (that's the initial substring of the JWS Compact Serialization up until but not including the second period character), feed them into the HMAC SHA-256 function, and then compare the output to the JWS Signature (which we base64url decode from the value in the JWS representation). If it matches exactly, the HMAC has been validated. Periodt ๐ โจ
A.2. Example JWS Using RSASSA-PKCS1-v1_5 SHA-256
A.2.1. Encoding ๐
okay so this one is giving a different vibe from the last example ๐
The JWS Protected Header changes in two ways. First, since we're using a different algorithm, the "alg" value is different. Second, just for illustration, we skip the optional "typ" (type) Header Parameter ๐ฆ (the algorithm has nothing to do with that choice, promise). The JWS Protected Header we're using is:
{"alg":"RS256"}
The octets for UTF8(JWS Protected Header) in this example, written as a JSON array, are:
[123, 34, 97, 108, 103, 34, 58, 34, 82, 83, 50, 53, 54, 34, 125]
Encode the header as BASE64URL(UTF8(JWS Protected Header)) and you get this value:
eyJhbGciOiJSUzI1NiJ9
The JWS Payload is the same as in the last example ๐ซถ so its BASE64URL value is also the same, and we're not redoing that math. Here it is anyway:
{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true}
Now we combine them as BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) โจ (the line breaks are just so it's readable on screen):
eyJhbGciOiJSUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
The JWS Signing Input is the ASCII version of that string above, and it's this octet sequence ๐ง
[101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 122, 73,
49, 78, 105, 74, 57, 46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105,
74, 113, 98, 50, 85, 105, 76, 65, 48, 75, 73, 67, 74, 108, 101, 72,
65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107, 122, 79, 68,
65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76,
121, 57, 108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118,
98, 83, 57, 112, 99, 49, 57, 121, 98, 50, 57, 48, 73, 106, 112, 48,
99, 110, 86, 108, 102, 81]
This example uses the RSA key in [JWK] (JSON Web Key) format, shown below. The line breaks inside the values are just for display ๐ธ
{"kty":"RSA",
"n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx
HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs
D1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSH
SXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdV
MTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8
NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
"e":"AQAB",
"d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97I
jlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0
BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn
439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYT
CBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLh
BOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ",
"p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdi
YrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPG
BY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc",
"q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxa
ewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA
-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc",
"dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3Q
CLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb
34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0",
"dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa
7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-ky
NlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
"qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2o
y26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLU
W0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
}
The RSA private key goes into the RSA signing function, which also gets the hash type, SHA-256, and the JWS Signing Input ๐ฅ The signature comes back as an octet sequence representing a big-endian integer. In this example, it's:
[112, 46, 33, 137, 67, 232, 143, 209, 30, 181, 216, 45, 191, 120, 69,
243, 65, 6, 174, 27, 129, 255, 247, 115, 17, 22, 173, 209, 113, 125,
131, 101, 109, 66, 10, 253, 60, 150, 238, 221, 115, 162, 102, 62, 81,
102, 104, 123, 0, 11, 135, 34, 110, 1, 135, 237, 16, 115, 249, 69,
229, 130, 173, 252, 239, 22, 216, 90, 121, 142, 232, 198, 109, 219,
61, 184, 151, 91, 23, 208, 148, 2, 190, 237, 213, 217, 217, 112, 7,
16, 141, 178, 129, 96, 213, 248, 4, 12, 167, 68, 87, 98, 184, 31,
190, 127, 249, 217, 46, 10, 231, 111, 36, 242, 91, 51, 187, 230, 244,
74, 230, 30, 177, 4, 10, 203, 32, 4, 77, 62, 249, 18, 142, 212, 1,
48, 121, 91, 212, 189, 59, 65, 238, 202, 208, 102, 171, 101, 25, 129,
253, 228, 141, 247, 127, 55, 45, 195, 139, 159, 175, 221, 59, 239,
177, 139, 93, 163, 204, 60, 46, 176, 47, 158, 58, 65, 214, 18, 202,
173, 21, 145, 18, 115, 160, 95, 35, 185, 232, 56, 250, 175, 132, 157,
105, 132, 41, 239, 90, 30, 136, 121, 130, 54, 195, 212, 14, 96, 69,
34, 165, 68, 200, 242, 122, 122, 45, 184, 6, 99, 209, 108, 247, 202,
234, 86, 222, 64, 92, 178, 33, 90, 69, 178, 194, 85, 102, 181, 90,
193, 167, 72, 160, 112, 223, 200, 163, 42, 70, 149, 67, 208, 25, 238,
251, 71]
Encoding that signature as BASE64URL(JWS Signature) gives this value (line breaks for display only) ๐ฆ
cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7
AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4
BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K
0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv
hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB
p0igcN_IoypGlUPQGe77Rw
Last step: put Header, Payload and Signature in that order with a period ('.') between each part, and you get the complete JWS in the JWS Compact Serialization ๐ (line breaks again just for display):
eyJhbGciOiJSUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7
AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4
BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K
0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv
hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB
p0igcN_IoypGlUPQGe77Rw
A.2.2. Validating ๐
Since the "alg" Header Parameter is RS256, we validate the RSASSA-PKCS1-v1_5 SHA-256 digital signature that lives in the JWS Signature โจ
Checking the JWS Signature is a bit different from the last example, so pay attention bestie ๐ We pass in three things: the public key (n, e), the JWS Signature (base64url decoded from its encoded form in the JWS representation), and the JWS Signing Input. The Signing Input is the initial substring of the JWS Compact Serialization, up until but not including the second period character. All of that goes to an RSASSA-PKCS1-v1_5 signature verifier that's been set up to use the SHA-256 hash function ๐
A.3. Example JWS Using ECDSA P-256 SHA-256 ๐
A.3.1. Encoding ๐
The JWS Protected Header in this example is different from the previous ones because we're using a different algorithm. The JWS Protected Header is:
{"alg":"ES256"}
The octets for UTF8(JWS Protected Header) in this example, written as a JSON array, are:
[123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 50, 53, 54, 34, 125]
Encode this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) and you get this value:
eyJhbGciOiJFUzI1NiJ9
The JWS Payload is the same as in the previous examples ๐ซถ so its BASE64URL(JWS Payload) value is also the same, and we're skipping that computation. Here's the payload anyway:
{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true}
Combine them as BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) and you get this string (line breaks for display only) โจ
eyJhbGciOiJFUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
The JWS Signing Input is the ASCII version of that string, so it's this octet sequence ๐ง
[101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 70, 85, 122, 73,
49, 78, 105, 74, 57, 46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105,
74, 113, 98, 50, 85, 105, 76, 65, 48, 75, 73, 67, 74, 108, 101, 72,
65, 105, 79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107, 122, 79, 68,
65, 115, 68, 81, 111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76,
121, 57, 108, 101, 71, 70, 116, 99, 71, 120, 108, 76, 109, 78, 118,
98, 83, 57, 112, 99, 49, 57, 121, 98, 50, 57, 48, 73, 106, 112, 48,
99, 110, 86, 108, 102, 81]
This example uses the Elliptic Curve key in [JWK] (JSON Web Key) format, shown below ๐ธ
{"kty":"EC",
"crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"
}
The ECDSA (Elliptic Curve Digital Signature Algorithm) private part d goes into an ECDSA signing function ๐ฅ That function also takes the curve type, P-256, the hash type, SHA-256, and the JWS Signing Input. The result is the Elliptic Curve (EC) point (R, S), where R and S are unsigned integers. In this example, R and S are given as octet sequences representing big-endian integers, like this:
+--------+----------------------------------------------------------+
| Result | Value |
| Name | |
+--------+----------------------------------------------------------+
| R | [14, 209, 33, 83, 121, 99, 108, 72, 60, 47, 127, 21, 88, |
| | 7, 212, 2, 163, 178, 40, 3, 58, 249, 124, 126, 23, 129, |
| | 154, 195, 22, 158, 166, 101] |
| S | [197, 10, 7, 211, 140, 60, 112, 229, 216, 241, 45, 175, |
| | 8, 74, 84, 128, 166, 101, 144, 197, 242, 147, 80, 154, |
| | 143, 63, 127, 138, 131, 163, 84, 213] |
+--------+----------------------------------------------------------+
The JWS Signature is the value R || S ๐ฆ Encoding the signature as BASE64URL(JWS Signature) produces this value (line breaks for display only):
DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA
pmWQxfKTUJqPP3-Kg6NU1Q
Now concatenate Header.Payload.Signature, with a period ('.') between the parts, and you get the complete JWS representation using the JWS Compact Serialization ๐ (line breaks for display only):
eyJhbGciOiJFUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA
pmWQxfKTUJqPP3-Kg6NU1Q
A.3.2. Validating ๐
okay so bestie, since the "alg" Header Parameter is "ES256", we validate the ECDSA P-256 SHA-256 digital signature sitting in the JWS Signature ๐ฆ
validating the JWS Signature is a bit different from the previous examples โจ we have to split the 64 member octet sequence of the JWS Signature (the one you get by base64url decoding the value from the JWS representation) into two 32 octet sequences. The first one is R and the second one is S ๐ซถ Then we hand the public key (x, y), the signature (R, S), and the JWS Signing Input (that's the initial substring of the JWS Compact Serialization up until but not including the second period character) to an ECDSA signature verifier that's been set up for the P-256 curve with the SHA-256 hash function ๐
A.4. Example JWS Using ECDSA P-521 SHA-512 ๐
A.4.1. Encoding
the JWS Protected Header in this example is different from the last one, because we're using different ECDSA curves and hash functions ๐ The JWS Protected Header is:
{"alg":"ES512"}
the octets representing UTF8(JWS Protected Header) in this example (using JSON array notation) are:
[123, 34, 97, 108, 103, 34, 58, 34, 69, 83, 53, 49, 50, 34, 125]
encoding this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) gives this value:
eyJhbGciOiJFUzUxMiJ9
the JWS Payload here is the ASCII string "Payload" ๐ its representation is this octet sequence:
[80, 97, 121, 108, 111, 97, 100]
encoding this JWS Payload as BASE64URL(JWS Payload) gives this value:
UGF5bG9hZA
combining these as BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) gives this string:
eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA
the resulting JWS Signing Input value, which is the ASCII representation of the string above, is this octet sequence:
[101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 70, 85, 122, 85,
120, 77, 105, 74, 57, 46, 85, 71, 70, 53, 98, 71, 57, 104, 90, 65]
this example uses the Elliptic Curve key in JSON Web Key [JWK] format shown below (the line breaks inside the values are just for display ๐):
{"kty":"EC",
"crv":"P-521",
"x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_
NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk",
"y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDl
y79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2",
"d":"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPA
xerEzgdRhajnu0ferB0d53vM9mE15j2C"
}
the ECDSA private part d gets passed to an ECDSA signing function, which also takes the curve type, P-521, the hash type, SHA-512, and the JWS Signing Input as inputs ๐ฅ the result of the digital signature is the EC point (R, S), where R and S are unsigned integers. In this example, the R and S values, given as octet sequences representing big-endian integers, are:
+--------+----------------------------------------------------------+
| Result | Value |
| Name | |
+--------+----------------------------------------------------------+
| R | [1, 220, 12, 129, 231, 171, 194, 209, 232, 135, 233, |
| | 117, 247, 105, 122, 210, 26, 125, 192, 1, 217, 21, 82, |
| | 91, 45, 240, 255, 83, 19, 34, 239, 71, 48, 157, 147, |
| | 152, 105, 18, 53, 108, 163, 214, 68, 231, 62, 153, 150, |
| | 106, 194, 164, 246, 72, 143, 138, 24, 50, 129, 223, 133, |
| | 206, 209, 172, 63, 237, 119, 109] |
| S | [0, 111, 6, 105, 44, 5, 41, 208, 128, 61, 152, 40, 92, |
| | 61, 152, 4, 150, 66, 60, 69, 247, 196, 170, 81, 193, |
| | 199, 78, 59, 194, 169, 16, 124, 9, 143, 42, 142, 131, |
| | 48, 206, 238, 34, 175, 83, 203, 220, 159, 3, 107, 155, |
| | 22, 27, 73, 111, 68, 68, 21, 238, 144, 229, 232, 148, |
| | 188, 222, 59, 242, 103] |
+--------+----------------------------------------------------------+
the JWS Signature is the value R || S. Encoding the signature as BASE64URL(JWS Signature) produces this value (with line breaks just for display โจ):
AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZq
wqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8Kp
EHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn
concatenating these values in the order Header.Payload.Signature, with period ('.') characters between the parts, gives this complete JWS representation using the JWS Compact Serialization (line breaks for display purposes only ๐ฆ):
eyJhbGciOiJFUzUxMiJ9
.
UGF5bG9hZA
.
AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZq
wqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8Kp
EHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn
A.4.2. Validating
since the "alg" Header Parameter is "ES512", we validate the ECDSA P-521 SHA-512 digital signature in the JWS Signature ๐
validating this JWS Signature is very similar to the previous example ๐ธ we have to split the 132-member octet sequence of the JWS Signature into two 66-octet sequences, the first representing R and the second S. Then we pass the public key (x, y), the signature (R, S), and the JWS Signing Input to an ECDSA signature verifier that's been set up for the P-521 curve with the SHA-512 hash function.
A.5. Example Unsecured JWS ๐
the following example JWS Protected Header says that the encoded object is an Unsecured JWS:
{"alg":"none"}
encoding this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) gives this value:
eyJhbGciOiJub25lIn0
the JWS Payload in this example is the same as in the previous examples, so its BASE64URL(JWS Payload) value will be the same too, and we're not repeating the computation ๐
{"iss":"joe",
"exp":1300819380,
"http://example.com/is_root":true}
the JWS Signature is the empty octet string, and BASE64URL(JWS Signature) is the empty string. ๐ซ
concatenating these values in the order Header.Payload.Signature, with period ('.') characters between the parts, gives this complete JWS representation using the JWS Compact Serialization (line breaks for display purposes only ๐ง):
eyJhbGciOiJub25lIn0
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
A.6. Example JWS Using General JWS JSON Serialization ๐
this section has an example using the general JWS JSON Serialization syntax. It shows that you can convey multiple digital signatures and/or MACs for the same payload, which is so iconic ๐
the JWS Payload here is the same one used in the examples in Appendix A.2 and Appendix A.3 (line breaks for display only):
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
two digital signatures are used in this example: the first uses RSASSA-PKCS1-v1_5 SHA-256 and the second uses ECDSA P-256 SHA-256. For the first, the JWS Protected Header and key are the same as in Appendix A.2, so you get the same JWS Signature value, and its computation isn't repeated here. For the second, the JWS Protected Header and key are the same as in Appendix A.3, which also gives the same JWS Signature value, so again no repeat ๐
A.6.1. JWS Per-Signature Protected Headers
the JWS Protected Header value for the first signature is:
{"alg":"RS256"}
encoding this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) gives this value:
eyJhbGciOiJSUzI1NiJ9
the JWS Protected Header value for the second signature is:
{"alg":"ES256"}
encoding this JWS Protected Header as BASE64URL(UTF8(JWS Protected Header)) gives this value:
eyJhbGciOiJFUzI1NiJ9
A.6.2. JWS Per-Signature Unprotected Headers
key IDs are supplied for both keys using per-signature Header Parameters ๐ซถ The two JWS Unprotected Header values used to represent these key IDs are:
{"kid":"2010-12-29"}
and
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}
A.6.3. Complete JOSE Header Values
combining the JWS Protected Header and JWS Unprotected Header values gives us the JOSE Header values for the first and second signatures, respectively:
{"alg":"RS256",
"kid":"2010-12-29"}
and
{"alg":"ES256",
"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}
A.6.4. Complete JWS JSON Serialization Representation
the complete JWS JSON Serialization for these values is below (line breaks inside values for display only ๐):
{
"payload":
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
"signatures":[
{"protected":"eyJhbGciOiJSUzI1NiJ9",
"header":
{"kid":"2010-12-29"},
"signature":
"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ
mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb
KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl
b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES
c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX
LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"},
{"protected":"eyJhbGciOiJFUzI1NiJ9",
"header":
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
"signature":
"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
lSApmWQxfKTUJqPP3-Kg6NU1Q"}]
}
A.7. Example JWS Using Flattened JWS JSON Serialization ๐ฆ
this section has an example using the flattened JWS JSON Serialization syntax. It shows how you can carry a single digital signature or MAC in a flattened JSON structure โจ
the values here are the same as the ones in the second signature of the previous example in Appendix A.6.
the complete JWS JSON Serialization for these values is below (line breaks inside values for display only ๐):
{
"payload":
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
"protected":"eyJhbGciOiJFUzI1NiJ9",
"header":
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
"signature":
"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
lSApmWQxfKTUJqPP3-Kg6NU1Q"
}
Appendix B. "x5c" (X.509 Certificate Chain) Example โจ
okay so this is the big example chain ๐ it's a JSON array of certificates you could use as the value of an "x5c" (X.509 certificate chain) Header Parameter, which is defined in Section 4.1.6. the line breaks inside the values are only there so it's easier to read on screen, so don't treat them as part of the data ๐
["MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVM
xITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR2
8gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExM
TYwMTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UE
CBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWR
keS5jb20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYW
RkeS5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlc
nRpZmljYXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTt
wY6vj3D3HKrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqV
Tr9vcyOdQmVZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aL
GbqGmu75RpRSgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo
7RJlbmr2EkRTcDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgW
JCJjPOq8lh8BJ6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAw
EAAaOCATIwggEuMB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVH
SMEGDAWgBTSxLDSkdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEA
MDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWR
keS5jb20wRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2
RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVH
SAAMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
b20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggE
BANKGwOy9+aG2Z+5mC6IGOgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPI
UyIXvJxwqoJKSQ3kbTJSMUA2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL
5CkKSkB2XIsKd83ASe8T+5o0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9
p0iRFEUOOjZv2kWzRaJBydTXRE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsx
uxN89txJx9OjxUUAiKEngHUuHqDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZ
EjYx8WnM25sgVjOuH0aBsXBTWVU+4=",
"MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Z
hbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIE
luYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb
24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDY
yMFoXDTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZS
BHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgM
iBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XC
APVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux
6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLO
tXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWo
riMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZ
Eewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ
4EFgQU0sSw0pHUTBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBu
zEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQK
Ew5WYWxpQ2VydCwgSW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2x
pY3kgVmFsaWRhdGlvbiBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudm
FsaWNlcnQuY29tLzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CA
QEwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGG
F2h0dHA6Ly9vY3NwLmdvZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA
6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybD
BLBgNVHSAERDBCMEAGBFUdIAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZ
mljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjAN
BgkqhkiG9w0BAQUFAAOBgQC1QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+
Sn1eocSxI0YGyeR+sBjUZsE4OWBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgM
QLARzLrUc+cb53S8wGd9D0VmsfSxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j
09VZw==",
"MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ
0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNT
AzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0a
G9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkq
hkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE
5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTm
V0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZ
XJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQD
ExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9
AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5a
vIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zf
N1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwb
P7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQU
AA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQ
C1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMM
j4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd"]
that's a whole lot of base64 bestie ๐ญ๐ซถ
Appendix C. Notes on Implementing base64url Encoding without Padding ๐ฆ
this appendix is all about how to build base64url encoding and decoding functions without padding, starting from standard base64 functions that do use padding. it's a lil bit of a plot twist, but the trick is just to strip the padding on the way out and add it back on the way in ๐ง
to be concrete, here's some example C# code doing exactly that. you can totally write similar stuff in other languages ๐
static string base64urlencode(byte [] arg)
{
string s = Convert.ToBase64String(arg); // Regular base64 encoder
s = s.Split('=')[0]; // Remove any trailing '='s
s = s.Replace('+', '-'); // 62nd char of encoding
s = s.Replace('/', '_'); // 63rd char of encoding
return s;
}
static byte [] base64urldecode(string arg)
{
string s = arg;
s = s.Replace('-', '+'); // 62nd char of encoding
s = s.Replace('_', '/'); // 63rd char of encoding
switch (s.Length % 4) // Pad with trailing '='s
{
case 0: break; // No pad chars in this case
case 2: s += "=="; break; // Two pad chars
case 3: s += "="; break; // One pad char
default: throw new System.Exception(
"Illegal base64url string!");
}
return Convert.FromBase64String(s); // Standard base64 decoder
}
so the number of '=' padding characters you need to add back onto a base64url string (to turn it into a padded one) is totally deterministic. it only depends on the length of the encoded string ๐ if length mod 4 is 0, add nothing. if it's 2, add two '=' characters. if it's 3, add one '=' character. and if length mod 4 is 1? ngl that's just malformed input ๐
here's an example of how unencoded and encoded values line up. the octet sequence below encodes into the string below, and when you decode that string you get the original octets back ๐
3 236 255 224 193
A-z_4ME
Appendix D. Notes on Key Selection ๐
okay so this appendix is about a bunch of possible algorithms for picking the key you'll use to validate the digital signature or MAC of a JWS, or to decrypt a JWE ๐ it's a whole family of algorithms rather than just one, because different contexts use different key sources, try them in different orders, and sometimes don't try every key they collected. so every app ends up doing its own thing ๐
these steps are just for illustration. real apps can totally use different algorithms or do the steps in a different order. and honestly most apps have a much simpler way of picking keys, since they might only use one or two profiled methods. this appendix is just extra info on top of the normative key location stuff in Section 6 ๐ซถ
here are the steps. the steps can happen in any order and don't have to be treated as totally separate. for example, you can try a key as soon as you find it instead of gathering all of them first โจ
- Collect the set of potentially applicable keys. Sources of keys may include:
- Keys supplied by the application protocol being used.
- Keys referenced by the "jku" (JWK Set URL) Header Parameter.
- The key provided by the "jwk" (JSON Web Key) Header Parameter.
- The key referenced by the "x5u" (X.509 URL) Header Parameter.
- The key provided by the "x5c" (X.509 certificate chain) Header Parameter.
- Other applicable keys available to the application.
the order for collecting and trying keys from different sources is usually app-dependent. for example, a lot of the time all the keys from one set of places, like local caches, get tried before collecting and trying keys from other places ๐ธ
- Filter the set of collected keys. For instance, some apps will only use keys referenced by "kid" (key ID) or "x5t" (X.509 certificate SHA-1 thumbprint) parameters. if the app uses the JWK "alg" (algorithm), "use" (public key use), or "key_ops" (key operations) parameters, keys with inappropriate values for those get excluded. keys might also be filtered to include or exclude keys with certain other member values, in an app-specific way. and for some apps, no filtering happens at all ๐
- Order the set of collected keys. For instance, keys referenced by "kid" (key ID) or "x5t" (X.509 certificate SHA-1 thumbprint) parameters might get tried before keys with neither of those values. likewise, keys with certain member values might be ordered before keys with other member values. and for some apps, no ordering happens ๐ง
- Make trust decisions about the keys. Signatures made with keys that don't meet the app's trust criteria would not be accepted. those criteria might include (but aren't limited to) where the key came from, whether the TLS certificate validates for keys retrieved from URLs, whether a key in an X.509 certificate is backed by a valid certificate chain, and any other info the app knows ๐ฅ
- Attempt signature or MAC validation for a JWS, or decryption of a JWE, with some or all of the collected and possibly filtered and/or ordered keys. A limit on how many keys get tried might be applied. this process will normally stop after a successful validation or decryption ๐
one more thing, and it's a good one: it's reasonable for some apps to do signature or MAC validation before making a trust decision about a key, since keys whose validation fails don't need a trust decision at all ๐
and that's the end of Appendix D, the big key selection glow-up ๐ฆโจ
Appendix E. Negative Test Case for "crit" Header Parameter ๐ซ
okay bestie, this is the "you MUST say no to this" test ๐ โโ๏ธ conforming implementations must reject input that has critical extensions they don't understand or can't process. this JWS must be rejected by every implementation, because it uses an extension Header Parameter name "http://example.invalid/UNDEFINED" that nobody knows about. any similar input that swaps in "http://example.invalid/UNDEFINED" for some other Header Parameter name the implementation doesn't understand must also be rejected. the vibe is literally "not me rejecting this for fun, it's a rule" ๐
the JWS Protected Header value for this one is:
{"alg":"none",
"crit":["http://example.invalid/UNDEFINED"],
"http://example.invalid/UNDEFINED":true
}
and the complete JWS that must be rejected looks like this (line breaks are just for display, so it's not really split like this in real life โจ):
eyJhbGciOiJub25lIiwNCiAiY3JpdCI6WyJodHRwOi8vZXhhbXBsZS5jb20vVU5ERU
ZJTkVEIl0sDQogImh0dHA6Ly9leGFtcGxlLmNvbS9VTkRFRklORUQiOnRydWUNCn0.
RkFJTA.
Appendix F. Detached Content ๐ฆ
okay so sometimes you want to protect content that isn't actually inside the JWS itself ๐ซถ the move is to make a JWS the normal way, using a representation of the content as the payload, and then remove that payload from the JWS before you send the modified object to the recipient instead of the full JWS. with the JWS Compact Serialization, you delete it by swapping the second field (the one holding BASE64URL(JWS Payload)) for the empty string. with the JWS JSON Serialization, you delete the "payload" member instead.
the catch is that this method assumes the recipient can rebuild the exact payload used in the JWS ๐ so when they get the modified object, they stick the payload representation back in, make the JWS again, and then use it like normal. ngl the best part is that this needs zero special support from JWS libraries, because apps can do the whole thing by just changing the inputs and outputs of standard libraries ๐
Acknowledgements ๐
okay this is the thank-you section and it's so important ๐ฅน solutions for signing JSON were explored before by Magic Signatures [MagicSignatures], JSON Simple Sign [JSS], and Canvas Applications [CanvasApp], and they all influenced this document ๐
thanks to Axel Nennker for the early implementation and feedback on the JWS and JWE specifications ๐ง
this spec is the work of the JOSE working group, which has dozens of active and dedicated people ๐ซถ the following individuals contributed ideas, feedback, and wording that shaped this specification:
Dirk Balfanz, Richard Barnes, Brian Campbell, Alissa Cooper, Breno de Medeiros, Stephen Farrell, Yaron Y. Goland, Dick Hardt, Joe Hildebrand, Jeff Hodges, Russ Housley, Edmund Jay, Tero Kivinen, Ben Laurie, Ted Lemon, James Manger, Matt Miller, Kathleen Moriarty, Tony Nadalin, Hideki Nara, Axel Nennker, John Panzer, Ray Polk, Emmanuel Raviart, Eric Rescorla, Pete Resnick, Jim Schaad, Paul Tarjan, Hannes Tschofenig, and Sean Turner ๐
Jim Schaad and Karen O'Donoghue chaired the JOSE working group, and Sean Turner, Stephen Farrell, and Kathleen Moriarty served as Security Area Directors while this spec was being created ๐
Authors' Addresses โจ
Michael B. Jones ๐ Microsoft EMail: mbj@microsoft.com URI: http://self-issued.info/
John Bradley ๐ธ Ping Identity EMail: ve7jtb@ve7jtb.com URI: http://www.thread-safe.com/
Nat Sakimura ๐ Nomura Research Institute EMail: n-sakimura@nri.co.jp URI: http://nat.sakimura.org/
that's the whole spec, bestie, we did it ๐๐๐ฆ the whole crew is literally iconic ๐
๐ฆ where this page comes from
- ietf: rfc7515 2015-05
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms