JSON Signatures
Signing of
JSON data essentially comes in two flavors:
- "Freezing" the data and put it in a specific signature container. RFC7515 (JSON Web Signature) represents such a specification.
- Canonicalize the data and add a signature to it.
This document briefly outlines an example of the latter called
JSF (JSON Signature Format).
Due to the fact that there is currently no generally accepted canonicalization method for JSON, JSF builds on a much simpler concept ("Predictable Serialization") which did not become fully practical until ECMAScript V6 was launched. ECMAScript in short says that JSON (and JavaScript) property order must be respected during parsing and serialization which eliminates canonicalization entirely and enables the creation of "Crypto Safe" JSON objects that can travel securely through different systems without getting corrupted.
There is also a JSON encryption scheme, JEF (JSON Encryption Format), using the same syntax as JSF.
Although JSF is not tied to any specific application, it grew from the needs of the payment industry where "Stacked" signed messages begin to play an important role. Below is a (fictitious) example of such a scheme, where one message embeds another (inner) message:
AuthorizationPaymentRequest | Public Key | Signature |
|
X.509 Certificate Path |
Signature |
This scheme could be expressed in JSF like the following (note that the @context
and @qualifier
properties are not a part of JSF, but serve as a possible way to assign a type to a JSON object):
{
"@context": "https://json.sample-standards.org/payment",
"@qualifier": "Authorization",
"paymentRequest": {
"@context": "https://json.sample-standards.org/payment",
"@qualifier": "PaymentRequest",
"payee": {
"commonName": "Demo Merchant",
"homePage": "https://demomerchant.com"
},
"amount": "235.50",
"currency": "USD",
"referenceId": "05630753",
"timeStamp": "2019-08-05T10:07:00Z",
"signature": {
"algorithm": "ES256",
"publicKey": {
"kty": "EC",
"crv": "P-256",
"x": "rZ344aiTaOATmLBOdfYThvnQu_zyB1aJZrbbbks2P9I",
"y": "lKOvfJdgN8WqEbXMDYPRSMsPicm0Tk10pmer9LxvxLg"
},
"value": "x4SCpvutYjDAu0AGuiLHOZcGxWR2Od4Yc3luwlQl2cqjm7wwfrHYX9EdjkZGORCAVr8h4nG02B27DqWBMs9Tig"
}
},
"transactionId": "#1250000005",
"timeStamp": "2019-02-02T10:07:42Z",
"signature": {
"algorithm": "ES256",
"certificatePath": [
"MIIBtTCCAVmgAwIBAgIGAVQ0ylFPMAwGCCqGSM49BAMCBQAwLzELMAkGA1UEBhMCRVUxIDAeBgNVBAMTF1BheW1lbnQgTmV0d29yayBTdWIgQ0EzMB4XDTE0MDEwMTAwMDAwMFoXDTIwMDcxMDA5NTk1OVowMTELMAkGA1UEBhMCREUxDzANBgNVBAUTBjg5NjY0MDERMA8GA1UEAxMIQmlnIEJhbmswWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT5WvxaTfKC3knb8ndHxOtFpr4BZbtmJdrqrU_sQuzqB1bnOs91omd7YF0171OheanYomHj1nlCNavU8fN8kg3Do10wWzAJBgNVHRMEAjAAMA4GA1UdDwEB_wQEAwIHgDAdBgNVHQ4EFgQUJi4DYaNfCYrPI_J1eYKwYT2KAoAwHwYDVR0jBBgwFoAUsUm6VSVmkaQjMgqPDCzX06vzzPYwDAYIKoZIzj0EAwIFAANIADBFAiEAqdGsfVndVdwzfWsl-DObJlb8QOC_yRBJb4Qj_ATUrtcCIHer_yucA5CH0bCwYX3i2r67iG_MsApiD3jFnqaJhxCZ",
"MIIDcjCCAVqgAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAwMQswCQYDVQQGEwJVUzEhMB8GA1UEAxMYUGF5bWVudCBOZXR3b3JrIFJvb3QgQ0ExMB4XDTEyMDcxMDEwMDAwMFoXDTI1MDcxMDA5NTk1OVowLzELMAkGA1UEBhMCRVUxIDAeBgNVBAMTF1BheW1lbnQgTmV0d29yayBTdWIgQ0EzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYbZ_bwsmcb5g8VKvkJXeWed28Ls27Ji12Q1QeQvR9m_OFW3ax1eOCWCDMxC0pdcIEu7oRizEEjfBEthEfTJnRKNjMGEwDwYDVR0TAQH_BAUwAwEB_zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLFJulUlZpGkIzIKjwws19Or88z2MB8GA1UdIwQYMBaAFB8CW1HUIhDUcc3vYhYAnTGXnM5MMA0GCSqGSIb3DQEBDQUAA4ICAQBjTq8Xa6yJdqQ3ml0lsaz8RDgVr6lZbBb-AeBeeRD9Z3LxRVi_h1EytOi5WGwE1ArgL_s3E-HWj1khBTzp2xhk3uDBCnzgyxQM3nlBty4LJWWwjea_JhrmlEq9--yoUbWAbzdqowNFeN2Sks0Mn4PncjIszGBvlrVrGO3YSHMg6goNd4cF8dKbO8KrYoItAyw3w7XBPR77s0R_AxctPsbQeTYM98F2YrN4fqtk67EN1XLYuwjL2B8oeMecb5c7hzW4ANjS90nk-LWnBLLGZIgD2q2KOACg7cZPCMwpiiNdpp16NGlfulch4Yuo8UMY6dkA7eWQJz5zA1KmfsKy6OzqR2IZwxN5kYUTcVx2uSi1gVK63xmXIIj83xoUb-Qw4sFfKWpf7-j6Lshn95lIPkdx_i1zTeyRA6Y2hG2700UwUy_8olhPlTN4uZeZInTZpzjaPyJBNallo3f-fOtKmQvY5ls_mRmT-g7IitLlh-3xhvXBtqgmNkuwJmngg6utz21Rnwnv8LbLd7Uoz-Gv1Y7x2FXFGHTlsLh2R-kwzxRl4N-u1fx9kusgb4RBXO6-s1_1E9Ks800OrqbqQXeHVxi0hgYh8sxDG7fKFeikMKm3u19rm9VBCtOvSfyxTVSDeEft-dOdgQ0m_D53CW9x5ZxVhvpP_We_-5TddhlTUMNPvw"
],
"value": "cxhf2-55pxsMhsq7aMwiuLQAoUFUUF0lX5G91v-E_srnrJ2h96QvNll4LXV5lm3Z4t80tL3tzsj7TwzGBWEqvw"
}
}
The example above would if converted to
RFC7515 be slightly more convoluted since data must be Base64-encoded (which was a core rationale for developing JSF). Some protocols using
RFC7515 even add an
extra outer object and property to make the message type readable. This is unessesary using JSF because it only manifests itself as a property among other properties in a message. Anyway, here is the sample message using
RFC7515 notation:
{
"payload": "eyJAY29udGV4dCI6Imh0dHBzOi8vanNvbi5zYW1wbGUtc3RhbmRhcmRzLm9yZy9wYXltZW50IiwiQHF1YWxpZmllciI6IkF1dGhvcml6YXRpb24iLCJwYXltZW50UmVxdWVzdCI6eyJwYXlsb2FkIjoiZXlKQVkyOXVkR1Y0ZENJNkltaDBkSEJ6T2k4dmFuTnZiaTV6WVcxd2JHVXRjM1JoYm1SaGNtUnpMbTl5Wnk5d1lYbHRaVzUwSWl3aVFIRjFZV3hwWm1sbGNpSTZJbEJoZVcxbGJuUlNaWEYxWlhOMElpd2ljR0Y1WldVaU9uc2lZMjl0Ylc5dVRtRnRaU0k2SWtSbGJXOGdUV1Z5WTJoaGJuUWlMQ0pvYjIxbFVHRm5aU0k2SW1oMGRIQnpPaTh2WkdWdGIyMWxjbU5vWVc1MExtTnZiU0o5TENKaGJXOTFiblFpT2lJeU16VXVOVEFpTENKamRYSnlaVzVqZVNJNklsVlRSQ0lzSW5KbFptVnlaVzVqWlVsa0lqb2lNRFUyTXpBM05UTWlMQ0owYVcxbFUzUmhiWEFpT2lJeU1ERTVMVEE0TFRBMVZERXdPakEzT2pBd1dpSjkiLCJwcm90ZWN0ZWQiOiJleUpoYkdjaU9pSkZVekkxTmlJc0ltcDNheUk2ZXlKcmRIa2lPaUpGUXlJc0ltTnlkaUk2SWxBdE1qVTJJaXdpZUNJNkluSmFNelEwWVdsVVlVOUJWRzFNUWs5a1psbFVhSFp1VVhWZmVubENNV0ZLV25KaVltSnJjekpRT1VraUxDSjVJam9pYkV0UGRtWktaR2RPT0ZkeFJXSllUVVJaVUZKVFRYTlFhV050TUZSck1UQndiV1Z5T1V4NGRuaE1aeUo5ZlEiLCJzaWduYXR1cmUiOiJ1Z1huVnc3RUd4V2lJbFcyT3B4WGtwUEJ4eVlvV0I2MWYtaWlYTnFEOWxTcDN1ZjkwM2loSm42UFZfOHAtSm00bEZ6SllGRzRtRjZELU1sSnlCWVV6ZyJ9LCJ0cmFuc2FjdGlvbklkIjoiIzEyNTAwMDAwMDUiLCJ0aW1lU3RhbXAiOiIyMDE5LTAyLTAyVDEwOjA3OjQyWiJ9",
"protected": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlCdFRDQ0FWbWdBd0lCQWdJR0FWUTB5bEZQTUF3R0NDcUdTTTQ5QkFNQ0JRQXdMekVMTUFrR0ExVUVCaE1DUlZVeElEQWVCZ05WQkFNVEYxQmhlVzFsYm5RZ1RtVjBkMjl5YXlCVGRXSWdRMEV6TUI0WERURTBNREV3TVRBd01EQXdNRm9YRFRJd01EY3hNREE1TlRrMU9Wb3dNVEVMTUFrR0ExVUVCaE1DUkVVeER6QU5CZ05WQkFVVEJqZzVOalkwTURFUk1BOEdBMVVFQXhNSVFtbG5JRUpoYm1zd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFUNVd2eGFUZktDM2tuYjhuZEh4T3RGcHI0QlpidG1KZHJxclUvc1F1enFCMWJuT3M5MW9tZDdZRjAxNzFPaGVhbllvbUhqMW5sQ05hdlU4Zk44a2czRG8xMHdXekFKQmdOVkhSTUVBakFBTUE0R0ExVWREd0VCL3dRRUF3SUhnREFkQmdOVkhRNEVGZ1FVSmk0RFlhTmZDWXJQSS9KMWVZS3dZVDJLQW9Bd0h3WURWUjBqQkJnd0ZvQVVzVW02VlNWbWthUWpNZ3FQREN6WDA2dnp6UFl3REFZSUtvWkl6ajBFQXdJRkFBTklBREJGQWlFQXFkR3NmVm5kVmR3emZXc2wrRE9iSmxiOFFPQy95UkJKYjRRai9BVFVydGNDSUhlci95dWNBNUNIMGJDd1lYM2kycjY3aUcvTXNBcGlEM2pGbnFhSmh4Q1oiLCJNSUlEY2pDQ0FWcWdBd0lCQWdJQkF6QU5CZ2txaGtpRzl3MEJBUTBGQURBd01Rc3dDUVlEVlFRR0V3SlZVekVoTUI4R0ExVUVBeE1ZVUdGNWJXVnVkQ0JPWlhSM2IzSnJJRkp2YjNRZ1EwRXhNQjRYRFRFeU1EY3hNREV3TURBd01Gb1hEVEkxTURjeE1EQTVOVGsxT1Zvd0x6RUxNQWtHQTFVRUJoTUNSVlV4SURBZUJnTlZCQU1URjFCaGVXMWxiblFnVG1WMGQyOXlheUJUZFdJZ1EwRXpNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVZYlovYndzbWNiNWc4Vkt2a0pYZVdlZDI4THMyN0ppMTJRMVFlUXZSOW0vT0ZXM2F4MWVPQ1dDRE14QzBwZGNJRXU3b1JpekVFamZCRXRoRWZUSm5SS05qTUdFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBT0JnTlZIUThCQWY4RUJBTUNBUVl3SFFZRFZSME9CQllFRkxGSnVsVWxacEdrSXpJS2p3d3MxOU9yODh6Mk1COEdBMVVkSXdRWU1CYUFGQjhDVzFIVUloRFVjYzN2WWhZQW5UR1huTTVNTUEwR0NTcUdTSWIzRFFFQkRRVUFBNElDQVFCalRxOFhhNnlKZHFRM21sMGxzYXo4UkRnVnI2bFpiQmIrQWVCZWVSRDlaM0x4UlZpL2gxRXl0T2k1V0d3RTFBcmdML3MzRStIV2oxa2hCVHpwMnhoazN1REJDbnpneXhRTTNubEJ0eTRMSldXd2plYS9KaHJtbEVxOSsreW9VYldBYnpkcW93TkZlTjJTa3MwTW40UG5jaklzekdCdmxyVnJHTzNZU0hNZzZnb05kNGNGOGRLYk84S3JZb0l0QXl3M3c3WEJQUjc3czBSL0F4Y3RQc2JRZVRZTTk4RjJZck40ZnF0azY3RU4xWExZdXdqTDJCOG9lTWVjYjVjN2h6VzRBTmpTOTBuaytMV25CTExHWklnRDJxMktPQUNnN2NaUENNd3BpaU5kcHAxNk5HbGZ1bGNoNFl1bzhVTVk2ZGtBN2VXUUp6NXpBMUttZnNLeTZPenFSMklad3hONWtZVVRjVngydVNpMWdWSzYzeG1YSUlqODN4b1ViK1F3NHNGZktXcGY3K2o2THNobjk1bElQa2R4L2kxelRleVJBNlkyaEcyNzAwVXdVeS84b2xoUGxUTjR1WmVaSW5UWnB6amFQeUpCTmFsbG8zZitmT3RLbVF2WTVscy9tUm1UK2c3SWl0TGxoKzN4aHZYQnRxZ21Oa3V3Sm1uZ2c2dXR6MjFSbndudjhMYkxkN1VveitHdjFZN3gyRlhGR0hUbHNMaDJSK2t3enhSbDROK3UxZng5a3VzZ2I0UkJYTzYrczEvMUU5S3M4MDBPcnFicVFYZUhWeGkwaGdZaDhzeERHN2ZLRmVpa01LbTN1MTlybTlWQkN0T3ZTZnl4VFZTRGVFZnQrZE9kZ1EwbS9ENTNDVzl4NVp4Vmh2cFAvV2UvKzVUZGRobFRVTU5Qdnc9PSJdfQ",
"signature": "6f0hVFwUG_k8npaDcfS56arT-xQ0AG50simGCFTrIr85vZiJHRcZK51ebm6ZgaNzBP619Ok-yMGaU4hKeXlgQg"
}
Since
JSF is compatible with
ECMAScript (JavaScript), you can also use JSF signatures in browsers. The following shows how the
PaymentRequest
message could be featured inside of an HTML5 document:
var paymentRequest = {
// The Data
"@context": "https://json.sample-standards.org/payment",
"@qualifier": "PaymentRequest",
payee: {
commonName: "Demo Merchant",
homePage: "https://demomerchant.com"
},
amount: "235.50",
currency: "USD",
referenceId: "05630753",
timeStamp: "2019-08-05T10:07:00Z",
// The Signature
signature: {
algorithm: "ES256",
publicKey: {
kty: "EC",
crv: "P-256",
x: "rZ344aiTaOATmLBOdfYThvnQu_zyB1aJZrbbbks2P9I",
y: "lKOvfJdgN8WqEbXMDYPRSMsPicm0Tk10pmer9LxvxLg"
},
value: "x4SCpvutYjDAu0AGuiLHOZcGxWR2Od4Yc3luwlQl2cqjm7wwfrHYX9EdjkZGORCAVr8h4nG02B27DqWBMs9Tig"
}
};
Although just an example,
YASMIN represents a workable way for using JSF signatures in Web applications.
V0.92, A.Rundgren, 2019-12-20