From a3456b29413f888e4d3589d8ce218386525e6008 Mon Sep 17 00:00:00 2001 From: antelle Date: Mon, 12 Jun 2017 00:33:50 +0200 Subject: [PATCH] read code signing private key from smartcard --- grunt/lib/sign.js | 2 + grunt/tasks/grunt-sign-exe.js | 80 +++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/grunt/lib/sign.js b/grunt/lib/sign.js index 25a92be8..4293412e 100644 --- a/grunt/lib/sign.js +++ b/grunt/lib/sign.js @@ -29,3 +29,5 @@ module.exports = function sign(grunt, data) { throw err; }); }; + +module.exports.getPin = getPin; diff --git a/grunt/tasks/grunt-sign-exe.js b/grunt/tasks/grunt-sign-exe.js index 5f9f2c7f..bf08fe40 100644 --- a/grunt/tasks/grunt-sign-exe.js +++ b/grunt/tasks/grunt-sign-exe.js @@ -1,34 +1,69 @@ -// https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Signing_an_executable_with_Authenticode +/** + * This will require the latest (unreleased) version of `osslsigncode` with pkcs11 patch + * Build it like this: + * + * curl -L http://sourceforge.net/projects/osslsigncode/files/osslsigncode/osslsigncode-1.7.1.tar.gz/download -o osslsigncode.tar.gz + * tar -zxvf osslsigncode.tar.gz + * git clone https://git.code.sf.net/p/osslsigncode/osslsigncode osslsigncode-master + * cp osslsigncode-master/osslsigncode.c osslsigncode-1.7.1/osslsigncode.c + * rm osslsigncode.tar.gz + * rm -rf osslsigncode-master + * cd osslsigncode-1.7.1/ + * export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig + * ./configure + * make + * sudo cp osslsigncode /usr/local/bin/osslsigncode + * + * Install this: + * brew install opensc + * brew install engine_pkcs11 + * + * https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Signing_an_executable_with_Authenticode + */ const fs = require('fs'); module.exports = function (grunt) { - grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', function () { - const keytar = require('keytar'); + grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', async function () { const opt = this.options(); const done = this.async(); - keytar.getPassword(opt.keytarPasswordService, opt.keytarPasswordAccount).then(password => { - if (!password) { - return grunt.warn('Code sign password not found'); + if (opt.pvk) { + const keytar = require('keytar'); + keytar.getPassword(opt.keytarPasswordService, opt.keytarPasswordAccount).then(password => { + if (!password) { + return grunt.warn('Code sign password not found'); + } + const promises = Object.keys(opt.files).map(file => signFile(file, opt.files[file], opt, password)); + Promise.all(promises).then(done); + }).catch(e => { + grunt.warn('Code sign error: ' + e); + }); + } else { + const sign = require('../lib/sign'); + const pin = await sign.getPin(); + for (const file of Object.keys(opt.files)) { + await signFile(file, opt.files[file], opt, pin); } - const promises = Object.keys(opt.files).map(file => signFile(file, opt.files[file], opt, password)); - Promise.all(promises).then(done); - }).catch(e => { - grunt.warn('Code sign error: ' + e); - }); + done(); + } }); function signFile(file, name, opt, password) { const signedFile = file + '.sign'; return new Promise((resolve, reject) => { + const pkcsArgs = opt.pvk ? [] : [ + '-pkcs11engine', '/usr/local/lib/engines/engine_pkcs11.so', + '-pkcs11module', '/usr/local/lib/opensc-pkcs11.so' + ]; const args = [ '-spc', opt.spc, - '-key', require('path').resolve(opt.pvk), + '-key', opt.pvk ? require('path').resolve(opt.pvk) : opt.key, + '-pass', password, '-h', opt.algo, '-n', name, '-i', opt.url, '-t', 'http://timestamp.verisign.com/scripts/timstamp.dll', - '-pass', password, + ...pkcsArgs, '-in', file, '-out', signedFile ]; @@ -41,11 +76,20 @@ module.exports = function (grunt) { grunt.warn(`Cannot sign file ${file}, signtool error ${code}: ${error}`); return reject(); } - if (fs.existsSync(file)) { - fs.renameSync(signedFile, file); - } - grunt.log.writeln(`Signed: ${file}: ${name}`); - resolve(); + grunt.util.spawn({ + cmd: 'osslsigncode', + args: ['verify', signedFile] + }, (ex, result, code) => { + if (code) { + grunt.warn(`Verify error ${file}: \n${result.stdout.toString()}`); + return; + } + if (fs.existsSync(file)) { + fs.renameSync(signedFile, file); + } + grunt.log.writeln(`Signed ${file}: ${name}`); + resolve(); + }); }); // spawned.stdout.pipe(process.stdout); spawned.stderr.pipe(process.stderr);