Skip to content
Daniel edited this page Feb 23, 2018 · 24 revisions

Contents

Primer

A JSON Web Signature (JWS) represents content secured with digital signatures. It provides integrity protection for the content it represents. A JWS consists of two JSON-based data structures and a signature:

  1. Header
  2. Payload
  3. Signature

Header

The JWS Header is a JSON object specifying the algorithm used to compute the signature of a JWS. Optionally it can contain additional properties of the JWS.

Example

The following header specifies that the JWS' signature is computed with the RSASSA-PKCS1-v1_5 using SHA-512 algorithm.

{ "alg": "RS512" }

A detailed list describing possible header parameters can be found here.

Payload

The JWS Payload is the data being secured by the JWS.

Example

The following string, encoded as UTF-8 data, is an example of a JWS Payload.

"Trumpets of Mexico 🏜"

Signature

The JWS Signature is a digital signature over the JWS Header and JWS Payload. It is computed using the algorithm specified in the JWS Header.

The signing input is the following concatenation:

ascii(base64URL(utf8(JWS Header)) + "." + base64url(payload))

Example

The following is the signing input for the header and payload described above:

eyAiYWxnIjogIlJTNTEyIiB9.VHJ1bXBldHMgb2YgTWV4aWNvIPCfj5w

Serialization

JOSESwift implements compact serialization for JWS. In this format, a JWS is the following concatenation:

base64url(header) + "." + base64url(payload) + "." base64url(signature)

Example

Given the following header and payload:

// Header
{ "alg": "RS512" }

// Payload
"Trumpets of Mexico 🏜"

We get the following base64url encodings:

// base64url(header)
eyAiYWxnIjogIlJTNTEyIiB9

// base64url(payload)
VHJ1bXBldHMgb2YgTWV4aWNvIPCfj5w

// base64url(signature)
TwJS6...YvlTQ

Which yields the following JWS in compact serialization:

eyAiYWxnIjogIlJTNTEyIiB9.VHJ1bXBldHMgb2YgTWV4aWNvIPCfj5w.TwJS6...YvlTQ

Usage

This section describes how the above concepts are implemented and used in JOSESwift.

A JWS in JOSESwift is a simple immutable struct:

struct JWS {
    let header: JWSHeader
    let payload: Payload
    let signature: Data
}

Just as in the above definition, you need three parts to construct a JWS instance in JOSESwift.

  1. A JWSHeader instance
  2. A Payload instance
  3. A Signer instance which computes the signature

These three parts are described in more detail in the following sections.

Header

A JWSHeader is a simple struct, holding a dictionary of parameters:

struct JWSHeader {
    let parameters: [String: Any]
}

For convenient use, a JWSHeader has an initializer that lets you provide the value of the algorithm parameter:

init(algorithm: SignatureAlgorithm)

To instantiate a JWSHeader you specify the signing algorithm that it should carry:

let header = JWSHeader(algorithm: .RS512)

💡 A JWS Header should also support optional additional parameters. This is currently not supported. See issue #60.

Payload

Payload has an initializer that lets you specify the data that your JWS should represent:

init(_ payload: Data)

To instantiate Payload you provide it with the data that it should carry:

let message = "Trumpets of Mexico 🏜"

let data = message.data(using: .utf8)!

let payload = Payload(data)

Signer

A Signer handles all cryptographic functionality needed to compute a JWS Signature. Its sign function computes the signing input from the header and payload. It then passes this signing input to the libraries which provide the cryptographic primitives. The result of this function is the JWS Signature.

Signer provides an initializer which lets you specify the desired signing algorithm and your private key:

init?(signingAlgorithm: SignatureAlgorithm, privateKey: KeyType)

Note that the KeyType depends on the underlying crypto implementation. On iOS it is SecKey per default. The initializer will return nil if you specify the wrong key type.

Make sure to check that you get a valid Signer instance after calling the initializer:

let privateKey: SecKey = /* ... */

guard let signer = Signer(signingAlgorithm: .RS512, privateKey: privateKey) else {
    // Wrong key type.
}

// You have a valid signer.

As a framework user, you don’t need to worry about calling the signer’s sign function. It all happens automatically during the initialization of a JWS.

Instantiating a JWS

Once you have created the three parts, required to construct a JWS, you can use the following JWS initializer:

init<KeyType>(header: JWSHeader, payload: Payload, signer: Signer<KeyType>) throws

Make sure to check if any errors occurred during the initialization process:

do {
    let jws = try JWS(header: header, payload: payload, signer: signer)
} catch {
    // Signing went wrong.
}
Clone this wiki locally