-
Notifications
You must be signed in to change notification settings - Fork 113
A JSON Web Signature (JWS) represents content secured with digital signatures. It provides integrity protection for this content. A JWS consists of:
- A JSON-based header
- Some arbitrary payload
- A signature over this header and payload
The JWS Header is a JSON object specifying the algorithm used to compute the signature. Optionally it can contain additional properties of the JWS.
The following header specifies that the JWS' signature is computed using the RSASSA-PKCS1-v1_5 using SHA-512
algorithm.
{ "alg": "RS512" }
A detailed list describing possible header parameters can be found here.
The JWS Payload is the data being secured by the JWS.
The following string, encoded as UTF-8 data, is an example of a JWS Payload.
"Trumpets of Mexico 🏜"
The JWS Signature is a digital signature over the JWS Header and JWS Payload. It’s computed using the algorithm specified in the JWS Header.
The input to the signing function (also called signing input) is the following concatenation:
ascii(base64URL(utf8(JWS Header)) + "." + base64url(payload))
The following is the signing input for the header and payload described above:
eyAiYWxnIjogIlJTNTEyIiB9.VHJ1bXBldHMgb2YgTWV4aWNvIPCfj5w
JOSESwift implements compact serialization for JWS. Compact serialization represents a JWS as the following concatenation:
base64url(header) + "." + base64url(payload) + "." base64url(signature)
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 compact serialization:
// Comapct serialized JWS
eyAiYWxnIjogIlJTNTEyIiB9.VHJ1bXBldHMgb2YgTWV4aWNvIPCfj5w.TwJS6...YvlTQ
This section describes how the above concepts are implemented and used in JOSESwift.
A JWS
in JOSESwift is an immutable struct
:
struct JWS {
let header: JWSHeader
let payload: Payload
let signature: Data
}
You need three parts to construct a JWS
instance in JOSESwift.
- A
JWSHeader
instance - A
Payload
instance - A
Signer
instance which computes the signature
These three parts are described in more detail in the following sections.
A JWSHeader
is a 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
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)
A Signer
handles all cryptographic functionality needed to compute a JWS Signature. It computes the signing input from the header and payload. It then passes this signing input to the respective libraries providing the cryptographic primitives.
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’s 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 happens automatically during the initialization of a JWS.
Once you have created the header, payload, and signer, you can construct a JWS using the following initializer:
init<KeyType>(header: JWSHeader, payload: Payload, signer: Signer<KeyType>) throws
Make sure to check if any errors occur during the initialization:
do {
let jws = try JWS(header: header, payload: payload, signer: signer)
} catch {
// Signing went wrong.
}