From ba377874b19c3287789e24acf7b792c39319b74d Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 2 Oct 2021 03:02:49 +0100 Subject: [PATCH] Looks like upgrading to TLS isn't going to work, so we're going to implement it ourselves. ....this is a bad idea. --- package-lock.json | 401 ++++++++++++++++++-- package.json | 3 +- src/cli.mjs | 5 +- src/lib/async/sleep.mjs | 12 + src/lib/crypto/secretbox.mjs | 36 +- src/lib/io/Ansi.mjs | 88 +++++ src/lib/transport/Connection.mjs | 28 +- src/lib/transport/rekey.mjs | 41 ++ src/lib/transport/starttls.mjs | 34 -- src/subcommands/keygen/keygen.mjs | 7 + src/subcommands/keygen/meta.mjs | 5 + src/subcommands/query/meta.mjs | 3 +- src/subcommands/test-client/meta.mjs | 6 + src/subcommands/test-client/test-client.mjs | 45 +++ src/subcommands/test-server/meta.mjs | 6 + src/subcommands/test-server/test-server.mjs | 24 ++ 16 files changed, 665 insertions(+), 79 deletions(-) create mode 100644 src/lib/async/sleep.mjs create mode 100644 src/lib/io/Ansi.mjs create mode 100644 src/lib/transport/rekey.mjs delete mode 100644 src/lib/transport/starttls.mjs create mode 100644 src/subcommands/keygen/keygen.mjs create mode 100644 src/subcommands/keygen/meta.mjs create mode 100644 src/subcommands/test-client/meta.mjs create mode 100644 src/subcommands/test-client/test-client.mjs create mode 100644 src/subcommands/test-server/meta.mjs create mode 100644 src/subcommands/test-server/test-server.mjs diff --git a/package-lock.json b/package-lock.json index e1526cb..63fde0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,18 +10,93 @@ "license": "MPL-2.0", "dependencies": { "applause-cli": "^1.7.0", + "jpake": "^1.0.1", "log": "^6.2.0", - "make-cert": "^1.2.1", + "log-node": "^8.0.1", "nexline": "^1.2.2", "systeminformation": "^5.9.4", "tweetnacl": "^1.0.3" } }, + "node_modules/@types/crypto-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.2.tgz", + "integrity": "sha512-sCVniU+h3GcGqxOmng11BRvf9TfN9yIs8KKjB8C8d75W69cpTfZG80gau9yTx5SxF3gvHGbJhdESzzvnjtf3Og==" + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/applause-cli": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/applause-cli/-/applause-cli-1.7.0.tgz", "integrity": "sha512-zO/nBR9x37Iqlm3R2Glo0NyDIevwbDPrISprK61Z/M01Xvm5dFkL2FZAONxxHctT9QoF71fiY22sFRuq8Sqxug==" }, + "node_modules/cli-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.0.tgz", + "integrity": "sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A==", + "dependencies": { + "ansi-regex": "^2.1.1", + "d": "^1.0.1", + "es5-ext": "^0.10.51", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.7" + } + }, + "node_modules/cli-sprintf-format": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.0.tgz", + "integrity": "sha512-t3LcCdPvrypZovStadWdRS4a186gsq9aoHJYTIer55VY20YdVjGVHDV4uPWcWCXTw1tPjfwlRGE7zKMWJ663Sw==", + "dependencies": { + "cli-color": "^1.3", + "es5-ext": "^0.10.46", + "sprintf-kit": "2", + "supports-color": "^5.5" + } + }, + "node_modules/cli-sprintf-format/node_modules/cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "dependencies": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + } + }, + "node_modules/cli-sprintf-format/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-sprintf-format/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "node_modules/d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -74,6 +149,17 @@ "ext": "^1.1.2" } }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "node_modules/event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -109,6 +195,33 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, + "node_modules/has-ansi": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-4.0.1.tgz", + "integrity": "sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/iconv-lite": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", @@ -120,6 +233,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "node_modules/jpake": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jpake/-/jpake-1.0.1.tgz", + "integrity": "sha512-GG6hetewcHq0ip3Z5oElxD9hTv6fdcn0PQFTgKriGob5CakThcOI7Qv69AiB/K5xHKFzxdnUsDxUvPqOIAWXRg==", + "dependencies": { + "@types/crypto-js": "^4.0.1", + "crypto-js": "^4.0.0", + "noble-secp256k1": "^1.1.1" + } + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -141,17 +269,55 @@ "type": "^2.5.0" } }, - "node_modules/make-cert": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/make-cert/-/make-cert-1.2.1.tgz", - "integrity": "sha512-mvQkS2rSZE0rfgxycg/g2gcFaNm/XzDgkDF3CIp9StDaPU8f+3NL+gwg/qzsgL8bDy50jwak6OonVrAc/U/xEw==", + "node_modules/log-node": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.1.tgz", + "integrity": "sha512-w6ii8zZo+O4Os9EBB0+ruaeVU6CysNgYj/cUDOtobBxnNPRHynjMjzyqjEuNKGT/AD89sZzGh0pS3/0ZPRR1iQ==", "dependencies": { - "node-forge": "^0.10.0" + "cli-color": "^2.0.0", + "cli-sprintf-format": "^1.1.0", + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "has-ansi": "^4.0.1", + "sprintf-kit": "^2.0.1", + "supports-color": "^8.1.1", + "type": "^2.5.0" }, - "bin": { - "make-cert": "make-cert.js" + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "log": "^6.0.0" } }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/memoizee/node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "node_modules/nexline": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/nexline/-/nexline-1.2.2.tgz", @@ -169,13 +335,10 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, - "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "engines": { - "node": ">= 6.0.0" - } + "node_modules/noble-secp256k1": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/noble-secp256k1/-/noble-secp256k1-1.2.10.tgz", + "integrity": "sha512-PXlDRYoWD5JHm+fKVx8PsiLVsuYLIp+5ZhO76L//H/q2/YcQZAS59z9aXO7lcq4IMOq8a1U18KXgpijnkz+C5A==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -190,6 +353,20 @@ "es5-ext": "^0.10.53" } }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/systeminformation": { "version": "5.9.4", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.9.4.tgz", @@ -214,6 +391,15 @@ "url": "https://www.buymeacoffee.com/systeminfo" } }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -234,11 +420,78 @@ } }, "dependencies": { + "@types/crypto-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.2.tgz", + "integrity": "sha512-sCVniU+h3GcGqxOmng11BRvf9TfN9yIs8KKjB8C8d75W69cpTfZG80gau9yTx5SxF3gvHGbJhdESzzvnjtf3Og==" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, "applause-cli": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/applause-cli/-/applause-cli-1.7.0.tgz", "integrity": "sha512-zO/nBR9x37Iqlm3R2Glo0NyDIevwbDPrISprK61Z/M01Xvm5dFkL2FZAONxxHctT9QoF71fiY22sFRuq8Sqxug==" }, + "cli-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.0.tgz", + "integrity": "sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A==", + "requires": { + "ansi-regex": "^2.1.1", + "d": "^1.0.1", + "es5-ext": "^0.10.51", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.7" + } + }, + "cli-sprintf-format": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.0.tgz", + "integrity": "sha512-t3LcCdPvrypZovStadWdRS4a186gsq9aoHJYTIer55VY20YdVjGVHDV4uPWcWCXTw1tPjfwlRGE7zKMWJ663Sw==", + "requires": { + "cli-color": "^1.3", + "es5-ext": "^0.10.46", + "sprintf-kit": "2", + "supports-color": "^5.5" + }, + "dependencies": { + "cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "requires": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", @@ -293,6 +546,17 @@ "ext": "^1.1.2" } }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -325,6 +589,26 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, + "has-ansi": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-4.0.1.tgz", + "integrity": "sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==", + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + } + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, "iconv-lite": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", @@ -333,6 +617,21 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "jpake": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jpake/-/jpake-1.0.1.tgz", + "integrity": "sha512-GG6hetewcHq0ip3Z5oElxD9hTv6fdcn0PQFTgKriGob5CakThcOI7Qv69AiB/K5xHKFzxdnUsDxUvPqOIAWXRg==", + "requires": { + "@types/crypto-js": "^4.0.1", + "crypto-js": "^4.0.0", + "noble-secp256k1": "^1.1.1" + } + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -354,12 +653,49 @@ "type": "^2.5.0" } }, - "make-cert": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/make-cert/-/make-cert-1.2.1.tgz", - "integrity": "sha512-mvQkS2rSZE0rfgxycg/g2gcFaNm/XzDgkDF3CIp9StDaPU8f+3NL+gwg/qzsgL8bDy50jwak6OonVrAc/U/xEw==", + "log-node": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.1.tgz", + "integrity": "sha512-w6ii8zZo+O4Os9EBB0+ruaeVU6CysNgYj/cUDOtobBxnNPRHynjMjzyqjEuNKGT/AD89sZzGh0pS3/0ZPRR1iQ==", "requires": { - "node-forge": "^0.10.0" + "cli-color": "^2.0.0", + "cli-sprintf-format": "^1.1.0", + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "has-ansi": "^4.0.1", + "sprintf-kit": "^2.0.1", + "supports-color": "^8.1.1", + "type": "^2.5.0" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "requires": { + "es5-ext": "~0.10.2" + } + }, + "memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "dependencies": { + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + } } }, "nexline": { @@ -376,10 +712,10 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + "noble-secp256k1": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/noble-secp256k1/-/noble-secp256k1-1.2.10.tgz", + "integrity": "sha512-PXlDRYoWD5JHm+fKVx8PsiLVsuYLIp+5ZhO76L//H/q2/YcQZAS59z9aXO7lcq4IMOq8a1U18KXgpijnkz+C5A==" }, "safer-buffer": { "version": "2.1.2", @@ -394,11 +730,28 @@ "es5-ext": "^0.10.53" } }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + }, "systeminformation": { "version": "5.9.4", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.9.4.tgz", "integrity": "sha512-FOsiTn0CyJZoj9kIhla11ndsMzbbwwuriul81wpqIBt9IpbxHZ6P/oZCphIFgJrwqjTnme0Qp1HDzIkUD9Xr/g==" }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, "tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", diff --git a/package.json b/package.json index 8dde60f..bd1875f 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,9 @@ "homepage": "https://github.com/sbrl/systemquery#readme", "dependencies": { "applause-cli": "^1.7.0", + "jpake": "^1.0.1", "log": "^6.2.0", - "make-cert": "^1.2.1", + "log-node": "^8.0.1", "nexline": "^1.2.2", "systeminformation": "^5.9.4", "tweetnacl": "^1.0.3" diff --git a/src/cli.mjs b/src/cli.mjs index 31bda39..0b0c947 100644 --- a/src/cli.mjs +++ b/src/cli.mjs @@ -19,12 +19,13 @@ async function load_subcommands(cli) { } export default async function () { + let settings = (await import("./settings.mjs")).default; let cli = new CliParser(path.resolve(__dirname, "../package.json")); cli.argument("verbose", "Enable verbose debugging output", null, "boolean"); await load_subcommands(cli); - let settings_cli = cli.parse(process.argv.slice(2)); + settings.cli = cli.parse(process.argv.slice(2)); if(cli.current_subcommand == null) cli.write_help_exit(); @@ -41,8 +42,6 @@ export default async function () { process.exit(1); } - let settings = (await import("./settings.mjs")).default; - settings.cli = settings_cli; try { await (await import(subcommand_file)).default(); diff --git a/src/lib/async/sleep.mjs b/src/lib/async/sleep.mjs new file mode 100644 index 0000000..8f086f4 --- /dev/null +++ b/src/lib/async/sleep.mjs @@ -0,0 +1,12 @@ +"use strict"; + +/** + * Returns a promise that resolves in the given number of milliseconds. + * @param {number} ms The number of milliseconds to wait before resolving the promise. + * @return {Promise} A Promise that resolves after the given number of milliseconds have passed. + */ +export default function sleep(ms) { + return new Promise((resolve, _reject) => { + setTimeout(resolve, ms); + }); +} diff --git a/src/lib/crypto/secretbox.mjs b/src/lib/crypto/secretbox.mjs index 9c83340..67248c3 100644 --- a/src/lib/crypto/secretbox.mjs +++ b/src/lib/crypto/secretbox.mjs @@ -19,8 +19,18 @@ function make_key() { */ function encrypt(key, data) { const key_bytes = Buffer.from(key, "base64"); - const nonce = randomBytes(secretbox.nonceLength); const data_bytes = Buffer.from(data, "utf-8"); + return encrypt_bytes(key_bytes, data_bytes).toString("base64"); +} + +/** + * Encrypts the given data with the given key. + * @param {Buffer} key The key to use to encrypt the data. + * @param {Buffer} data The data to encrypt. + * @return {Buffer} The encrypted data. + */ +function encrypt_bytes(key_bytes, data_bytes) { + const nonce = randomBytes(secretbox.nonceLength); const cipher_bytes = secretbox(data_bytes, nonce, key_bytes); @@ -29,12 +39,12 @@ function encrypt(key, data) { key_bytes.fill(0); nonce.fill(0); - return Buffer.from(concat_bytes).toString("base64"); + return Buffer.from(concat_bytes); } /** * Decrypts the given data with the given key. - * @param {string} key The base64-encoded keyto use to decrypt the data. + * @param {string} key The base64-encoded key to use to decrypt the data. * @param {string} cipher_text The base64-encoded ciphertext to decrypt. * @return {string} The decoded data, utf-8 encoded. */ @@ -42,8 +52,20 @@ function decrypt(key, cipher_text) { const concat_bytes = Buffer.from(cipher_text, "base64"); const key_bytes = Buffer.from(key, "base64"); - const nonce = concat_bytes.slice(0, secretbox.nonceLength); - const cipher_bytes = concat_bytes.slice(secretbox.nonceLength); + const data_bytes = decrypt_bytes(key_bytes, concat_bytes); + if(data_bytes === null) return null; + return data_bytes.toString("utf-8"); +} + +/** + * Decrypts the given data with the given key. + * @param {Buffer} key The key to use to decrypt the data. + * @param {Buffer} cipher_text The ciphertext to decrypt. + * @return {Buffer} The decoded data. + */ +function decrypt_bytes(key_bytes, cipher_text_bytes) { + const nonce = cipher_text_bytes.slice(0, secretbox.nonceLength); + const cipher_bytes = cipher_text_bytes.slice(secretbox.nonceLength); const data_bytes = secretbox.open(cipher_bytes, nonce, key_bytes); // Failed to decrypt message. Could be because the nonce, key, or ciphertext is invalid @@ -51,7 +73,7 @@ function decrypt(key, cipher_text) { // Ref https://github.com/dchest/tweetnacl-js/wiki/Examples#secretbox if(!data_bytes) return null; - return Buffer.from(data_bytes).toString("utf-8"); + return Buffer.from(data_bytes); } -export { make_key, encrypt, decrypt }; +export { make_key, encrypt, decrypt, encrypt_bytes, decrypt_bytes }; diff --git a/src/lib/io/Ansi.mjs b/src/lib/io/Ansi.mjs new file mode 100644 index 0000000..26415ff --- /dev/null +++ b/src/lib/io/Ansi.mjs @@ -0,0 +1,88 @@ +"use strict"; + +/** + * Generates various VT100 ANSI escape sequences. + * Ported from C#. + * @licence MPL-2.0 + * @source https://gist.github.com/a4edd3204a03f4eedb79785751efb0f3#file-ansi-cs + * @author Starbeamrainbowlabs + * GitHub: @sbrl | Twitter: @SBRLabs | Reddit: u/Starbeamrainbowlabs + ***** Changelog ***** + * 27th March 2019: + * - Initial public release + * 9th March 2020: + * - Add Italics (\u001b[3m]) + * - Export a new instance of it by default (makes it so that there's 1 global instance) + * 5th September 2020: + * - Add support for NO_COLOR environment variable + */ +class Ansi { + constructor() { + /** + * Whether we should *actually* emit ANSI escape codes or not. + * Useful when we want to output to a log file, for example + * @type {Boolean} + */ + this.enabled = true; + + this.escape_codes(); + } + + escape_codes() { + if(typeof process !== "undefined" && typeof process.env.NO_COLOR == "string") { + this.enabled = false; + return; + } + // Solution on how to output ANSI escape codes in C# from here: + // https://www.jerriepelser.com/blog/using-ansi-color-codes-in-net-console-apps + this.reset = this.enabled ? "\u001b[0m" : ""; + this.hicol = this.enabled ? "\u001b[1m" : ""; + this.locol = this.enabled ? "\u001b[2m" : ""; + this.italics = this.enabled ? "\u001b[3m" : ""; + this.underline = this.enabled ? "\u001b[4m" : ""; + this.inverse = this.enabled ? "\u001b[7m" : ""; + this.fblack = this.enabled ? "\u001b[30m" : ""; + this.fred = this.enabled ? "\u001b[31m" : ""; + this.fgreen = this.enabled ? "\u001b[32m" : ""; + this.fyellow = this.enabled ? "\u001b[33m" : ""; + this.fblue = this.enabled ? "\u001b[34m" : ""; + this.fmagenta = this.enabled ? "\u001b[35m" : ""; + this.fcyan = this.enabled ? "\u001b[36m" : ""; + this.fwhite = this.enabled ? "\u001b[37m" : ""; + this.bblack = this.enabled ? "\u001b[40m" : ""; + this.bred = this.enabled ? "\u001b[41m" : ""; + this.bgreen = this.enabled ? "\u001b[42m" : ""; + this.byellow = this.enabled ? "\u001b[43m" : ""; + this.bblue = this.enabled ? "\u001b[44m" : ""; + this.bmagenta = this.enabled ? "\u001b[45m" : ""; + this.bcyan = this.enabled ? "\u001b[46m" : ""; + this.bwhite = this.enabled ? "\u001b[47m" : ""; + } + + // Thanks to http://ascii-table.com/ansi-escape-sequences.php for the following ANSI escape sequences + up(lines = 1) { + return this.enabled ? `\u001b[${lines}A` : ""; + } + down(lines = 1) { + return this.enabled ? `\u001b[${lines}B` : ""; + } + right(lines = 1) { + return this.enabled ? `\u001b[${lines}C` : ""; + } + left(lines = 1) { + return this.enabled ? `\u001b[${lines}D` : ""; + } + + jump_to(x, y) { + return this.enabled ? `\u001b[${y};${x}H` : ""; + } + + cursor_pos_save() { + return this.enabled ? `\u001b[s` : ""; + } + cursor_pos_restore() { + return this.enabled ? `\u001b[u` : ""; + } +} + +export default (new Ansi()); diff --git a/src/lib/transport/Connection.mjs b/src/lib/transport/Connection.mjs index fffeb24..8b03f34 100644 --- a/src/lib/transport/Connection.mjs +++ b/src/lib/transport/Connection.mjs @@ -7,13 +7,18 @@ import l from 'log'; import nexline from 'nexline'; import settings from '../../settings.mjs'; +import rekey from './rekey.mjs'; +import { write_safe } from '../io/StreamHelpers.mjs'; +import { encrypt_bytes, decrypt_bytes } from '../crypto/secretbox.mjs'; /** * Represents a connection to a single endpoint. */ class Connection extends EventEmitter { - constructor() { + constructor(secret_join) { super(); + + this.session_key = Buffer.from(secret_join, "base64"); } /** @@ -31,15 +36,13 @@ class Connection extends EventEmitter { await once(this.socket, "connect"); this.socket.setKeepAlive(true); + this.session_key = await rekey(this.socket, this.session_key); + this.reader = nexline({ + input: this.socket + }); - - - // this.reader = nexline({ - // input: this.socket - // }); - // - // this.read_task = read_loop(); + this.read_task = read_loop(); } destroy() { @@ -65,6 +68,15 @@ class Connection extends EventEmitter { let message = JSON.parse(text); } + + async send(message) { + // TODO: Implement a binary frame-based protocol here instead? It would be 33% more bandwidth efficient. + // Perhaps ? If messages are too long, we'll have to do something about that though.... + let payload = JSON.stringify(message); + payload = encrypt_bytes(this.session_key, payload); + + await write_safe(this.socket, payload); + } } export default Connection; diff --git a/src/lib/transport/rekey.mjs b/src/lib/transport/rekey.mjs new file mode 100644 index 0000000..1593822 --- /dev/null +++ b/src/lib/transport/rekey.mjs @@ -0,0 +1,41 @@ +"use strict"; + +import { once } from 'events'; + +import l from 'log'; +import { JPake } from 'jpake'; + +export default async function rekey(connection, secret_join) { + // 0: Setup jpake + let jpake = new JPake(secret_join); + + // 1: Round 1 + connection.send("jpake-rekey-r1", jpake.GetRound1Message()); + + // 2: Round 2 + const their_round1 = (await once(connection, "message"))[0]; + if(typeof their_round1 !== "string") return null; + + const our_round2 = jpake.GetRound2Message(their_round1); + if(typeof our_round2 !== "string") return null; + + connection.send("jpake-rekey-r2", our_round2); + + + // 3: Compute new shared key + const their_round2 = (await once(connection, "message"))[0]; + if(typeof their_round2 !== "string") return null; + const new_shared_key = jpake.ComputeSharedKey(their_round2); + if(typeof new_shared_key !== "string") return null; + + return Buffer.from(new_shared_key, "hex"); + + // let data_bytes = response[0].toString("base64"); + // + // const cert_theirs = decrypt(secret_join, data_bytes.toString("base64")); + // if(cert_theirs === null) { + // socket.destroy(); + // return null; + // } + // console.log(`STARTTLS cert_theirs`, cert_theirs); +} diff --git a/src/lib/transport/starttls.mjs b/src/lib/transport/starttls.mjs deleted file mode 100644 index a18515f..0000000 --- a/src/lib/transport/starttls.mjs +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; - -import { once } from 'events'; -import tls from 'tls'; - -import { write_safe } from '../io/StreamHelpers.mjs'; -import { encrypt, decrypt } from '../crypto/secretbox.mjs'; - - -export default async function starttls(socket, secret_join, { cert: cert_ours, key: key_ours }, is_server = true) { - // 1: Encrypt our self-signed cert and send it to the peer - const cert_encrypted = encrypt(secret_join, cert_ours); - await write_safe(socket, Buffer.from(cert_encrypted, "base64")); - - // 2: Receive our peer's certificate and decrypt it - let data_bytes = Buffer.from(await once(socket, "data")[0], "base64"); - - const cert_theirs = decrypt(secret_join, data_bytes.toString("base64")); - if(cert_theirs === null) { - socket.destroy(); - return null; - } - - // 3: Upgrade to proper TLS - const tls_socket = new tls.TLSSocket(socket, { - isServer: is_server, - requestCert: true, - ca: cert_theirs, - cert: cert_ours, - key: key_ours - }); - - return tls_socket; -} diff --git a/src/subcommands/keygen/keygen.mjs b/src/subcommands/keygen/keygen.mjs new file mode 100644 index 0000000..a42fbf1 --- /dev/null +++ b/src/subcommands/keygen/keygen.mjs @@ -0,0 +1,7 @@ +"use strict"; + +import { make_key } from '../../lib/crypto/secretbox.mjs'; + +export default async function() { + console.log(make_key()); +} diff --git a/src/subcommands/keygen/meta.mjs b/src/subcommands/keygen/meta.mjs new file mode 100644 index 0000000..1f37f18 --- /dev/null +++ b/src/subcommands/keygen/meta.mjs @@ -0,0 +1,5 @@ +"use strict"; + +export default function(cli) { + cli.subcommand("keygen", "Generates a new secret key"); +} diff --git a/src/subcommands/query/meta.mjs b/src/subcommands/query/meta.mjs index 671746f..1a0004e 100644 --- a/src/subcommands/query/meta.mjs +++ b/src/subcommands/query/meta.mjs @@ -1,6 +1,5 @@ "use strict"; export default function(cli) { - cli.subcommand("query", "Query the cluster [requires agent with the query permission to be running on this host]") - .argument("address", "Address of the agent to connect to.", "unix-abstract:systemquery", "string"); + cli.subcommand("query", "Queries the local systemquery agent"); } diff --git a/src/subcommands/test-client/meta.mjs b/src/subcommands/test-client/meta.mjs new file mode 100644 index 0000000..4dca40e --- /dev/null +++ b/src/subcommands/test-client/meta.mjs @@ -0,0 +1,6 @@ +"use strict"; + +export default function(cli) { + cli.subcommand("test-client", "Start a client to test the encryption protocol") + .argument("port", "Port to connect to the server on", 5101, "integer"); +} diff --git a/src/subcommands/test-client/test-client.mjs b/src/subcommands/test-client/test-client.mjs new file mode 100644 index 0000000..2d14a8c --- /dev/null +++ b/src/subcommands/test-client/test-client.mjs @@ -0,0 +1,45 @@ +"use strict"; + +import net from 'net'; + +import l from 'log'; +import make_cert from 'make-cert'; + +import settings from '../../settings.mjs'; +import sleep from '../../lib/async/sleep.mjs'; +import starttls from '../../lib/transport/starttls.mjs'; +import { encrypt, decrypt } from '../../lib/crypto/secretbox.mjs'; + +export default async function() { + const test_key = "H7xKSxvJFoZoNjCKAfxn4E3qUzY3Y/4bjY+qIzxg+78="; + const our_cert = make_cert("test_server.localhost"); + + const test_data = "hello, world"; + l.notice(`TEST_DATA`, test_data); + const encrypted = encrypt(test_key, test_data); + l.notice(`ENCRYPTED`, encrypted); + const decrypted = decrypt(test_key, encrypted); + l.notice(`DECRYPTED`, decrypted); + + const socket = net.createConnection({ + port: settings.cli.port + }, () => { + l.notice("connection established"); + }); + + await starttls(socket, test_key, our_cert, false); + + socket.on("data", (chunk) => { + l.notice(`<<< ${chunk.toString("utf-8")}`); + }); + socket.on("end", () => { + l.notice("disconnected"); + }); + + + for(let i = 0; i < 100; i++) { + await sleep(1000); + l.notice(`>>> hello world ${i}`); + socket.write(`hello world ${i}\n`); + } +} diff --git a/src/subcommands/test-server/meta.mjs b/src/subcommands/test-server/meta.mjs new file mode 100644 index 0000000..140a564 --- /dev/null +++ b/src/subcommands/test-server/meta.mjs @@ -0,0 +1,6 @@ +"use strict"; + +export default function(cli) { + cli.subcommand("test-server", "Start an echo server to test the encryption protocol") + .argument("port", "Port to start the server on", 5101, "integer"); +} diff --git a/src/subcommands/test-server/test-server.mjs b/src/subcommands/test-server/test-server.mjs new file mode 100644 index 0000000..284d96e --- /dev/null +++ b/src/subcommands/test-server/test-server.mjs @@ -0,0 +1,24 @@ +"use strict"; + +import net from 'net'; + +import make_cert from 'make-cert'; +import l from 'log'; + +import settings from '../../settings.mjs'; +import starttls from '../../lib/transport/starttls.mjs'; + +export default async function() { + const test_key = "H7xKSxvJFoZoNjCKAfxn4E3qUzY3Y/4bjY+qIzxg+78="; + const our_cert = make_cert("test_server.localhost"); + + const server = net.createServer(async (client) => { + l.notice("client connected"); + await starttls(client, test_key, our_cert, true); + client.write("hello\n"); + client.pipe(client); + }); + + server.on("error", (error) => { throw error; }); + server.listen(settings.cli.port, () => l.notice(`Listening on port ${settings.cli.port}`)); +}