Wiki - Signing

Compatibility

Objective

Prerequisites

Component Format Description
private-key.pem PKCS#8 🔑 Private key used for signing (generated once, contact support@qz.io if missing)
private-key.pfx PKCS#12 🔑 Optionally replaces .pem file for .NET environments
digital-certificate.txt x509 🔒 Trusted certificate*

Steps

  1. Generate a Trusted Certificate (digital-certificate.txt).
  2. Edit qz.security.setCertificatePromise() to use your Trusted Certificate.
  3. Add qz.security.setSignatureAlgorithm("SHA512"); to use use SHA512 (or SHA256, SHA1, etc)
  4. Edit qz.security.setSignaturePromise() to use your server-side signing method.
  5. 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 Trusted 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 Trusted Certificate by changing the fetch(...) line to match the address of the certificate.

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

    qz.security.setCertificatePromise(function(resolve, reject) {
       fetch("assets/signing/digital-certificate.txt", {cache: 'no-store', headers: {'Content-Type': 'text/plain'}})
          .then(function(data) { data.ok ? resolve(data.text()) : reject(data.text()); });
    });

    Note: fetch() can be replaced with any ajax library of choice ($.ajax(), xhr, PageMethods, etc).

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 fetch(...) line to match the address of your php file.

qz.security.setSignatureAlgorithm("SHA512"); // Since 2.1
qz.security.setSignaturePromise(function(toSign) {
   return function(resolve, reject) {
      fetch("/secure/url/for/sign-message?request=" + toSign, {cache: 'no-store', headers: {'Content-Type': 'text/plain'}})
         .then(function(data) { data.ok ? resolve(data.text()) : reject(data.text()); });
   };
});

POST Method:

qz.security.setSignatureAlgorithm("SHA512"); // Since 2.1
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.setSignatureAlgorithm("SHA512"); // Since 2.1
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

  2. Edit the line: $req = $_GET['request']; appropriate ly 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';
    
    $req = $_GET['request']; //GET method
    //$req = $_POST['request']; //POST method
    
    $privateKey = openssl_get_privatekey(file_get_contents($KEY));
    
    $signature = null;
    openssl_sign($req, $signature, $privateKey, "sha512"); // Use "sha1" for QZ Tray 2.0 and older
    
    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