generated from JeanOUINA/typescript-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add GLOBAL_REQUEST, DEBUG, IGNORE, aes256-ctr, aes192-ctr
- Loading branch information
Showing
14 changed files
with
404 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,10 @@ import ServiceRequest from "./packets/ServiceRequest.js" | |
import ServiceAccept from "./packets/ServiceAccept.js" | ||
import Agent from "./publickey/Agent.js" | ||
import NoneAgent from "./publickey/NoneAgent.js" | ||
import GlobalRequest from "./packets/GlobalRequest.js" | ||
import RequestFailure from "./packets/RequestFailure.js" | ||
import Debug from "./packets/Debug.js" | ||
import { readNextBuffer } from "./utils/Buffer.js" | ||
|
||
export interface ClientOptions { | ||
hostname: string | ||
|
@@ -156,6 +160,7 @@ export default class Client extends (EventEmitter as new () => TypedEmitter<Clie | |
|
||
hasReceivedNewKeys: boolean = false | ||
hasSentNewKeys: boolean = false | ||
hasAuthenticated: boolean = false | ||
|
||
state = SocketState.Closed | ||
get isConnected(): boolean { | ||
|
@@ -374,6 +379,56 @@ export default class Client extends (EventEmitter as new () => TypedEmitter<Clie | |
// we could not authenticate. | ||
throw new Error("All authentication methods failed.") | ||
} | ||
this.hasAuthenticated = true | ||
|
||
// now that we have received USERAUTH_SUCCESS, we need | ||
// to handle GLOBAL_REQUEST. | ||
|
||
this.on("packet", (packet) => { | ||
if (!(packet instanceof GlobalRequest)) return | ||
|
||
this.debug(`Received global request packet:`, packet) | ||
|
||
switch (packet.data.request_name) { | ||
case "[email protected]": { | ||
const hostkeys = [] | ||
let raw = packet.data.args | ||
while (raw.length != 0) { | ||
let arg: Buffer | ||
;[arg, raw] = readNextBuffer(raw) | ||
|
||
try { | ||
hostkeys.push(PublicKey.parse(arg)) | ||
} catch (err) { | ||
// unsupported host key algorithm | ||
// or parse error | ||
// either way don't care and silently fail. | ||
this.debug(`Error while trying to parse host key:`, err) | ||
} | ||
} | ||
|
||
this.debug(`Received ${hostkeys.length} valid host keys`) | ||
|
||
// Do we care ? | ||
// at this point, most usage will be | ||
// from people ignoring host keys | ||
// TODO: need to implement verifying host keys | ||
|
||
// https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD | ||
// section 2.5 (ctrl + f search for "[email protected]") | ||
break | ||
} | ||
default: { | ||
this.debug(`Unknown global request name: ${packet.data.request_name}`) | ||
if (packet.data.want_reply) { | ||
// this might be a keep alive lol | ||
// shitty spec | ||
// either way, send a failure response. | ||
this.sendPacket(new RequestFailure({})) | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
|
||
waitEvent<event extends keyof ClientEvents>( | ||
|
@@ -622,33 +677,48 @@ export default class Client extends (EventEmitter as new () => TypedEmitter<Clie | |
} | ||
|
||
const p = packet.parse(payload) | ||
this.emit("packet", p) | ||
this.debug("Parsing packet:", p) | ||
|
||
this.emit("packet", p) | ||
|
||
switch (packet.type) { | ||
case SSHPacketType.SSH_MSG_DISCONNECT: { | ||
const disconnect = p as Disconnect | ||
this.debug( | ||
"Server disconnected:", | ||
DisconnectReason[disconnect.data.reason_code], | ||
disconnect.data.description, | ||
disconnect.data.language_tag, | ||
) | ||
// TODO: Handle disconnect | ||
break | ||
} | ||
|
||
case SSHPacketType.SSH_MSG_IGNORE: | ||
this.debug(`Received Ignore packet. Ignoring.`) | ||
break | ||
|
||
case SSHPacketType.SSH_MSG_DEBUG: { | ||
const debug = p as Debug | ||
this.debug(`Received debug packet:`, [debug.data.message]) | ||
break | ||
} | ||
|
||
case SSHPacketType.SSH_MSG_KEXINIT: | ||
// handle key exchange | ||
this.emit("serverKexInit", p as KexInit, payload) | ||
break | ||
|
||
case SSHPacketType.SSH_MSG_KEXDH_REPLY: | ||
// handle key exchange | ||
this.emit("serverKexDHReply", p as KexDHReply) | ||
break | ||
|
||
case SSHPacketType.SSH_MSG_NEWKEYS: | ||
this.hasReceivedNewKeys = true | ||
this.emit("serverNewKeys") | ||
// handle key exchange | ||
break | ||
case SSHPacketType.SSH_MSG_DISCONNECT: { | ||
const disconnect = p as Disconnect | ||
this.debug( | ||
"Server disconnected:", | ||
DisconnectReason[disconnect.data.reason_code], | ||
disconnect.data.description, | ||
disconnect.data.language_tag, | ||
) | ||
// TODO: Handle disconnect | ||
} | ||
} | ||
|
||
if (this.buffering.length > 0) { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { EncryptionAlgorithm } from "../../algorithms.js" | ||
import AESNCTR from "./aesN-ctr.js" | ||
|
||
export default class AES192CTR extends AESNCTR { | ||
static alg_name = "aes192-ctr" | ||
static key_length = 24 | ||
static iv_length = 16 | ||
static block_size = 16 | ||
|
||
static instantiate(key: Buffer, iv: Buffer): EncryptionAlgorithm { | ||
return new AES192CTR(key, iv) | ||
} | ||
|
||
constructor(key: Buffer, iv: Buffer) { | ||
super("aes-192-ctr", key, iv) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { EncryptionAlgorithm } from "../../algorithms.js" | ||
import AESNCTR from "./aesN-ctr.js" | ||
|
||
export default class AES256CTR extends AESNCTR { | ||
static alg_name = "aes256-ctr" | ||
static key_length = 32 | ||
static iv_length = 16 | ||
static block_size = 16 | ||
|
||
static instantiate(key: Buffer, iv: Buffer): EncryptionAlgorithm { | ||
return new AES256CTR(key, iv) | ||
} | ||
|
||
constructor(key: Buffer, iv: Buffer) { | ||
super("aes-256-ctr", key, iv) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import crypto from "crypto" | ||
import { EncryptionAlgorithm } from "../../algorithms.js" | ||
|
||
export default class AESNCTR implements EncryptionAlgorithm { | ||
static key_length: number | ||
static iv_length: number | ||
static block_size: number | ||
|
||
key: Buffer | ||
iv: Buffer | ||
encrypt_instance: crypto.Cipher | ||
decrypt_instance: crypto.Cipher | ||
constructor(algorithm: string, key: Buffer, iv: Buffer) { | ||
this.key = key | ||
this.iv = iv | ||
this.encrypt_instance = crypto.createCipheriv(algorithm, this.key, this.iv) | ||
this.decrypt_instance = crypto.createDecipheriv(algorithm, this.key, this.iv) | ||
} | ||
|
||
encrypt(plaintext: Buffer): Buffer { | ||
return this.encrypt_instance.update(plaintext) | ||
} | ||
|
||
decrypt(ciphertext: Buffer): Buffer { | ||
return this.decrypt_instance.update(ciphertext) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.