UNPKG

undersign

Version:

Create eIDAS compatible XAdES digital signatures with certificate OCSP responses and timestamps. Works with the Estonian Id-card and Mobile-Id to create BDOCs, but isn't limited to Estonia.

112 lines (92 loc) 3.65 kB
var _ = require("../lib/underscore") var Fs = require("fs") var Mime = require("mime") var Tsl = require("../lib/tsl") var Xades = require("../xades") var Neodoc = require("neodoc") var MobileId = require("../lib/mobile_id") var MobileIdError = require("../lib/mobile_id").MobileIdError var Certificate = require("../lib/certificate") var Ocsp = require("../lib/ocsp") var Timestamp = require("../lib/timestamp") var digest = require("../lib/x509_asn").digest var co = require("co") var sha256 = require("../lib/crypto").hash.bind(null, "sha256") var sha256Stream = require("../lib/crypto").hashStream.bind(null, "sha256") var USAGE_TEXT = ` Usage: hades mobile-id-sign (-h | --help) hades mobile-id-sign [options] <file> Options: -h, --help Display this help and exit. -p, --phone=X Phone number. -i, --id=X Personal id number. --tsl=FILE Use given Trust Service List. --issuer=PATH Explicit issuer certificate if TSL unavailable. --ocsp-url=URL URL for the OCSP server. --mobile-id-user=NAME Username (relying party name) for Mobile Id. --mobile-id-password=UUID Password (relying party UUID) for Mobile Id. --timemark Get the Estonian BDOC's timemark with OCSP. --timestamp Get a timestamp on the signature. --timestamp-url=URL URL for the timestamp server. `.trimLeft() module.exports = _.compose(errorify, co.wrap(function*(argv) { var args = Neodoc.run(USAGE_TEXT, {argv: argv}) if (args["--help"]) return void process.stdout.write(USAGE_TEXT) var path = args["<file>"] if (path == null) return void process.stdout.write(USAGE_TEXT) var mobileId = args["--mobile-id-user"] ? new MobileId({ user: args["--mobile-id-user"], password: args["--mobile-id-password"] }) : MobileId.demo var phoneNumber = args["--phone"] var personalId = args["--id"] var tslPath = args["--tsl"] var issuerPath = args["--issuer"] if (!(tslPath || issuerPath)) throw new Error("Pass either --tsl or <issuer-certificate>") var cert = yield mobileId.readCertificate(phoneNumber, personalId) var tsl = tslPath && Tsl.parse(Fs.readFileSync(tslPath)) var issuer = issuerPath && Certificate.parse(Fs.readFileSync(issuerPath)) if (issuer == null) issuer = tsl.certificates.getIssuer(cert) if (issuer == null) throw new Error( "Can't find issuer: " + cert.issuerDistinguishedName.join(", ") ) var xades = new Xades(cert, [{ path: path, type: Mime.lookup(path), hash: yield sha256Stream(Fs.createReadStream(path)) }], {policy: args["--timemark"] ? "bdoc" : null}) console.warn( "Confirmation code: " + serializeConfirmation(xades.signableHash) ) var sessionId = yield mobileId.sign( phoneNumber, personalId, xades.signableHash ) var signature = yield mobileId.waitForSignature(sessionId) xades.setSignature(signature) if (args["--timestamp"]) xades.setTimestamp(yield Timestamp.request( args["--timestamp-url"], sha256(xades.signatureElement) ).then(Timestamp.parse)) xades.setOcspResponse(yield Ocsp.request(issuer, cert, { url: args["--ocsp-url"], nonce: args["--timemark"] ? digest("sha1", Buffer.from(signature, "base64")) : null }).then(Ocsp.parse)) console.log(xades.toString()) })) function errorify(res) { return res.catch(function(err) { if (err instanceof MobileIdError) { process.exitCode = 3 console.error("Mobile-Id Error: %s: %s", err.code, err.message) } else throw err }) } function serializeConfirmation(signableHash) { return ("000" + MobileId.confirmation(signableHash)).slice(-4) }