dynatrace-cordova-outsystems-plugin
Version:
This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent and the Javascript Bridge. The Mobile Agent will give you all device specific values con
315 lines (282 loc) • 7.99 kB
JavaScript
// Copyright 2015 Joyent, Inc.
module.exports = Signature;
var assert = require('assert-plus');
var Buffer = require('safer-buffer').Buffer;
var algs = require('./algs');
var crypto = require('crypto');
var errs = require('./errors');
var utils = require('./utils');
var asn1 = require('asn1');
var SSHBuffer = require('./ssh-buffer');
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
var SignatureParseError = errs.SignatureParseError;
function Signature(opts) {
assert.object(opts, 'options');
assert.arrayOfObject(opts.parts, 'options.parts');
assert.string(opts.type, 'options.type');
var partLookup = {};
for (var i = 0; i < opts.parts.length; ++i) {
var part = opts.parts[i];
partLookup[part.name] = part;
}
this.type = opts.type;
this.hashAlgorithm = opts.hashAlgo;
this.curve = opts.curve;
this.parts = opts.parts;
this.part = partLookup;
}
Signature.prototype.toBuffer = function (format) {
if (format === undefined)
format = 'asn1';
assert.string(format, 'format');
var buf;
var stype = 'ssh-' + this.type;
switch (this.type) {
case 'rsa':
switch (this.hashAlgorithm) {
case 'sha256':
stype = 'rsa-sha2-256';
break;
case 'sha512':
stype = 'rsa-sha2-512';
break;
case 'sha1':
case undefined:
break;
default:
throw (new Error('SSH signature ' +
'format does not support hash ' +
'algorithm ' + this.hashAlgorithm));
}
if (format === 'ssh') {
buf = new SSHBuffer({});
buf.writeString(stype);
buf.writePart(this.part.sig);
return (buf.toBuffer());
} else {
return (this.part.sig.data);
}
break;
case 'ed25519':
if (format === 'ssh') {
buf = new SSHBuffer({});
buf.writeString(stype);
buf.writePart(this.part.sig);
return (buf.toBuffer());
} else {
return (this.part.sig.data);
}
break;
case 'dsa':
case 'ecdsa':
var r, s;
if (format === 'asn1') {
var der = new asn1.BerWriter();
der.startSequence();
r = utils.mpNormalize(this.part.r.data);
s = utils.mpNormalize(this.part.s.data);
der.writeBuffer(r, asn1.Ber.Integer);
der.writeBuffer(s, asn1.Ber.Integer);
der.endSequence();
return (der.buffer);
} else if (format === 'ssh' && this.type === 'dsa') {
buf = new SSHBuffer({});
buf.writeString('ssh-dss');
r = this.part.r.data;
if (r.length > 20 && r[0] === 0x00)
r = r.slice(1);
s = this.part.s.data;
if (s.length > 20 && s[0] === 0x00)
s = s.slice(1);
if ((this.hashAlgorithm &&
this.hashAlgorithm !== 'sha1') ||
r.length + s.length !== 40) {
throw (new Error('OpenSSH only supports ' +
'DSA signatures with SHA1 hash'));
}
buf.writeBuffer(Buffer.concat([r, s]));
return (buf.toBuffer());
} else if (format === 'ssh' && this.type === 'ecdsa') {
var inner = new SSHBuffer({});
r = this.part.r.data;
inner.writeBuffer(r);
inner.writePart(this.part.s);
buf = new SSHBuffer({});
/* XXX: find a more proper way to do this? */
var curve;
if (r[0] === 0x00)
r = r.slice(1);
var sz = r.length * 8;
if (sz === 256)
curve = 'nistp256';
else if (sz === 384)
curve = 'nistp384';
else if (sz === 528)
curve = 'nistp521';
buf.writeString('ecdsa-sha2-' + curve);
buf.writeBuffer(inner.toBuffer());
return (buf.toBuffer());
}
throw (new Error('Invalid signature format'));
default:
throw (new Error('Invalid signature data'));
}
};
Signature.prototype.toString = function (format) {
assert.optionalString(format, 'format');
return (this.toBuffer(format).toString('base64'));
};
Signature.parse = function (data, type, format) {
if (typeof (data) === 'string')
data = Buffer.from(data, 'base64');
assert.buffer(data, 'data');
assert.string(format, 'format');
assert.string(type, 'type');
var opts = {};
opts.type = type.toLowerCase();
opts.parts = [];
try {
assert.ok(data.length > 0, 'signature must not be empty');
switch (opts.type) {
case 'rsa':
return (parseOneNum(data, type, format, opts));
case 'ed25519':
return (parseOneNum(data, type, format, opts));
case 'dsa':
case 'ecdsa':
if (format === 'asn1')
return (parseDSAasn1(data, type, format, opts));
else if (opts.type === 'dsa')
return (parseDSA(data, type, format, opts));
else
return (parseECDSA(data, type, format, opts));
default:
throw (new InvalidAlgorithmError(type));
}
} catch (e) {
if (e instanceof InvalidAlgorithmError)
throw (e);
throw (new SignatureParseError(type, format, e));
}
};
function parseOneNum(data, type, format, opts) {
if (format === 'ssh') {
try {
var buf = new SSHBuffer({buffer: data});
var head = buf.readString();
} catch (e) {
/* fall through */
}
if (buf !== undefined) {
var msg = 'SSH signature does not match expected ' +
'type (expected ' + type + ', got ' + head + ')';
switch (head) {
case 'ssh-rsa':
assert.strictEqual(type, 'rsa', msg);
opts.hashAlgo = 'sha1';
break;
case 'rsa-sha2-256':
assert.strictEqual(type, 'rsa', msg);
opts.hashAlgo = 'sha256';
break;
case 'rsa-sha2-512':
assert.strictEqual(type, 'rsa', msg);
opts.hashAlgo = 'sha512';
break;
case 'ssh-ed25519':
assert.strictEqual(type, 'ed25519', msg);
opts.hashAlgo = 'sha512';
break;
default:
throw (new Error('Unknown SSH signature ' +
'type: ' + head));
}
var sig = buf.readPart();
assert.ok(buf.atEnd(), 'extra trailing bytes');
sig.name = 'sig';
opts.parts.push(sig);
return (new Signature(opts));
}
}
opts.parts.push({name: 'sig', data: data});
return (new Signature(opts));
}
function parseDSAasn1(data, type, format, opts) {
var der = new asn1.BerReader(data);
der.readSequence();
var r = der.readString(asn1.Ber.Integer, true);
var s = der.readString(asn1.Ber.Integer, true);
opts.parts.push({name: 'r', data: utils.mpNormalize(r)});
opts.parts.push({name: 's', data: utils.mpNormalize(s)});
return (new Signature(opts));
}
function parseDSA(data, type, format, opts) {
if (data.length != 40) {
var buf = new SSHBuffer({buffer: data});
var d = buf.readBuffer();
if (d.toString('ascii') === 'ssh-dss')
d = buf.readBuffer();
assert.ok(buf.atEnd(), 'extra trailing bytes');
assert.strictEqual(d.length, 40, 'invalid inner length');
data = d;
}
opts.parts.push({name: 'r', data: data.slice(0, 20)});
opts.parts.push({name: 's', data: data.slice(20, 40)});
return (new Signature(opts));
}
function parseECDSA(data, type, format, opts) {
var buf = new SSHBuffer({buffer: data});
var r, s;
var inner = buf.readBuffer();
var stype = inner.toString('ascii');
if (stype.slice(0, 6) === 'ecdsa-') {
var parts = stype.split('-');
assert.strictEqual(parts[0], 'ecdsa');
assert.strictEqual(parts[1], 'sha2');
opts.curve = parts[2];
switch (opts.curve) {
case 'nistp256':
opts.hashAlgo = 'sha256';
break;
case 'nistp384':
opts.hashAlgo = 'sha384';
break;
case 'nistp521':
opts.hashAlgo = 'sha512';
break;
default:
throw (new Error('Unsupported ECDSA curve: ' +
opts.curve));
}
inner = buf.readBuffer();
assert.ok(buf.atEnd(), 'extra trailing bytes on outer');
buf = new SSHBuffer({buffer: inner});
r = buf.readPart();
} else {
r = {data: inner};
}
s = buf.readPart();
assert.ok(buf.atEnd(), 'extra trailing bytes');
r.name = 'r';
s.name = 's';
opts.parts.push(r);
opts.parts.push(s);
return (new Signature(opts));
}
Signature.isSignature = function (obj, ver) {
return (utils.isCompatible(obj, Signature, ver));
};
/*
* API versions for Signature:
* [1,0] -- initial ver
* [2,0] -- support for rsa in full ssh format, compat with sshpk-agent
* hashAlgorithm property
* [2,1] -- first tagged version
*/
Signature.prototype._sshpkApiVersion = [2, 1];
Signature._oldVersionDetect = function (obj) {
assert.func(obj.toBuffer);
if (obj.hasOwnProperty('hashAlgorithm'))
return ([2, 0]);
return ([1, 0]);
};