Skip to content

cyberphone/node-webpki.org

Repository files navigation

JSF and JEF for "node.js"

JSF (JSON Signature Format) specification: https://cyberphone.github.io/doc/security/jsf.html
JEF (JSON Encryption Format) specification: https://cyberphone.github.io/doc/security/jef.html

CURRENTLY ONLY FOR INTERNAL USE!!!

Installation

There is no npm yet but you can test this code anyway by downloading the zip https://github.com/cyberphone/node-webpki.org/archive/master.zip to a free directory and then perform three steps:

C:\node-webpki.org-master>mkdir node_modules
C:\node-webpki.org-master>mkdir node_modules\webpki.org
C:\node-webpki.org-master>copy package.json node_modules\webpki.org

Then you should be able to run the supplied demo and test programs:

C:\node-webpki.org-master>node democert.js
{"statement":"Hello signed world!", etc etc etc}
Validation success=true

Create a signed object

'use strict';

const Fs = require('fs');

const Keys = require('webpki.org').Keys;
const Jsf = require('webpki.org').Jsf;
const JsonUtil = require('webpki.org').JsonUtil;

function readPrivateKey(path) {
  return Keys.createPrivateKeyFromPem(Fs.readFileSync(__dirname + '/test/' + path));
}

// Load a private key in PKCS #8/PEM format
const privateKey = readPrivateKey('p256privatekey.pem');

// Initiate the signer
var signer = new Jsf.Signer(privateKey);

// Create an object to sign
var jsonObject = {'statement':'Hello signed world!'};

// Perform signing
var signedObject = signer.sign(jsonObject);

// Print it on the console as "pretty" (but legal) JSON.
console.log(JsonUtil.prettyPrint(signedObject));

Resulting JSON string

{
  "statement": "Hello signed world!",
  "signature": {
    "algorithm": "ES256",
    "publicKey": {
      "kty": "EC",
      "crv": "P-256",
      "x": "censDzcMEkgiePz6DXB7cDuwFemshAFR90UNVQFCg8Q",
      "y": "xq8rze6ewG0-eVcSF72J77gKiD0IHnzpwHaU7t6nVeY"
    },
    "value": "9JV3WcUU5SmV0v3mVXZubOpRE5bgjOVaPFBnw6ZcRMN8A7bYHt8U7F9qYVd9ZDiSDZRPEhCDSGnDeB6VZ7wnVA"
  }
}

Validate a signature

// Now we could verify the signed object we just created

function readPublicKey(path) {
  return Keys.createPublicKeyFromPem(Fs.readFileSync(__dirname + '/test/' + path));
}

// Load a matching public key
const publicKey = readPublicKey('p256publickey.pem');

// Create a verifier object
var verifier = new Jsf.Verifier();

// Call decoding.  This will check that the signature is technically correct
var result = verifier.decodeSignature(signedObject);

// Now check if the anticipated key was used as well
result.verifyPublicKey(publicKey);

// If we got here all is good...
console.log('Validation successful!');

Using Certificates

Creating signatures with certificate paths is almost identical to signatures only using public keys. You simply need to add the path.

'use strict';

const Fs = require('fs');

const Keys     = require('webpki.org').Keys;
const Jsf      = require('webpki.org').Jsf;
const JsonUtil = require('webpki.org').JsonUtil;

// Load private key and certificate path
const keyData = Fs.readFileSync(__dirname + '/test/mybank-cert-and-key-p256.pem');
const privateKey = Keys.createPrivateKeyFromPem(keyData);
const certificatePath = Keys.createCertificatesFromPem(keyData);

// Initiate the signer
var signer = new Jsf.Signer(privateKey);

// Indicate that we want to include a certificate path
signer.setCertificatePath(certificatePath, true);

// Create an object to sign
var jsonObject = {'statement':'Hello signed world!'};

// Perform signing
var signedJavaScript = signer.sign(jsonObject);

// Print it on the console as "pretty" (but legal) JSON.
console.log(JsonUtil.prettyPrint(signedJavaScript));

This sample would generate the following JSON:

{
  "statement": "Hello signed world!",
  "signature": {
    "algorithm": "ES256",
    "signerCertificate": {
      "issuer": "CN=Payment Network Sub CA3,C=EU",
      "serialNumber": "1441094164079",
      "subject": "CN=mybank.com,2.5.4.5=#130434353031,C=FR"
    },
    "certificatePath": [
      "MIIBtTCCAVmgAwIBAgIGAU-H595vMAwGCCqGSM49BAMCBQAwLzELMAkGA1UEBhMCRVUxIDAeBgNVBAMTF1BheW1lbnQgTmV0d29yayBTdWIgQ0EzMB4XDTE0MDEwMTAwMDAwMFoXDTIwMDcxMDA5NTk1OVowMTELMAkGA1UEBhMCRlIxDTALBgNVBAUTBDQ1MDExEzARBgNVBAMTCm15YmFuay5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASjhSNHJyRmQi5U-r7WkNns0D6b1n1gQybglCvyXgIA2RCSJXJKHZrw37giKmGqX-4cXU3x__zOQXN1U48VAwNvo10wWzAJBgNVHRMEAjAAMA4GA1UdDwEB_wQEAwIHgDAdBgNVHQ4EFgQUOdV3H3r6TufkQh-dqhcXMrjUY2kwHwYDVR0jBBgwFoAUy0fdXq1oJ6GFAJo10qx609KDARAwDAYIKoZIzj0EAwIFAANIADBFAiEAluqzuTTzVBG74AoALaWRsRn9QALg2N6C3sIlztm6sPoCID1ZnGnTrhz-CodxuGvg7fkOVfdffdSuEdyhQXemGtT4",
      "MIIDcjCCAVqgAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAwMQswCQYDVQQGEwJVUzEhMB8GA1UEAxMYUGF5bWVudCBOZXR3b3JrIFJvb3QgQ0ExMB4XDTEyMDcxMDEwMDAwMFoXDTI1MDcxMDA5NTk1OVowLzELMAkGA1UEBhMCRVUxIDAeBgNVBAMTF1BheW1lbnQgTmV0d29yayBTdWIgQ0EzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcX8CYrYFoQhPbTci93W5qyCx0i0H-FvmXIvH5XNBlnNLfPkRacqn0PRFNn4Z4o3BVxI3x5yob9C7FqpKslcCgKNjMGEwDwYDVR0TAQH_BAUwAwEB_zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMtH3V6taCehhQCaNdKsetPSgwEQMB8GA1UdIwQYMBaAFELvwS_Fk7IfHMWJeu-yhGdM-5EiMA0GCSqGSIb3DQEBDQUAA4ICAQBNQdIOSU2fB5JjCO9Q0mCfOxDXFihMKSiOanAJ_r2rxGN7Uprw32JPsJnQhuxbrwmniKgCmBVD6Jak4GtHSLVvJPjpf_Pe7pUbyMb6iNNeV3SmJvsHoE2m5WdSGxjIPxK4NOBv3Mm3Ib1_kxyVceegHEHRUk5IXyQUNV1sUsxIypELjC8bAIvnMj_J1FlP8nsfehbibT3XH04uvX9dgNGexpz8BDLa0fEpLzrKoyMtUbSwg88_WsdPnkvp1fhiwCF9GpIHwsXi3Nv-Wdgdyn-hKFQe6sP2FmsPDiI2qWqX7fEs0VN5Uo2oI5Q2T6673JiZnkycXYLNIRpc06KSTcs8B45u5NMAyvLx3l4S8My-HK4nfiqbF3TPVGJkq4aXAAZnhVcQTrO71tQ0BJMibKjz6sylBEnhlFQs3ICcesaGVXV3JVbwtf_OkAUUUduYWOmUZU5ng3vNJV0ofqfvoNcBlVsrWpFNqImy2-icUxiad_8--ortiq4WG594Ap52CqXt7K8UcZaMLDAj2COOmo1gy9iUjzgyzSqnYye2Gqr72ts5jd8B8wkM1rM0JDM6DvCyJgHVvc8VTNE7Mt2Mu9XsofQkdLdDgrPuo6AV88g1BGk7cY0FJMJFoBAlrj98A4KslbeGBV7AUGuzvS-w1VA6dRH6_5Fv2eSHXW6pzA_D8Q"
    ],
    "value": "dBnkOuspGDc63aSWkXnXFPsdd2w8EpKl-01FbhO2v-oqVZ4JHUtHWP76qX04DqUJJWKy8Kw47jmKpAwkET2O0w"
  }
}

Validation of Certificate Paths

Validation requires that you provide a collection of CA certificates.

// Now we could verify the signed object we just created

// Load trust store
const trustedCAs = Keys.createCertificatesFromPem(Fs.readFileSync(__dirname + '/test/payment-network-ca.pem'));

// Create a verifier object
var verifier = new Jsf.Verifier();

// Call decoding.  This will check that the signature is technically correct
var result = verifier.decodeSignature(signedJavaScript);

// Now check if the certificate path is trusted
console.log('Validation success=' + result.verifyTrust(trustedCAs));

HMAC Signatures

'use strict';

const Jsf      = require('webpki.org').Jsf;
const JsonUtil = require('webpki.org').JsonUtil;

// Define a suitable secret key
var secretKey = new Buffer('F4C74F3398C49CF46D93EC9818832661A40BAE4D204D75503614102074346909', 'hex');

// Initiate the signer with key and algorithm.  Finally, add an (optional) keyId
var signer = new Jsf.Signer(secretKey, 'HS256').setKeyId('mykey');

// Create an object to sign
var jsonObject = {'statement':'Hello signed world!'};

// Perform signing
var signedJavaScript = signer.sign(jsonObject);

// Print it on the console as "pretty" (but legal) JSON.
console.log(JsonUtil.prettyPrint(signedJavaScript));

// Now we could verify the signed object we just created

// Create a verifier object
var verifier = new Jsf.Verifier();

// Call decoding.  This will check that the signature is technically correct
var result = verifier.decodeSignature(signedJavaScript);

// Now check the result
console.log('Validation success=' + result.verifyHmac(secretKey));

And here is the expected result:

{
  "statement": "Hello signed world!",
  "signature": {
    "algorithm": "HS256",
    "keyId": "mykey",
    "value": "IcC43Ecr11NPF01n6pj540OYvpVeUp3-wyxJ_cY_Yf4"
  }
}

About

Node.js library for creating and consuming JSON, JCS, JSF and JEF

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published