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
353 lines (297 loc) • 8.75 kB
JavaScript
// Copyright 2017 Joyent, Inc.
module.exports = {
read: read,
verify: verify,
sign: sign,
signAsync: signAsync,
write: write,
/* Internal private API */
fromBuffer: fromBuffer,
toBuffer: toBuffer
};
var assert = require('assert-plus');
var SSHBuffer = require('../ssh-buffer');
var crypto = require('crypto');
var Buffer = require('safer-buffer').Buffer;
var algs = require('../algs');
var Key = require('../key');
var PrivateKey = require('../private-key');
var Identity = require('../identity');
var rfc4253 = require('./rfc4253');
var Signature = require('../signature');
var utils = require('../utils');
var Certificate = require('../certificate');
function verify(cert, key) {
/*
* We always give an issuerKey, so if our verify() is being called then
* there was no signature. Return false.
*/
return (false);
}
var TYPES = {
'user': 1,
'host': 2
};
Object.keys(TYPES).forEach(function (k) { TYPES[TYPES[k]] = k; });
var ECDSA_ALGO = /^ecdsa-sha2-([^@-]+)-cert-v01.com$/;
function read(buf, options) {
if (Buffer.isBuffer(buf))
buf = buf.toString('ascii');
var parts = buf.trim().split(/[ \t\n]+/g);
if (parts.length < 2 || parts.length > 3)
throw (new Error('Not a valid SSH certificate line'));
var algo = parts[0];
var data = parts[1];
data = Buffer.from(data, 'base64');
return (fromBuffer(data, algo));
}
function fromBuffer(data, algo, partial) {
var sshbuf = new SSHBuffer({ buffer: data });
var innerAlgo = sshbuf.readString();
if (algo !== undefined && innerAlgo !== algo)
throw (new Error('SSH certificate algorithm mismatch'));
if (algo === undefined)
algo = innerAlgo;
var cert = {};
cert.signatures = {};
cert.signatures.openssh = {};
cert.signatures.openssh.nonce = sshbuf.readBuffer();
var key = {};
var parts = (key.parts = []);
key.type = getAlg(algo);
var partCount = algs.info[key.type].parts.length;
while (parts.length < partCount)
parts.push(sshbuf.readPart());
assert.ok(parts.length >= 1, 'key must have at least one part');
var algInfo = algs.info[key.type];
if (key.type === 'ecdsa') {
var res = ECDSA_ALGO.exec(algo);
assert.ok(res !== null);
assert.strictEqual(res[1], parts[0].data.toString());
}
for (var i = 0; i < algInfo.parts.length; ++i) {
parts[i].name = algInfo.parts[i];
if (parts[i].name !== 'curve' &&
algInfo.normalize !== false) {
var p = parts[i];
p.data = utils.mpNormalize(p.data);
}
}
cert.subjectKey = new Key(key);
cert.serial = sshbuf.readInt64();
var type = TYPES[sshbuf.readInt()];
assert.string(type, 'valid cert type');
cert.signatures.openssh.keyId = sshbuf.readString();
var principals = [];
var pbuf = sshbuf.readBuffer();
var psshbuf = new SSHBuffer({ buffer: pbuf });
while (!psshbuf.atEnd())
principals.push(psshbuf.readString());
if (principals.length === 0)
principals = ['*'];
cert.subjects = principals.map(function (pr) {
if (type === 'user')
return (Identity.forUser(pr));
else if (type === 'host')
return (Identity.forHost(pr));
throw (new Error('Unknown identity type ' + type));
});
cert.validFrom = int64ToDate(sshbuf.readInt64());
cert.validUntil = int64ToDate(sshbuf.readInt64());
var exts = [];
var extbuf = new SSHBuffer({ buffer: sshbuf.readBuffer() });
var ext;
while (!extbuf.atEnd()) {
ext = { critical: true };
ext.name = extbuf.readString();
ext.data = extbuf.readBuffer();
exts.push(ext);
}
extbuf = new SSHBuffer({ buffer: sshbuf.readBuffer() });
while (!extbuf.atEnd()) {
ext = { critical: false };
ext.name = extbuf.readString();
ext.data = extbuf.readBuffer();
exts.push(ext);
}
cert.signatures.openssh.exts = exts;
/* reserved */
sshbuf.readBuffer();
var signingKeyBuf = sshbuf.readBuffer();
cert.issuerKey = rfc4253.read(signingKeyBuf);
/*
* OpenSSH certs don't give the identity of the issuer, just their
* public key. So, we use an Identity that matches anything. The
* isSignedBy() function will later tell you if the key matches.
*/
cert.issuer = Identity.forHost('**');
var sigBuf = sshbuf.readBuffer();
cert.signatures.openssh.signature =
Signature.parse(sigBuf, cert.issuerKey.type, 'ssh');
if (partial !== undefined) {
partial.remainder = sshbuf.remainder();
partial.consumed = sshbuf._offset;
}
return (new Certificate(cert));
}
function int64ToDate(buf) {
var i = buf.readUInt32BE(0) * 4294967296;
i += buf.readUInt32BE(4);
var d = new Date();
d.setTime(i * 1000);
d.sourceInt64 = buf;
return (d);
}
function dateToInt64(date) {
if (date.sourceInt64 !== undefined)
return (date.sourceInt64);
var i = Math.round(date.getTime() / 1000);
var upper = Math.floor(i / 4294967296);
var lower = Math.floor(i % 4294967296);
var buf = Buffer.alloc(8);
buf.writeUInt32BE(upper, 0);
buf.writeUInt32BE(lower, 4);
return (buf);
}
function sign(cert, key) {
if (cert.signatures.openssh === undefined)
cert.signatures.openssh = {};
try {
var blob = toBuffer(cert, true);
} catch (e) {
delete (cert.signatures.openssh);
return (false);
}
var sig = cert.signatures.openssh;
var hashAlgo = undefined;
if (key.type === 'rsa' || key.type === 'dsa')
hashAlgo = 'sha1';
var signer = key.createSign(hashAlgo);
signer.write(blob);
sig.signature = signer.sign();
return (true);
}
function signAsync(cert, signer, done) {
if (cert.signatures.openssh === undefined)
cert.signatures.openssh = {};
try {
var blob = toBuffer(cert, true);
} catch (e) {
delete (cert.signatures.openssh);
done(e);
return;
}
var sig = cert.signatures.openssh;
signer(blob, function (err, signature) {
if (err) {
done(err);
return;
}
try {
/*
* This will throw if the signature isn't of a
* type/algo that can be used for SSH.
*/
signature.toBuffer('ssh');
} catch (e) {
done(e);
return;
}
sig.signature = signature;
done();
});
}
function write(cert, options) {
if (options === undefined)
options = {};
var blob = toBuffer(cert);
var out = getCertType(cert.subjectKey) + ' ' + blob.toString('base64');
if (options.comment)
out = out + ' ' + options.comment;
return (out);
}
function toBuffer(cert, noSig) {
assert.object(cert.signatures.openssh, 'signature for openssh format');
var sig = cert.signatures.openssh;
if (sig.nonce === undefined)
sig.nonce = crypto.randomBytes(16);
var buf = new SSHBuffer({});
buf.writeString(getCertType(cert.subjectKey));
buf.writeBuffer(sig.nonce);
var key = cert.subjectKey;
var algInfo = algs.info[key.type];
algInfo.parts.forEach(function (part) {
buf.writePart(key.part[part]);
});
buf.writeInt64(cert.serial);
var type = cert.subjects[0].type;
assert.notStrictEqual(type, 'unknown');
cert.subjects.forEach(function (id) {
assert.strictEqual(id.type, type);
});
type = TYPES[type];
buf.writeInt(type);
if (sig.keyId === undefined) {
sig.keyId = cert.subjects[0].type + '_' +
(cert.subjects[0].uid || cert.subjects[0].hostname);
}
buf.writeString(sig.keyId);
var sub = new SSHBuffer({});
cert.subjects.forEach(function (id) {
if (type === TYPES.host)
sub.writeString(id.hostname);
else if (type === TYPES.user)
sub.writeString(id.uid);
});
buf.writeBuffer(sub.toBuffer());
buf.writeInt64(dateToInt64(cert.validFrom));
buf.writeInt64(dateToInt64(cert.validUntil));
var exts = sig.exts;
if (exts === undefined)
exts = [];
var extbuf = new SSHBuffer({});
exts.forEach(function (ext) {
if (ext.critical !== true)
return;
extbuf.writeString(ext.name);
extbuf.writeBuffer(ext.data);
});
buf.writeBuffer(extbuf.toBuffer());
extbuf = new SSHBuffer({});
exts.forEach(function (ext) {
if (ext.critical === true)
return;
extbuf.writeString(ext.name);
extbuf.writeBuffer(ext.data);
});
buf.writeBuffer(extbuf.toBuffer());
/* reserved */
buf.writeBuffer(Buffer.alloc(0));
sub = rfc4253.write(cert.issuerKey);
buf.writeBuffer(sub);
if (!noSig)
buf.writeBuffer(sig.signature.toBuffer('ssh'));
return (buf.toBuffer());
}
function getAlg(certType) {
if (certType === 'ssh-rsa-cert-v01@openssh.com')
return ('rsa');
if (certType === 'ssh-dss-cert-v01@openssh.com')
return ('dsa');
if (certType.match(ECDSA_ALGO))
return ('ecdsa');
if (certType === 'ssh-ed25519-cert-v01@openssh.com')
return ('ed25519');
throw (new Error('Unsupported cert type ' + certType));
}
function getCertType(key) {
if (key.type === 'rsa')
return ('ssh-rsa-cert-v01@openssh.com');
if (key.type === 'dsa')
return ('ssh-dss-cert-v01@openssh.com');
if (key.type === 'ecdsa')
return ('ecdsa-sha2-' + key.curve + '-cert-v01@openssh.com');
if (key.type === 'ed25519')
return ('ssh-ed25519-cert-v01@openssh.com');
throw (new Error('Unsupported key type ' + key.type));
}