Exemple #1
0
function privateKeySigner(options) {
	mod_assert.object(options, 'options');
	if (typeof (options.key) !== 'string' &&
	    !Buffer.isBuffer(options.key)) {
		throw (new Error('options.key (a String or Buffer) is ' +
		    'required'));
	}
	mod_assert.string(options.user, 'options.user');
	mod_assert.optionalString(options.subuser, 'options.subuser');
	mod_assert.optionalString(options.keyId, 'options.keyId');

	var key = mod_sshpk.parsePrivateKey(options.key);
	var kp = KeyPair.fromPrivateKey(key);
	return (kp.createSign(options));
}
Exemple #2
0
 function RequestSigner(options) {
   assert.object(options, 'options');
   var alg = [];
   if (options.algorithm !== undefined) {
     assert.string(options.algorithm, 'options.algorithm');
     alg = validateAlgorithm(options.algorithm);
   }
   this.rs_alg = alg;
   if (options.sign !== undefined) {
     assert.func(options.sign, 'options.sign');
     this.rs_signFunc = options.sign;
   } else if (alg[0] === 'hmac' && options.key !== undefined) {
     assert.string(options.keyId, 'options.keyId');
     this.rs_keyId = options.keyId;
     if (typeof(options.key) !== 'string' && !Buffer.isBuffer(options.key))
       throw (new TypeError('options.key for HMAC must be a string or Buffer'));
     this.rs_signer = crypto.createHmac(alg[1].toUpperCase(), options.key);
     this.rs_signer.sign = function() {
       var digest = this.digest('base64');
       return ({
         hashAlgorithm: alg[1],
         toString: function() {
           return (digest);
         }
       });
     };
   } else if (options.key !== undefined) {
     var key = options.key;
     if (typeof(key) === 'string' || Buffer.isBuffer(key))
       key = sshpk.parsePrivateKey(key);
     assert.ok(sshpk.PrivateKey.isPrivateKey(key, [1, 2]), 'options.key must be a sshpk.PrivateKey');
     this.rs_key = key;
     assert.string(options.keyId, 'options.keyId');
     this.rs_keyId = options.keyId;
     if (!PK_ALGOS[key.type]) {
       throw (new InvalidAlgorithmError(key.type.toUpperCase() + ' type ' + 'keys are not supported'));
     }
     if (alg[0] !== undefined && key.type !== alg[0]) {
       throw (new InvalidAlgorithmError('options.key must be a ' + alg[0].toUpperCase() + ' key, was given a ' + key.type.toUpperCase() + ' key instead'));
     }
     this.rs_signer = key.createSign(alg[1]);
   } else {
     throw (new TypeError('options.sign (func) or options.key is required'));
   }
   this.rs_headers = [];
   this.rs_lines = [];
 }
test('defaults', function(t) {
  var req = http.request(httpOptions, function(res) {
    t.end();
  });
  req._stringToSign = null;
  t.ok(httpSignature.sign(req, signOptions));
  var authz = req.getHeader('Authorization');
  t.ok(authz);

  t.strictEqual(typeof (req._stringToSign), 'string');
  t.ok(req._stringToSign.match(/^date: [^\n]*$/));

  var key = sshpk.parsePrivateKey(rsaPrivate);
  var sig = key.createSign().update(req._stringToSign).sign();
  t.ok(authz.indexOf(sig.toString()) !== -1);

  console.log('> ' + authz);
  req.end();
});
test('with custom authorizationHeaderName', function(t) {
  var req = http.request(httpOptions, function(res) {
    t.end();
  });
  req._stringToSign = null;
  var opts = Object.create(signOptions);
  opts.authorizationHeaderName = 'x-auths';
  t.ok(httpSignature.sign(req, opts));
  var authz = req.getHeader('x-auths');
  t.ok(authz);

  t.strictEqual(typeof (req._stringToSign), 'string');
  t.ok(req._stringToSign.match(/^date: [^\n]*$/));

  var key = sshpk.parsePrivateKey(rsaPrivate);
  var sig = key.createSign().update(req._stringToSign).sign();
  t.ok(authz.indexOf(sig.toString()) !== -1);

  console.log('> ' + authz);
  req.end();
});
test('valid ecdsa', function(t) {
  server.tester = function(req, res) {
    var parsed = httpSignature.parseRequest(req);
    t.ok(httpSignature.verify(parsed, ecdsaPublic));

    res.writeHead(200);
    res.write(JSON.stringify(parsed, null, 2));
    res.end();
  };

  options.headers.Date = jsprim.rfc1123(new Date());
  var key = sshpk.parsePrivateKey(ecdsaPrivate);
  var signer = key.createSign('sha512');
  signer.update('date: ' + options.headers.Date);
  options.headers.Authorization =
    'Signature keyId="foo",algorithm="ecdsa-sha512",signature="' +
    signer.sign().toString() + '"';

  http.get(options, function(res) {
    t.equal(res.statusCode, 200);
    t.end();
  });
});
/* See createSigner() */
function RequestSigner(options) {
  assert.object(options, 'options');

  var alg = [];
  if (options.algorithm !== undefined) {
    assert.string(options.algorithm, 'options.algorithm');
    alg = validateAlgorithm(options.algorithm);
  }
  this.rs_alg = alg;

  /*
   * RequestSigners come in two varieties: ones with an rs_signFunc, and ones
   * with an rs_signer.
   *
   * rs_signFunc-based RequestSigners have to build up their entire signing
   * string within the rs_lines array and give it to rs_signFunc as a single
   * concat'd blob. rs_signer-based RequestSigners can add a line at a time to
   * their signing state by using rs_signer.update(), thus only needing to
   * buffer the hash function state and one line at a time.
   */
  if (options.sign !== undefined) {
    assert.func(options.sign, 'options.sign');
    this.rs_signFunc = options.sign;

  } else if (alg[0] === 'hmac' && options.key !== undefined) {
    assert.string(options.keyId, 'options.keyId');
    this.rs_keyId = options.keyId;

    if (typeof (options.key) !== 'string' && !Buffer.isBuffer(options.key))
      throw (new TypeError('options.key for HMAC must be a string or Buffer'));

    /*
     * Make an rs_signer for HMACs, not a rs_signFunc -- HMACs digest their
     * data in chunks rather than requiring it all to be given in one go
     * at the end, so they are more similar to signers than signFuncs.
     */
    this.rs_signer = crypto.createHmac(alg[1].toUpperCase(), options.key);
    this.rs_signer.sign = function () {
      var digest = this.digest('base64');
      return ({
        hashAlgorithm: alg[1],
        toString: function () { return (digest); }
      });
    };

  } else if (options.key !== undefined) {
    var key = options.key;
    if (typeof (key) === 'string' || Buffer.isBuffer(key))
      key = sshpk.parsePrivateKey(key);

    assert.ok(sshpk.PrivateKey.isPrivateKey(key, [1, 2]),
      'options.key must be a sshpk.PrivateKey');
    this.rs_key = key;

    assert.string(options.keyId, 'options.keyId');
    this.rs_keyId = options.keyId;

    if (!PK_ALGOS[key.type]) {
      throw (new InvalidAlgorithmError(key.type.toUpperCase() + ' type ' +
        'keys are not supported'));
    }

    if (alg[0] !== undefined && key.type !== alg[0]) {
      throw (new InvalidAlgorithmError('options.key must be a ' +
        alg[0].toUpperCase() + ' key, was given a ' +
        key.type.toUpperCase() + ' key instead'));
    }

    this.rs_signer = key.createSign(alg[1]);

  } else {
    throw (new TypeError('options.sign (func) or options.key is required'));
  }

  this.rs_headers = [];
  this.rs_lines = [];
}
  signRequest: function signRequest(request, options) {
    assert.object(request, 'request');
    assert.object(options, 'options');
    assert.optionalString(options.algorithm, 'options.algorithm');
    assert.string(options.keyId, 'options.keyId');
    assert.optionalArrayOfString(options.headers, 'options.headers');
    assert.optionalString(options.httpVersion, 'options.httpVersion');

    if (!request.getHeader('Date'))
      request.setHeader('Date', jsprim.rfc1123(new Date()));
    if (!options.headers)
      options.headers = ['date'];
    if (!options.httpVersion)
      options.httpVersion = '1.1';

    var alg = [];
    if (options.algorithm) {
      options.algorithm = options.algorithm.toLowerCase();
      alg = validateAlgorithm(options.algorithm);
    }

    var i;
    var stringToSign = '';
    for (i = 0; i < options.headers.length; i++) {
      if (typeof (options.headers[i]) !== 'string')
        throw new TypeError('options.headers must be an array of Strings');

      var h = options.headers[i].toLowerCase();

      if (h === 'request-line') {
        if (!options.strict) {
          /**
           * We allow headers from the older spec drafts if strict parsing isn't
           * specified in options.
           */
          stringToSign +=
            request.method + ' ' + request.path + ' HTTP/' +
            options.httpVersion;
        } else {
          /* Strict parsing doesn't allow older draft headers. */
          throw (new StrictParsingError('request-line is not a valid header ' +
            'with strict parsing enabled.'));
        }
      } else if (h === '(request-target)') {
        stringToSign +=
          '(request-target): ' + request.method.toLowerCase() + ' ' +
          request.path;
      } else {
        var value = request.getHeader(h);
        if (value === undefined || value === '') {
          throw new MissingHeaderError(h + ' was not in the request');
        }
        stringToSign += h + ': ' + value;
      }

      if ((i + 1) < options.headers.length)
        stringToSign += '\n';
    }

    /* This is just for unit tests. */
    if (request.hasOwnProperty('_stringToSign')) {
      request._stringToSign = stringToSign;
    }

    var signature;
    if (alg[0] === 'hmac') {
      if (typeof (options.key) !== 'string' && !Buffer.isBuffer(options.key))
        throw (new TypeError('options.key must be a string or Buffer'));

      var hmac = crypto.createHmac(alg[1].toUpperCase(), options.key);
      hmac.update(stringToSign);
      signature = hmac.digest('base64');

    } else {
      var key = options.key;
      if (typeof (key) === 'string' || Buffer.isBuffer(key))
        key = sshpk.parsePrivateKey(options.key);

      assert.ok(sshpk.PrivateKey.isPrivateKey(key, [1, 2]),
        'options.key must be a sshpk.PrivateKey');

      if (!PK_ALGOS[key.type]) {
        throw (new InvalidAlgorithmError(key.type.toUpperCase() + ' type ' +
          'keys are not supported'));
      }

      if (alg[0] !== undefined && key.type !== alg[0]) {
        throw (new InvalidAlgorithmError('options.key must be a ' +
          alg[0].toUpperCase() + ' key, was given a ' +
          key.type.toUpperCase() + ' key instead'));
      }

      var signer = key.createSign(alg[1]);
      signer.update(stringToSign);
      var sigObj = signer.sign();
      if (!HASH_ALGOS[sigObj.hashAlgorithm]) {
        throw (new InvalidAlgorithmError(sigObj.hashAlgorithm.toUpperCase() +
          ' is not a supported hash algorithm'));
      }
      options.algorithm = key.type + '-' + sigObj.hashAlgorithm;
      signature = sigObj.toString();
      assert.notStrictEqual(signature, '', 'empty signature produced');
    }

    request.setHeader('Authorization', sprintf(AUTHZ_FMT,
                                               options.keyId,
                                               options.algorithm,
                                               options.headers.join(' '),
                                               signature));

    return true;
  }
test('find keys and examples', function (t) {
	var i = 0;
	for (; i < doc.length; ++i)
		if (/^# Appendix A/.test(doc[i]))
			break;
	if (i >= doc.length)
		t.fail('could not find appendix A')

	var pubKeyLines = [];
	for (; i < doc.length; ++i)
		if (/-BEGIN PUBLIC KEY-/.test(doc[i]))
			break;
	for (; i < doc.length; ++i) {
		pubKeyLines.push(doc[i]);
		if (/-END PUBLIC KEY-/.test(doc[i]))
			break;
	}
	pubKey = sshpk.parseKey(pubKeyLines.
	    map(function (l) { return (l.replace(/^    /g, '')); }).
	    join('\n'));

	var privKeyLines = [];
	for (; i < doc.length; ++i)
		if (/-BEGIN RSA PRIVATE KEY-/.test(doc[i]))
			break;
	for (; i < doc.length; ++i) {
		privKeyLines.push(doc[i]);
		if (/-END RSA PRIVATE KEY-/.test(doc[i]))
			break;
	}
	privKey = sshpk.parsePrivateKey(privKeyLines.
	    map(function (l) { return (l.replace(/^    /g, '')); }).
	    join('\n'));

	var reqLines = [];
	for (; i < doc.length; ++i)
		if (doc[i] === '<!-- httpreq -->')
			break;
	for (++i; i < doc.length; ++i) {
		if (doc[i] === '<!-- /httpreq -->')
			break;
		reqLines.push(doc[i]);
	}
	httpReqData = reqLines.
	    map(function (l) { return (l.replace(/^    /g, '')); }).
	    join('\r\n');

	var thisConfig;
	var lines;
	do {
		thisConfig = {};
		for (; i < doc.length; ++i) {
			var m = doc[i].match(/^<!-- sign (.+) -->$/);
			if (m && m[1]) {
				thisConfig = JSON.parse(m[1]);
				break;
			}
		}

		for (; i < doc.length; ++i)
			if (doc[i] === '<!-- signstring -->')
				break;
		lines = [];
		for (++i; i < doc.length; ++i) {
			if (doc[i] === '<!-- /signstring -->')
				break;
			if (doc[i].length > 0)
				lines.push(doc[i]);
		}
		thisConfig.signString = lines.
		    map(function (l) { return (l.replace(/^    /g, '')); }).
		    join('\n');

		for (; i < doc.length; ++i)
			if (doc[i] === '<!-- authz -->')
				break;
		lines = [];
		for (++i; i < doc.length; ++i) {
			if (doc[i] === '<!-- /authz -->')
				break;
			if (doc[i].length > 0)
				lines.push(doc[i]);
		}
		thisConfig.authz = lines.
		    map(function (l) { return (l.replace(/^    /g, '')); }).
		    join('\n');

		if (thisConfig.name)
			signs.push(thisConfig);

	} while (i < doc.length);

	t.end();
});
Exemple #9
0
mod_assert.object(config, 'config');
mod_assert.optionalNumber(config.port, 'config.port');
if (config.port === undefined)
	config.port = 8080;

var log = mod_bunyan.createLogger({ name: 'makecheckbot' });

var repoHasMakeCheck = {};
repoHasMakeCheck['joyent/illumos-extra'] = false;
repoHasMakeCheck['joyent/illumos-joyent'] = false;
repoHasMakeCheck['joyent/zfs_snapshot_tar'] = false;
repoHasMakeCheck['joyent/illumos-kvm'] = false;
repoHasMakeCheck['joyent/postgres'] = false;

var dockerKeyPem = mod_fs.readFileSync(config.docker.keyFile);
var dockerKey = mod_sshpk.parsePrivateKey(dockerKeyPem);
var id = mod_sshpk.identityFromDN('CN=' + config.docker.user);
var cert = mod_sshpk.createSelfSignedCertificate(id, dockerKey);

config.gerrit.log = log;
config.gerrit.recovery = {
	default: {
		timeout: 30000,
		maxTimeout: 120000,
		delay: 5000,
		maxDelay: 15000,
		retries: Infinity
	}
};
var gerrit = new mod_gbot.Client(config.gerrit);
var tmpDir;
var ID_RSA_FP = 'SHA256:29GY+6bxcBkcNNUzTnEcTdTv1W3d3PN/OxyplcYSoX4';
var ID_RSA_MD5 = 'fa:56:a1:6b:cc:04:97:fe:e2:98:54:c4:2e:0d:26:c6';
var ID_RSA2_FP = 'SHA256:FWEns/VvPZdbSPtoVDUlUpewdP/LgC/4+l/V42Oltpw';
var ID_DSA_FP = 'SHA256:WI2QyT/UuJ4LaPylGynx244f6k+xqVHYOyxg1cfnL0I';
var ID_DSA_MD5 = 'a6:e6:68:d3:28:2b:0a:a0:12:54:da:c4:c0:22:8d:ba';

var SIG_RSA_SHA256 = 'KX1okEE5wWjgrDYM35z9sO49WRk/DeZy7QeSNCFdOsn45BO6rVOIH5v' +
    'V7WD25/VWyGCiN86Pml/Eulhx3Xx4ZUEHHc18K0BAKU5CSu/jCRI0dEFt4q1bXCyM7aK' +
    'FlAXpk7CJIM0Gx91CJEXcZFuUddngoqljyt9hu4dpMhrjVFA=';

var SIG_RSA_SHA1 = 'parChQDdkj8wFY75IUW/W7KN9q5FFTPYfcAf+W7PmN8yxnRJB884NHYNT' +
    'hl/TjZB2s0vt+kkfX3nldi54heTKbDKFwCOoDmVWQ2oE2ZrJPPFiUHReUAIRvwD0V/q7' +
    '4c/DiRR6My7FEa8Szce27DBrjBmrMvMcmd7/jDbhaGusy4=';

var ID_RSA = sshpk.parsePrivateKey(
    fs.readFileSync(path.join(testDir, 'id_rsa')));

function copyAsset(name, dst, cb) {
    var rd = fs.createReadStream(path.join(testDir, name));
    var wr = fs.createWriteStream(path.join(tmpDir, dst));
    wr.on('close', cb);
    rd.pipe(wr);
}

test('setup fs only', function (t) {
    temp.mkdir('smartdc-auth.signers.test', function (err, tmp) {
        t.error(err);
        tmpDir = tmp;
        fs.mkdirSync(path.join(tmpDir, '.ssh'));

        vasync.parallel({