1*1c60b9acSAndroid Build Coastguard Workerssh-base Plugin 2*1c60b9acSAndroid Build Coastguard Worker================ 3*1c60b9acSAndroid Build Coastguard Worker 4*1c60b9acSAndroid Build Coastguard Worker## Introduction 5*1c60b9acSAndroid Build Coastguard Worker 6*1c60b9acSAndroid Build Coastguard Workerlws-ssh-base is a protcol plugin for libwebsockets that implements a 7*1c60b9acSAndroid Build Coastguard Workergeneric, abstract, ssh server. 8*1c60b9acSAndroid Build Coastguard Worker 9*1c60b9acSAndroid Build Coastguard Worker - very small footprint in code and memory, takes up small part of ESP32 10*1c60b9acSAndroid Build Coastguard Worker 11*1c60b9acSAndroid Build Coastguard Worker - written with security in mind: valgrind and Coverity -clean 12*1c60b9acSAndroid Build Coastguard Worker 13*1c60b9acSAndroid Build Coastguard Worker - binds to one or more vhosts, that controls listen port(s) 14*1c60b9acSAndroid Build Coastguard Worker 15*1c60b9acSAndroid Build Coastguard Worker - all IO and settings abstracted through a single "ops" struct from user code 16*1c60b9acSAndroid Build Coastguard Worker 17*1c60b9acSAndroid Build Coastguard Worker - each instance on a vhost has its own "ops" struct, defining server keys, 18*1c60b9acSAndroid Build Coastguard Worker auth method and functions to implement IO and other operations 19*1c60b9acSAndroid Build Coastguard Worker 20*1c60b9acSAndroid Build Coastguard Worker - The plugin has no built-in behaviours like check ~/.ssh/authorized_keys, 21*1c60b9acSAndroid Build Coastguard Worker treat auth usernames as system usernames, or spawn the user's shell. 22*1c60b9acSAndroid Build Coastguard Worker Everything potentially dangerous is left to the user ops code to decide 23*1c60b9acSAndroid Build Coastguard Worker how to handle. It's NOT like sshd where running it implies it will accept 24*1c60b9acSAndroid Build Coastguard Worker existing keys for any system user, will spawn a shell, etc, unless you 25*1c60b9acSAndroid Build Coastguard Worker implement those parts in the ops callbacks. 26*1c60b9acSAndroid Build Coastguard Worker 27*1c60b9acSAndroid Build Coastguard Worker - The plugin requires extra code around it in the form of the ops struct 28*1c60b9acSAndroid Build Coastguard Worker handlers. So it's role is something like an abstract base class for an ssh 29*1c60b9acSAndroid Build Coastguard Worker server. All the crypto, protocol sequencing and state machine are inside, 30*1c60b9acSAndroid Build Coastguard Worker but all the IO except the network connection is outside. 31*1c60b9acSAndroid Build Coastguard Worker 32*1c60b9acSAndroid Build Coastguard Worker - Built as part of libwebsockets, like all plugins may be dynamically loaded 33*1c60b9acSAndroid Build Coastguard Worker at runtime or built statically. Test app `libwebsockets-test-sshd` provided 34*1c60b9acSAndroid Build Coastguard Worker 35*1c60b9acSAndroid Build Coastguard Worker - Uses hash and RSA functions from either mbedTLS or OpenSSL automatically, 36*1c60b9acSAndroid Build Coastguard Worker according to which library libwebsockets was built for 37*1c60b9acSAndroid Build Coastguard Worker 38*1c60b9acSAndroid Build Coastguard WorkerTo maintain its small size, it implements a single "best of breed" crypto for 39*1c60b9acSAndroid Build Coastguard Workerthe following functions: 40*1c60b9acSAndroid Build Coastguard Worker 41*1c60b9acSAndroid Build Coastguard Worker|Function|Crypto| 42*1c60b9acSAndroid Build Coastguard Worker|---|---| 43*1c60b9acSAndroid Build Coastguard Worker|KEX|[email protected]| 44*1c60b9acSAndroid Build Coastguard Worker|Server host key|ssh-rsa (4096b)| 45*1c60b9acSAndroid Build Coastguard Worker|Encryption|[email protected]| 46*1c60b9acSAndroid Build Coastguard Worker|Compression|None| 47*1c60b9acSAndroid Build Coastguard Worker 48*1c60b9acSAndroid Build Coastguard Worker## License 49*1c60b9acSAndroid Build Coastguard Worker 50*1c60b9acSAndroid Build Coastguard Workerlws-ssh-base is Free Software, available under libwebsockets' MIT license. 51*1c60b9acSAndroid Build Coastguard Worker 52*1c60b9acSAndroid Build Coastguard WorkerThe crypto parts are available elsewhere under a BSD license. But for 53*1c60b9acSAndroid Build Coastguard Workersimplicity the whole plugin is under MIT. 54*1c60b9acSAndroid Build Coastguard Worker 55*1c60b9acSAndroid Build Coastguard Worker## Generating your own keys 56*1c60b9acSAndroid Build Coastguard Worker 57*1c60b9acSAndroid Build Coastguard Worker``` 58*1c60b9acSAndroid Build Coastguard Worker $ ssh-keygen -t rsa -b 4096 -f mykeys 59*1c60b9acSAndroid Build Coastguard Worker``` 60*1c60b9acSAndroid Build Coastguard Worker 61*1c60b9acSAndroid Build Coastguard Workerwill ask for a passphrase and generate the private key in `mykeys` and the 62*1c60b9acSAndroid Build Coastguard Workerpublic key in `mykeys.pub`. If you already have a suitable RSA key you use 63*1c60b9acSAndroid Build Coastguard Workerwith ssh, you can just use that directly. 64*1c60b9acSAndroid Build Coastguard Worker 65*1c60b9acSAndroid Build Coastguard Workerlws installs a test keypair in /usr[/local]/share/libwebsockets-test-server 66*1c60b9acSAndroid Build Coastguard Workerthat the test apps will accept. 67*1c60b9acSAndroid Build Coastguard Worker 68*1c60b9acSAndroid Build Coastguard Worker## Example code 69*1c60b9acSAndroid Build Coastguard Worker 70*1c60b9acSAndroid Build Coastguard Worker1) There's a working example app `libwebsockets-test-sshd` included that 71*1c60b9acSAndroid Build Coastguard Workerspawns a bash shell when an ssh client authenticates. The username used on 72*1c60b9acSAndroid Build Coastguard Workerthe remote ssh has no meaning, it spawns the shell under the credentials of 73*1c60b9acSAndroid Build Coastguard Worker"lws-test-sshd" was run under. It accepts the lws ssh test key which is 74*1c60b9acSAndroid Build Coastguard Workerinstalled into /usr[/local]/share/libwebsockets-test-server. 75*1c60b9acSAndroid Build Coastguard Worker 76*1c60b9acSAndroid Build Coastguard WorkerStart the server like this (it wants root only because the server key is stored 77*1c60b9acSAndroid Build Coastguard Workerin /etc) 78*1c60b9acSAndroid Build Coastguard Worker 79*1c60b9acSAndroid Build Coastguard Worker``` 80*1c60b9acSAndroid Build Coastguard Worker $ sudo libwebsockets-test-sshd 81*1c60b9acSAndroid Build Coastguard Worker``` 82*1c60b9acSAndroid Build Coastguard Worker 83*1c60b9acSAndroid Build Coastguard WorkerConnect to it using the test private key like this 84*1c60b9acSAndroid Build Coastguard Worker 85*1c60b9acSAndroid Build Coastguard Worker``` 86*1c60b9acSAndroid Build Coastguard Worker $ ssh -p 2200 -i /usr/local/share/libwebsockets-test-server/lws-ssh-test-keys [email protected] 87*1c60b9acSAndroid Build Coastguard Worker``` 88*1c60b9acSAndroid Build Coastguard Worker 89*1c60b9acSAndroid Build Coastguard Worker2) There's also a working example plugin `lws-sshd-demo` that "subclasses" the 90*1c60b9acSAndroid Build Coastguard Workerabstract `lws-ssh-base` plugin to make a protocol which can be used from, 91*1c60b9acSAndroid Build Coastguard Workereg, lwsws. For an lwsws vhost that listens on port 2222 and responds with 92*1c60b9acSAndroid Build Coastguard Workerthe lws-sshd-demo ssh server, the related config is: 93*1c60b9acSAndroid Build Coastguard Worker 94*1c60b9acSAndroid Build Coastguard Worker``` 95*1c60b9acSAndroid Build Coastguard Worker { 96*1c60b9acSAndroid Build Coastguard Worker "name": "sshd", 97*1c60b9acSAndroid Build Coastguard Worker "port": "2222", 98*1c60b9acSAndroid Build Coastguard Worker "onlyraw": "1", 99*1c60b9acSAndroid Build Coastguard Worker "ws-protocols": [{ 100*1c60b9acSAndroid Build Coastguard Worker "lws-ssh-base": { 101*1c60b9acSAndroid Build Coastguard Worker "status": "ok", 102*1c60b9acSAndroid Build Coastguard Worker "ops-from": "lws-sshd-demo" 103*1c60b9acSAndroid Build Coastguard Worker }, 104*1c60b9acSAndroid Build Coastguard Worker "lws-sshd-demo": { 105*1c60b9acSAndroid Build Coastguard Worker "status": "ok", 106*1c60b9acSAndroid Build Coastguard Worker "raw": "1" 107*1c60b9acSAndroid Build Coastguard Worker } 108*1c60b9acSAndroid Build Coastguard Worker }] 109*1c60b9acSAndroid Build Coastguard Worker } 110*1c60b9acSAndroid Build Coastguard Worker``` 111*1c60b9acSAndroid Build Coastguard Worker 112*1c60b9acSAndroid Build Coastguard Worker 113*1c60b9acSAndroid Build Coastguard Worker 114*1c60b9acSAndroid Build Coastguard Worker## Integration to other apps 115*1c60b9acSAndroid Build Coastguard Worker 116*1c60b9acSAndroid Build Coastguard Worker### Step 0: Build and install libwebsockets 117*1c60b9acSAndroid Build Coastguard Worker 118*1c60b9acSAndroid Build Coastguard WorkerFor the `libwebsockets-test-sshd` example, you will need CMake options 119*1c60b9acSAndroid Build Coastguard Worker`LWS_WITH_CGI`, since it uses lws helpers to spawn a shell. 120*1c60b9acSAndroid Build Coastguard Worker 121*1c60b9acSAndroid Build Coastguard Workerlws-ssh-base itself doesn't require CGI support in libwebsockets. 122*1c60b9acSAndroid Build Coastguard Worker 123*1c60b9acSAndroid Build Coastguard Worker### Step 1: make the code available in your app 124*1c60b9acSAndroid Build Coastguard Worker 125*1c60b9acSAndroid Build Coastguard WorkerInclude `lws-plugin-ssh-base` in your app, either as a runtime plugin or by using 126*1c60b9acSAndroid Build Coastguard Workerthe lws static include scheme. 127*1c60b9acSAndroid Build Coastguard Worker 128*1c60b9acSAndroid Build Coastguard WorkerTo bring in the whole of the ssh-base plugin 129*1c60b9acSAndroid Build Coastguard Workerinto your app in one step, statically, just include 130*1c60b9acSAndroid Build Coastguard Worker`plugins/ssh-base/include/lws-plugin-sshd-static-build-includes.h`, you can see 131*1c60b9acSAndroid Build Coastguard Workeran example of this in `./test-apps/test-sshd.c`. 132*1c60b9acSAndroid Build Coastguard Worker 133*1c60b9acSAndroid Build Coastguard Worker### Step 2: define your `struct lws_ssh_ops` 134*1c60b9acSAndroid Build Coastguard Worker 135*1c60b9acSAndroid Build Coastguard Worker`plugins/ssh-base/include/lws-plugin-ssh.h` defines 136*1c60b9acSAndroid Build Coastguard Worker`struct lws_ssh_ops` which is used for all customization and integration 137*1c60b9acSAndroid Build Coastguard Workerof the plugin per vhost. Eg, 138*1c60b9acSAndroid Build Coastguard Worker 139*1c60b9acSAndroid Build Coastguard Worker``` 140*1c60b9acSAndroid Build Coastguard Workerstatic const struct lws_ssh_ops ssh_ops = { 141*1c60b9acSAndroid Build Coastguard Worker .channel_create = ssh_ops_channel_create, 142*1c60b9acSAndroid Build Coastguard Worker .channel_destroy = ssh_ops_channel_destroy, 143*1c60b9acSAndroid Build Coastguard Worker .tx_waiting = ssh_ops_tx_waiting, 144*1c60b9acSAndroid Build Coastguard Worker .tx = ssh_ops_tx, 145*1c60b9acSAndroid Build Coastguard Worker .rx = ssh_ops_rx, 146*1c60b9acSAndroid Build Coastguard Worker .get_server_key = ssh_ops_get_server_key, 147*1c60b9acSAndroid Build Coastguard Worker .set_server_key = ssh_ops_set_server_key, 148*1c60b9acSAndroid Build Coastguard Worker .set_env = ssh_ops_set_env, 149*1c60b9acSAndroid Build Coastguard Worker .pty_req = ssh_ops_pty_req, 150*1c60b9acSAndroid Build Coastguard Worker .child_process_io = ssh_ops_child_process_io, 151*1c60b9acSAndroid Build Coastguard Worker .child_process_terminated = ssh_ops_child_process_terminated, 152*1c60b9acSAndroid Build Coastguard Worker .exec = ssh_ops_exec, 153*1c60b9acSAndroid Build Coastguard Worker .shell = ssh_ops_shell, 154*1c60b9acSAndroid Build Coastguard Worker .is_pubkey_authorized = ssh_ops_is_pubkey_authorized, 155*1c60b9acSAndroid Build Coastguard Worker .banner = ssh_ops_banner, 156*1c60b9acSAndroid Build Coastguard Worker .disconnect_reason = ssh_ops_disconnect_reason, 157*1c60b9acSAndroid Build Coastguard Worker .server_string = "SSH-2.0-Libwebsockets", 158*1c60b9acSAndroid Build Coastguard Worker .api_version = 1, 159*1c60b9acSAndroid Build Coastguard Worker}; 160*1c60b9acSAndroid Build Coastguard Worker``` 161*1c60b9acSAndroid Build Coastguard WorkerThe `ssh_ops_...()` functions are your implementations for the operations 162*1c60b9acSAndroid Build Coastguard Workerneeded by the plugin for your purposes. 163*1c60b9acSAndroid Build Coastguard Worker 164*1c60b9acSAndroid Build Coastguard Worker### Step 3: enable `lws-ssh-base` protocol to a vhost and configure using pvo 165*1c60b9acSAndroid Build Coastguard Worker 166*1c60b9acSAndroid Build Coastguard WorkerA pointer to your struct lws_ssh_ops is passed into the vhost instance of the 167*1c60b9acSAndroid Build Coastguard Workerprotocol using per-vhost options 168*1c60b9acSAndroid Build Coastguard Worker 169*1c60b9acSAndroid Build Coastguard Worker``` 170*1c60b9acSAndroid Build Coastguard Workerstatic const struct lws_protocol_vhost_options pvo_ssh_ops = { 171*1c60b9acSAndroid Build Coastguard Worker NULL, 172*1c60b9acSAndroid Build Coastguard Worker NULL, 173*1c60b9acSAndroid Build Coastguard Worker "ops", 174*1c60b9acSAndroid Build Coastguard Worker (void *)&ssh_ops 175*1c60b9acSAndroid Build Coastguard Worker}; 176*1c60b9acSAndroid Build Coastguard Worker 177*1c60b9acSAndroid Build Coastguard Workerstatic const struct lws_protocol_vhost_options pvo_ssh = { 178*1c60b9acSAndroid Build Coastguard Worker NULL, 179*1c60b9acSAndroid Build Coastguard Worker &pvo_ssh_ops, 180*1c60b9acSAndroid Build Coastguard Worker "lws-sshd-base", 181*1c60b9acSAndroid Build Coastguard Worker "" /* ignored, just matches the protocol name above */ 182*1c60b9acSAndroid Build Coastguard Worker}; 183*1c60b9acSAndroid Build Coastguard Worker 184*1c60b9acSAndroid Build Coastguard Worker... 185*1c60b9acSAndroid Build Coastguard Worker info.port = 22; 186*1c60b9acSAndroid Build Coastguard Worker info.options = LWS_SERVER_OPTION_ONLY_RAW; 187*1c60b9acSAndroid Build Coastguard Worker info.vhost_name = "sshd"; 188*1c60b9acSAndroid Build Coastguard Worker info.protocols = protocols_sshd; 189*1c60b9acSAndroid Build Coastguard Worker info.pvo = &pvo_ssh; 190*1c60b9acSAndroid Build Coastguard Worker 191*1c60b9acSAndroid Build Coastguard Worker vh_sshd = lws_create_vhost(context, &info); 192*1c60b9acSAndroid Build Coastguard Worker``` 193*1c60b9acSAndroid Build Coastguard Worker 194*1c60b9acSAndroid Build Coastguard WorkerThere are two possible pvos supported, "ops", shown above, directly passes the 195*1c60b9acSAndroid Build Coastguard Workerops structure in using the value on the "ops" pvo. 196*1c60b9acSAndroid Build Coastguard Worker 197*1c60b9acSAndroid Build Coastguard WorkerTo support other protocols that want to provide ops to lws-ssh-base themselves 198*1c60b9acSAndroid Build Coastguard Workerfor a particular vhost, you can also provide a pvo `"ops-from"` whose value is 199*1c60b9acSAndroid Build Coastguard Workerthe name of the protocol also enabled on this vhost, whose protocol ".user" 200*1c60b9acSAndroid Build Coastguard Workerpointer points to the ops struct lws-ssh-base should use. 201*1c60b9acSAndroid Build Coastguard Worker 202*1c60b9acSAndroid Build Coastguard Worker## Integration to other plugins 203*1c60b9acSAndroid Build Coastguard Worker 204*1c60b9acSAndroid Build Coastguard WorkerA worked example of using the abstract `lws-ssh-base` plugin from another 205*1c60b9acSAndroid Build Coastguard Workerplugin that provides the ops struct is in `./plugins/protocol_lws_sshd_demo`. 206*1c60b9acSAndroid Build Coastguard Worker 207*1c60b9acSAndroid Build Coastguard WorkerThe key points to note 208*1c60b9acSAndroid Build Coastguard Worker 209*1c60b9acSAndroid Build Coastguard Worker - the plugin sets the ops struct for the vhost instantiation of `lws-ssh-base` 210*1c60b9acSAndroid Build Coastguard Worker by passing a pointer to the ops struct in its `lws_protocols` struct `user` 211*1c60b9acSAndroid Build Coastguard Worker member. 212*1c60b9acSAndroid Build Coastguard Worker 213*1c60b9acSAndroid Build Coastguard Worker - the config for the vhost tells `lws-ssh-base` to pick up the ops struct 214*1c60b9acSAndroid Build Coastguard Worker pointer using an "ops-from" pvo that indicates the protocol name. 215*1c60b9acSAndroid Build Coastguard Worker 216*1c60b9acSAndroid Build Coastguard Worker``` 217*1c60b9acSAndroid Build Coastguard Worker "lws-ssh-base": { 218*1c60b9acSAndroid Build Coastguard Worker "status": "ok", 219*1c60b9acSAndroid Build Coastguard Worker "ops-from": "lws-sshd-demo" 220*1c60b9acSAndroid Build Coastguard Worker }, 221*1c60b9acSAndroid Build Coastguard Worker``` 222*1c60b9acSAndroid Build Coastguard Worker 223*1c60b9acSAndroid Build Coastguard Worker - the config for the vhost tells lws this vhost only serves RAW (ie, no http) 224*1c60b9acSAndroid Build Coastguard Worker 225*1c60b9acSAndroid Build Coastguard Worker``` 226*1c60b9acSAndroid Build Coastguard Worker { 227*1c60b9acSAndroid Build Coastguard Worker "name": "sshd", 228*1c60b9acSAndroid Build Coastguard Worker "port": "2222", 229*1c60b9acSAndroid Build Coastguard Worker "onlyraw": "1", 230*1c60b9acSAndroid Build Coastguard Worker ... 231*1c60b9acSAndroid Build Coastguard Worker``` 232*1c60b9acSAndroid Build Coastguard Worker 233*1c60b9acSAndroid Build Coastguard Worker - the config for the vhost marks the protocol that uses `lws-ssh-base`, not 234*1c60b9acSAndroid Build Coastguard Worker `lws-ssh-base` itself, as the protocol to be served for raw connections 235*1c60b9acSAndroid Build Coastguard Worker 236*1c60b9acSAndroid Build Coastguard Worker``` 237*1c60b9acSAndroid Build Coastguard Worker "lws-sshd-demo": { 238*1c60b9acSAndroid Build Coastguard Worker "status": "ok", 239*1c60b9acSAndroid Build Coastguard Worker "raw": "1" 240*1c60b9acSAndroid Build Coastguard Worker ... 241*1c60b9acSAndroid Build Coastguard Worker``` 242*1c60b9acSAndroid Build Coastguard Worker 243*1c60b9acSAndroid Build Coastguard Worker## Notes 244*1c60b9acSAndroid Build Coastguard Worker 245*1c60b9acSAndroid Build Coastguard WorkerYou can have the vhost it binds to listen on a nonstandard port. The ssh 246*1c60b9acSAndroid Build Coastguard Workercommandline app cane be told to connect to a non-22 port with 247*1c60b9acSAndroid Build Coastguard Worker`ssh -p portnum user@hostname` 248*1c60b9acSAndroid Build Coastguard Worker 249*1c60b9acSAndroid Build Coastguard Worker 250