Wiki - 2.0 Signing Messages

Compatibility

Objective

Prerequisites

Component Format Description
private-key.pem PKCS#1 🔑 Private key used for signing
digital-certificate.txt x509 🔒 Trusted, intermediate certificate*

Steps

  1. Generate an Intermediate Certificate (digital-certificate.txt).
  2. Edit qz.security.setCertificatePromise() to use your Intermediate Certificate.
  3. Edit qz.security.setSignaturePromise() to use your server-side signing method.
  4. Edit sign-message.php to sign print requests with your private key.
    Examples in other languages can be find in demo/assets/signing of QZ Tray.


Loading the Intermediate Certificate

A sample certificate chain is provided with the demo, labeled as "localhost". This will display a trusted message on load of the page.

  1. Edit the setCertificatePromise() provided in the sample.html file.
  2. Replace the "localhost" certificate chain with your Intermediate Certificate by changing the $.ajax(...) line to match the address of the certificate.

    The Intermediate Certificate generated by QZ Industries, LLC is digital-certificate.txt

    qz.security.setCertificatePromise(function(resolve, reject) {
       $.ajax("assets/signing/digital-certificate.txt").then(resolve, reject);
    });

    Note: $.ajax is a jQuery function and can be replaced with any ajax library of choice (xhr, PageMethods, etc).

    Note: If the certificate has changed, appending a question mark to the URL will force refresh of the cache. e.g. assets/signing/digital-certificate.txt?foo.

Supplying the Signature

The function setSignaturePromise() is used for proving a JavaScript callback method for signing each privileged method to prevent anonymous printing. This is a security measure to ensure the identity of websites can be verified by the software.

These methods are invoked on any privileged function, which includes finding attached devices, printing, or sending/reading data from a USB or serial device.

GET Method:

Change the $.ajax(...) line to match the address of your php file.

qz.security.setSignaturePromise(function(toSign) {
   return function(resolve, reject) {
      $.ajax("assets/signing/sign-message.php?request=" + toSign).then(resolve, reject);
   };
});

POST Method:

qz.security.setSignaturePromise(function(toSign) {
   return function(resolve, reject) {
      $.post("assets/signing/sign-message.php", {request: toSign}).then(resolve, reject);
   };
});

.NET PageMethods

.NET conveniently exposes a promise-friendly PageMethods object which is capable of calling a server-side .NET function by name directly from JavaScript. This assumes a server-side signing example has already been setup in C#, VB.NET, etc.

qz.security.setSignaturePromise(function (toSign) {
   return function (resolve, reject) {
      PageMethods.SignMessage(toSign, resolve, reject); 
   };
});

Server-side Signing Method

A server-side signing method must be used in combination with the AJAX call. This signing will happen with your company's private key.

Trusted websites with a valid public key chain pair and a properly configured qz.security.setSignaturePromise AJAX function will unlock QZ Tray's ability to communicate silently (print, read serial ports, usb devices, etc). Non-signed requests (Untrusted websites) will continue to show a warning dialog.

In this example we go over how to accomplish this in php by editing the sign-message.php file that is provided with the software (demo/assets/signing/sign-message.php). Examples in other languages including: Ruby, Python, JavaScript, C#, J#, Java, ASP and VB can be found here.

  1. Change the line $KEY = 'private-key.pem'; to match the name of your private key

    • $PASS = ' ' is not needed if the private key file is not password protected.
    • Make sure to delete $PASS out of the line $privateKey = openssl_get_privatekey(file_get_contents($KEY), $PASS); if not password protected.
  2. Make sure to edit this line: $req = $_GET['request']; appropriately to edit the method you are using in the AJAX call (GET or POST)

    <?php
    // #########################################################
    // #                     PHP Signing                       #
    // #########################################################
    // Sample key.  Replace with one used for CSR generation
    $KEY = 'private-key.pem';
    $PASS = 'S3cur3P@ssw0rd'; //Comment out/delete if the private key is not password protected
    
    $req = $_GET['request']; //GET method
    //$req = $_POST['request']; //POST method
    $privateKey = openssl_get_privatekey(file_get_contents($KEY), $PASS); //use syntax below if file is not password protected
    //$privateKey = openssl_get_privatekey(file_get_contents($KEY));
    
    $signature = null;
    openssl_sign($req, $signature, $privateKey);
    
    if ($signature) {
      header("Content-type: text/plain");
      echo base64_encode($signature);
      exit(0);
    }
    
    echo '<h1>Error signing message</h1>';
    exit(1);
    ?>
  3. If these changes have been done correctly, you will be able to suppress this dialog box:

    image

    This will no longer come from an untrusted source.

    image

    The new certificate should look similar to this (trusted, valid, fingerprint, and contains your information):

    image


Advanced

To override the Trusted Root certificate:

Edit this page