twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

verify.js (3088B)


      1 // Copyright 2015 Joyent, Inc.
      2 
      3 var assert = require('assert-plus');
      4 var crypto = require('crypto');
      5 var sshpk = require('sshpk');
      6 var utils = require('./utils');
      7 
      8 var HASH_ALGOS = utils.HASH_ALGOS;
      9 var PK_ALGOS = utils.PK_ALGOS;
     10 var InvalidAlgorithmError = utils.InvalidAlgorithmError;
     11 var HttpSignatureError = utils.HttpSignatureError;
     12 var validateAlgorithm = utils.validateAlgorithm;
     13 
     14 ///--- Exported API
     15 
     16 module.exports = {
     17   /**
     18    * Verify RSA/DSA signature against public key.  You are expected to pass in
     19    * an object that was returned from `parse()`.
     20    *
     21    * @param {Object} parsedSignature the object you got from `parse`.
     22    * @param {String} pubkey RSA/DSA private key PEM.
     23    * @return {Boolean} true if valid, false otherwise.
     24    * @throws {TypeError} if you pass in bad arguments.
     25    * @throws {InvalidAlgorithmError}
     26    */
     27   verifySignature: function verifySignature(parsedSignature, pubkey) {
     28     assert.object(parsedSignature, 'parsedSignature');
     29     if (typeof (pubkey) === 'string' || Buffer.isBuffer(pubkey))
     30       pubkey = sshpk.parseKey(pubkey);
     31     assert.ok(sshpk.Key.isKey(pubkey, [1, 1]), 'pubkey must be a sshpk.Key');
     32 
     33     var alg = validateAlgorithm(parsedSignature.algorithm);
     34     if (alg[0] === 'hmac' || alg[0] !== pubkey.type)
     35       return (false);
     36 
     37     var v = pubkey.createVerify(alg[1]);
     38     v.update(parsedSignature.signingString);
     39     return (v.verify(parsedSignature.params.signature, 'base64'));
     40   },
     41 
     42   /**
     43    * Verify HMAC against shared secret.  You are expected to pass in an object
     44    * that was returned from `parse()`.
     45    *
     46    * @param {Object} parsedSignature the object you got from `parse`.
     47    * @param {String} secret HMAC shared secret.
     48    * @return {Boolean} true if valid, false otherwise.
     49    * @throws {TypeError} if you pass in bad arguments.
     50    * @throws {InvalidAlgorithmError}
     51    */
     52   verifyHMAC: function verifyHMAC(parsedSignature, secret) {
     53     assert.object(parsedSignature, 'parsedHMAC');
     54     assert.string(secret, 'secret');
     55 
     56     var alg = validateAlgorithm(parsedSignature.algorithm);
     57     if (alg[0] !== 'hmac')
     58       return (false);
     59 
     60     var hashAlg = alg[1].toUpperCase();
     61 
     62     var hmac = crypto.createHmac(hashAlg, secret);
     63     hmac.update(parsedSignature.signingString);
     64 
     65     /*
     66      * Now double-hash to avoid leaking timing information - there's
     67      * no easy constant-time compare in JS, so we use this approach
     68      * instead. See for more info:
     69      * https://www.isecpartners.com/blog/2011/february/double-hmac-
     70      * verification.aspx
     71      */
     72     var h1 = crypto.createHmac(hashAlg, secret);
     73     h1.update(hmac.digest());
     74     h1 = h1.digest();
     75     var h2 = crypto.createHmac(hashAlg, secret);
     76     h2.update(new Buffer(parsedSignature.params.signature, 'base64'));
     77     h2 = h2.digest();
     78 
     79     /* Node 0.8 returns strings from .digest(). */
     80     if (typeof (h1) === 'string')
     81       return (h1 === h2);
     82     /* And node 0.10 lacks the .equals() method on Buffers. */
     83     if (Buffer.isBuffer(h1) && !h1.equals)
     84       return (h1.toString('binary') === h2.toString('binary'));
     85 
     86     return (h1.equals(h2));
     87   }
     88 };