Skip to content
This repository was archived by the owner on Dec 10, 2018. It is now read-only.

2.0 Signing Messages

Tres Finocchiaro edited this page Feb 9, 2016 · 27 revisions

Compatibility

  • ✅ 2.0 | ⛔ 1.9 | ...

Objective

  • Use an Intermediate Certificate (digital-certificate.txt) and a private key (private-key.pem) to achieve silent printing.

Prerequisites

Component Description
private-key.pem 🔑 Private key used for signing
digital-certificate.txt 🔒 Trusted, intermediate certificate

Note: To override the Trusted Root certificate, launch QZ Tray using java -DtrustedRootCert=MyRootCA.crt -jar qz-tray.jar.

  • A language capable of reading an RSA private key and generating an SHA1 base64 encoded signature hash.
  • Signing examples are available here: assets/signing

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.
  • Note: Your public-key.txt is not needed for signing. Store your public-key.txt securely as you will need it for generating a new Intermediate Certificate when it expires.

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);
});

Supplying the Signature

A new setSignaturePromise() has been added to the software to prevent anonymous printing. This is a security measure to ensure the identity of websites can be verified by the software.

  • Note: Print jobs are sent to the server as GET and if the print job is larger than a URI can fit, then it should be POST-ed (generally has no size limit)
  • Note: GET will also truncate all data after a # hash mark, so findPrinter('foo#') won't work unless the code is switched from GET to POST

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.

  • This private key MUST be 2048-bit
  • If generated by QZ Industries, LLC the file name will be private-key.pem

Trusted websites with a valid public key chain pair and a properly configured qz.security.setSignaturePromise AJAX function will automatically print to QZ Tray. 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.
  1. Make sure to edit this line: $req = $_GET['request']; appropriately to edit the method you are using in the AJAX call (GET or POST)

Error signing message'; exit(1); ?>

1. If these changes have been done correctly, you will be able to suppress this dialog box:

 ![image](https://cloud.githubusercontent.com/assets/12505463/8151249/1a16ce4a-12d6-11e5-821e-052513345e71.png)

 This will no longer come from an untrusted source. 

 ![image](https://cloud.githubusercontent.com/assets/12505463/8245927/d6e8da60-1603-11e5-9f7b-27f6650b5d5f.png)

 The new certificate should look similar to this (trusted, valid, and has a fingerprint):

 ![image](https://cloud.githubusercontent.com/assets/12505463/8245953/312f15c0-1604-11e5-8f24-d65a5b4d2119.png)

Clone this wiki locally