"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/sshpk/lib/signature.js" (8 Mar 2017, 6319 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2015 Joyent, Inc.
    2 
    3 module.exports = Signature;
    4 
    5 var assert = require('assert-plus');
    6 var algs = require('./algs');
    7 var crypto = require('crypto');
    8 var errs = require('./errors');
    9 var utils = require('./utils');
   10 var asn1 = require('asn1');
   11 var SSHBuffer = require('./ssh-buffer');
   12 
   13 var InvalidAlgorithmError = errs.InvalidAlgorithmError;
   14 var SignatureParseError = errs.SignatureParseError;
   15 
   16 function Signature(opts) {
   17     assert.object(opts, 'options');
   18     assert.arrayOfObject(opts.parts, 'options.parts');
   19     assert.string(opts.type, 'options.type');
   20 
   21     var partLookup = {};
   22     for (var i = 0; i < opts.parts.length; ++i) {
   23         var part = opts.parts[i];
   24         partLookup[part.name] = part;
   25     }
   26 
   27     this.type = opts.type;
   28     this.hashAlgorithm = opts.hashAlgo;
   29     this.parts = opts.parts;
   30     this.part = partLookup;
   31 }
   32 
   33 Signature.prototype.toBuffer = function (format) {
   34     if (format === undefined)
   35         format = 'asn1';
   36     assert.string(format, 'format');
   37 
   38     var buf;
   39 
   40     switch (this.type) {
   41     case 'rsa':
   42     case 'ed25519':
   43         if (format === 'ssh') {
   44             buf = new SSHBuffer({});
   45             buf.writeString('ssh-' + this.type);
   46             buf.writePart(this.part.sig);
   47             return (buf.toBuffer());
   48         } else {
   49             return (this.part.sig.data);
   50         }
   51 
   52     case 'dsa':
   53     case 'ecdsa':
   54         var r, s;
   55         if (format === 'asn1') {
   56             var der = new asn1.BerWriter();
   57             der.startSequence();
   58             r = utils.mpNormalize(this.part.r.data);
   59             s = utils.mpNormalize(this.part.s.data);
   60             der.writeBuffer(r, asn1.Ber.Integer);
   61             der.writeBuffer(s, asn1.Ber.Integer);
   62             der.endSequence();
   63             return (der.buffer);
   64         } else if (format === 'ssh' && this.type === 'dsa') {
   65             buf = new SSHBuffer({});
   66             buf.writeString('ssh-dss');
   67             r = this.part.r.data;
   68             if (r.length > 20 && r[0] === 0x00)
   69                 r = r.slice(1);
   70             s = this.part.s.data;
   71             if (s.length > 20 && s[0] === 0x00)
   72                 s = s.slice(1);
   73             if ((this.hashAlgorithm &&
   74                 this.hashAlgorithm !== 'sha1') ||
   75                 r.length + s.length !== 40) {
   76                 throw (new Error('OpenSSH only supports ' +
   77                     'DSA signatures with SHA1 hash'));
   78             }
   79             buf.writeBuffer(Buffer.concat([r, s]));
   80             return (buf.toBuffer());
   81         } else if (format === 'ssh' && this.type === 'ecdsa') {
   82             var inner = new SSHBuffer({});
   83             r = this.part.r.data;
   84             inner.writeBuffer(r);
   85             inner.writePart(this.part.s);
   86 
   87             buf = new SSHBuffer({});
   88             /* XXX: find a more proper way to do this? */
   89             var curve;
   90             if (r[0] === 0x00)
   91                 r = r.slice(1);
   92             var sz = r.length * 8;
   93             if (sz === 256)
   94                 curve = 'nistp256';
   95             else if (sz === 384)
   96                 curve = 'nistp384';
   97             else if (sz === 528)
   98                 curve = 'nistp521';
   99             buf.writeString('ecdsa-sha2-' + curve);
  100             buf.writeBuffer(inner.toBuffer());
  101             return (buf.toBuffer());
  102         }
  103         throw (new Error('Invalid signature format'));
  104     default:
  105         throw (new Error('Invalid signature data'));
  106     }
  107 };
  108 
  109 Signature.prototype.toString = function (format) {
  110     assert.optionalString(format, 'format');
  111     return (this.toBuffer(format).toString('base64'));
  112 };
  113 
  114 Signature.parse = function (data, type, format) {
  115     if (typeof (data) === 'string')
  116         data = new Buffer(data, 'base64');
  117     assert.buffer(data, 'data');
  118     assert.string(format, 'format');
  119     assert.string(type, 'type');
  120 
  121     var opts = {};
  122     opts.type = type.toLowerCase();
  123     opts.parts = [];
  124 
  125     try {
  126         assert.ok(data.length > 0, 'signature must not be empty');
  127         switch (opts.type) {
  128         case 'rsa':
  129             return (parseOneNum(data, type, format, opts,
  130                 'ssh-rsa'));
  131         case 'ed25519':
  132             return (parseOneNum(data, type, format, opts,
  133                 'ssh-ed25519'));
  134 
  135         case 'dsa':
  136         case 'ecdsa':
  137             if (format === 'asn1')
  138                 return (parseDSAasn1(data, type, format, opts));
  139             else if (opts.type === 'dsa')
  140                 return (parseDSA(data, type, format, opts));
  141             else
  142                 return (parseECDSA(data, type, format, opts));
  143 
  144         default:
  145             throw (new InvalidAlgorithmError(type));
  146         }
  147 
  148     } catch (e) {
  149         if (e instanceof InvalidAlgorithmError)
  150             throw (e);
  151         throw (new SignatureParseError(type, format, e));
  152     }
  153 };
  154 
  155 function parseOneNum(data, type, format, opts, headType) {
  156     if (format === 'ssh') {
  157         try {
  158             var buf = new SSHBuffer({buffer: data});
  159             var head = buf.readString();
  160         } catch (e) {
  161             /* fall through */
  162         }
  163         if (head === headType) {
  164             var sig = buf.readPart();
  165             assert.ok(buf.atEnd(), 'extra trailing bytes');
  166             sig.name = 'sig';
  167             opts.parts.push(sig);
  168             return (new Signature(opts));
  169         }
  170     }
  171     opts.parts.push({name: 'sig', data: data});
  172     return (new Signature(opts));
  173 }
  174 
  175 function parseDSAasn1(data, type, format, opts) {
  176     var der = new asn1.BerReader(data);
  177     der.readSequence();
  178     var r = der.readString(asn1.Ber.Integer, true);
  179     var s = der.readString(asn1.Ber.Integer, true);
  180 
  181     opts.parts.push({name: 'r', data: utils.mpNormalize(r)});
  182     opts.parts.push({name: 's', data: utils.mpNormalize(s)});
  183 
  184     return (new Signature(opts));
  185 }
  186 
  187 function parseDSA(data, type, format, opts) {
  188     if (data.length != 40) {
  189         var buf = new SSHBuffer({buffer: data});
  190         var d = buf.readBuffer();
  191         if (d.toString('ascii') === 'ssh-dss')
  192             d = buf.readBuffer();
  193         assert.ok(buf.atEnd(), 'extra trailing bytes');
  194         assert.strictEqual(d.length, 40, 'invalid inner length');
  195         data = d;
  196     }
  197     opts.parts.push({name: 'r', data: data.slice(0, 20)});
  198     opts.parts.push({name: 's', data: data.slice(20, 40)});
  199     return (new Signature(opts));
  200 }
  201 
  202 function parseECDSA(data, type, format, opts) {
  203     var buf = new SSHBuffer({buffer: data});
  204 
  205     var r, s;
  206     var inner = buf.readBuffer();
  207     if (inner.toString('ascii').match(/^ecdsa-/)) {
  208         inner = buf.readBuffer();
  209         assert.ok(buf.atEnd(), 'extra trailing bytes on outer');
  210         buf = new SSHBuffer({buffer: inner});
  211         r = buf.readPart();
  212     } else {
  213         r = {data: inner};
  214     }
  215 
  216     s = buf.readPart();
  217     assert.ok(buf.atEnd(), 'extra trailing bytes');
  218 
  219     r.name = 'r';
  220     s.name = 's';
  221 
  222     opts.parts.push(r);
  223     opts.parts.push(s);
  224     return (new Signature(opts));
  225 }
  226 
  227 Signature.isSignature = function (obj, ver) {
  228     return (utils.isCompatible(obj, Signature, ver));
  229 };
  230 
  231 /*
  232  * API versions for Signature:
  233  * [1,0] -- initial ver
  234  * [2,0] -- support for rsa in full ssh format, compat with sshpk-agent
  235  *          hashAlgorithm property
  236  * [2,1] -- first tagged version
  237  */
  238 Signature.prototype._sshpkApiVersion = [2, 1];
  239 
  240 Signature._oldVersionDetect = function (obj) {
  241     assert.func(obj.toBuffer);
  242     if (obj.hasOwnProperty('hashAlgorithm'))
  243         return ([2, 0]);
  244     return ([1, 0]);
  245 };