123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // Copyright 2015 Joyent, Inc.
- module.exports = Fingerprint;
- var assert = require('assert-plus');
- var Buffer = require('safer-buffer').Buffer;
- var algs = require('./algs');
- var crypto = require('crypto');
- var errs = require('./errors');
- var Key = require('./key');
- var Certificate = require('./certificate');
- var utils = require('./utils');
- var FingerprintFormatError = errs.FingerprintFormatError;
- var InvalidAlgorithmError = errs.InvalidAlgorithmError;
- function Fingerprint(opts) {
- assert.object(opts, 'options');
- assert.string(opts.type, 'options.type');
- assert.buffer(opts.hash, 'options.hash');
- assert.string(opts.algorithm, 'options.algorithm');
- this.algorithm = opts.algorithm.toLowerCase();
- if (algs.hashAlgs[this.algorithm] !== true)
- throw (new InvalidAlgorithmError(this.algorithm));
- this.hash = opts.hash;
- this.type = opts.type;
- }
- Fingerprint.prototype.toString = function (format) {
- if (format === undefined) {
- if (this.algorithm === 'md5')
- format = 'hex';
- else
- format = 'base64';
- }
- assert.string(format);
- switch (format) {
- case 'hex':
- return (addColons(this.hash.toString('hex')));
- case 'base64':
- return (sshBase64Format(this.algorithm,
- this.hash.toString('base64')));
- default:
- throw (new FingerprintFormatError(undefined, format));
- }
- };
- Fingerprint.prototype.matches = function (other) {
- assert.object(other, 'key or certificate');
- if (this.type === 'key') {
- utils.assertCompatible(other, Key, [1, 0], 'key');
- } else {
- utils.assertCompatible(other, Certificate, [1, 0],
- 'certificate');
- }
- var theirHash = other.hash(this.algorithm);
- var theirHash2 = crypto.createHash(this.algorithm).
- update(theirHash).digest('base64');
- if (this.hash2 === undefined)
- this.hash2 = crypto.createHash(this.algorithm).
- update(this.hash).digest('base64');
- return (this.hash2 === theirHash2);
- };
- Fingerprint.parse = function (fp, options) {
- assert.string(fp, 'fingerprint');
- var alg, hash, enAlgs;
- if (Array.isArray(options)) {
- enAlgs = options;
- options = {};
- }
- assert.optionalObject(options, 'options');
- if (options === undefined)
- options = {};
- if (options.enAlgs !== undefined)
- enAlgs = options.enAlgs;
- assert.optionalArrayOfString(enAlgs, 'algorithms');
- var parts = fp.split(':');
- if (parts.length == 2) {
- alg = parts[0].toLowerCase();
- /*JSSTYLED*/
- var base64RE = /^[A-Za-z0-9+\/=]+$/;
- if (!base64RE.test(parts[1]))
- throw (new FingerprintFormatError(fp));
- try {
- hash = Buffer.from(parts[1], 'base64');
- } catch (e) {
- throw (new FingerprintFormatError(fp));
- }
- } else if (parts.length > 2) {
- alg = 'md5';
- if (parts[0].toLowerCase() === 'md5')
- parts = parts.slice(1);
- parts = parts.map(function (p) {
- while (p.length < 2)
- p = '0' + p;
- if (p.length > 2)
- throw (new FingerprintFormatError(fp));
- return (p);
- });
- parts = parts.join('');
- /*JSSTYLED*/
- var md5RE = /^[a-fA-F0-9]+$/;
- if (!md5RE.test(parts) || parts.length % 2 !== 0)
- throw (new FingerprintFormatError(fp));
- try {
- hash = Buffer.from(parts, 'hex');
- } catch (e) {
- throw (new FingerprintFormatError(fp));
- }
- }
- if (alg === undefined)
- throw (new FingerprintFormatError(fp));
- if (algs.hashAlgs[alg] === undefined)
- throw (new InvalidAlgorithmError(alg));
- if (enAlgs !== undefined) {
- enAlgs = enAlgs.map(function (a) { return a.toLowerCase(); });
- if (enAlgs.indexOf(alg) === -1)
- throw (new InvalidAlgorithmError(alg));
- }
- return (new Fingerprint({
- algorithm: alg,
- hash: hash,
- type: options.type || 'key'
- }));
- };
- function addColons(s) {
- /*JSSTYLED*/
- return (s.replace(/(.{2})(?=.)/g, '$1:'));
- }
- function base64Strip(s) {
- /*JSSTYLED*/
- return (s.replace(/=*$/, ''));
- }
- function sshBase64Format(alg, h) {
- return (alg.toUpperCase() + ':' + base64Strip(h));
- }
- Fingerprint.isFingerprint = function (obj, ver) {
- return (utils.isCompatible(obj, Fingerprint, ver));
- };
- /*
- * API versions for Fingerprint:
- * [1,0] -- initial ver
- * [1,1] -- first tagged ver
- */
- Fingerprint.prototype._sshpkApiVersion = [1, 1];
- Fingerprint._oldVersionDetect = function (obj) {
- assert.func(obj.toString);
- assert.func(obj.matches);
- return ([1, 0]);
- };
|