Skip to content

Commit

Permalink
davidrg#83 - SSH KEY CREATE now works
Browse files Browse the repository at this point in the history
  • Loading branch information
davidrg committed Sep 2, 2022
1 parent 69d5b1a commit 41c6ee5
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 31 deletions.
2 changes: 2 additions & 0 deletions doc/ssh-readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ SSH [OPEN] host [port]
Just reports an error if version is 1 (SSH-1 not supported)
/SUBSYSTEM:name
Implemented though doesn't appear to be working at the moment
SSH KEY CREATE [ /BITS:bits /PASSPHRASE:passphrase /TYPE:{ DSS, ECDSA, ED25519, RSA } ] filename
Creates an SSH key pair
SET SSH
COMPRESSION {ON,OFF}
HEARTBEAT-INTERVAL interval
Expand Down
235 changes: 227 additions & 8 deletions kermit/k95/ckossh.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ char *cksshv = "SSH support, 10.0.0, 28 July 2022";
* where all the work is done (using libssh) lives in ckoshs.c.
*/

#include <libssh/libssh.h>

#include "ckcdeb.h"
#include "ckossh.h"
#include "ckcker.h"

#include "ckuusr.h"
#include "ckoshs.h"


/* Global Variables:
* These are all declared in ckuus3.c around like 8040
*
Expand Down Expand Up @@ -132,12 +134,11 @@ char *cksshv = "SSH support, 10.0.0, 28 July 2022";
* TODO: /NEW-PASSPHRASE:passphrase
* TODO: /OLD-PASSPHRASE:passphrase
* TODO: filename
* TODO: CREATE
* TODO: /BITS:bits
* TODO: /PASSPHRASE: passphrase
* TODO: /TYPE:{V1-RSA,V2-DSA,V2-RSA}
* TODO: /V1-RSA-COMMENT: comment
* TODO: filename
* CREATE
* /BITS:bits
* /PASSPHRASE: passphrase
* /TYPE:{ DSS, ECDSA, ED25519, RSA }
* filename
* TODO: DISPLAY
* TODO: /FORMAT:{fingerprint, ietf,openssh,ssh.com}
* TODO: filename
Expand All @@ -157,6 +158,7 @@ char *cksshv = "SSH support, 10.0.0, 28 July 2022";
* TODO: KERBEROS5 TGT-PASSING {ON,OFF} -- delete
* TODO: PRIVILEGED-PORT {ON,OFF}
* TODO: QUIET {ON,OFF}
* -> This should suppress all printfs
* STRICT-HOST-KEY-CHECK {ASK, ON, OFF}
* USE-OPENSSH-CONFIG {ON,OFF}
* Value is stored in ssh_cfg
Expand Down Expand Up @@ -962,8 +964,225 @@ int ssh_fwd_remote_port(int port, char * host, int host_port)
return SSH_ERR_NOT_IMPLEMENTED; /* TODO */
}

/* These live in ckoreg.c */
char* GetHomePath();
char* GetHomeDrive();

/** Creates a
*
* @param filename File to write the private key to
* @param bits Length of the key in bits. Valid options vary by key type
* @param pp Passphrase
* @param type Key type
* @param cmd_comment SSH V1 RSA Comment (obsolete)
* @return
*/
int sshkey_create(char * filename, int bits, char * pp, int type, char * cmd_comment) {
return SSH_ERR_NOT_IMPLEMENTED; /* TODO */
enum ssh_keytypes_e ktype;
char *output_filename = NULL, *pubkey_output_filename = NULL,
*passphrase = NULL, *default_filename = NULL;
ssh_key key = NULL;
int rc;

debug(F100, "sshkey_create", "", 0);

/* By default, openssh searches for id_rsa, id_ecdsa, id_ecdsa_sk,
* id_ed25519, id_ed25519_sk and id_dsa */
switch(type) {
case SSHKT_DSS:
default_filename = "id_dsa";
ktype = SSH_KEYTYPE_DSS;
if (bits == 0) bits = 1024;
if (bits != 1024 && bits != 2048) {
printf("Invalid key length %d - valid options are: 1024, 2048\n");
}
break;
case SSHKT_RSA:
default_filename = "id_rsa";
ktype = SSH_KEYTYPE_RSA;
if (bits == 0) bits = 3072;
if (bits != 1024 && bits != 2048 && bits != 3072 &&
bits != 2048 && bits != 8192) {
printf("Invalid key length %d - valid options are: 1024, 2048, 3072, 4096, 8192\n");
return SSH_ERR_UNSPECIFIED;
}
break;
case SSHKT_RSA1:
default_filename = NULL;
ktype = SSH_KEYTYPE_RSA1;
if (bits == 0) bits = 3072;
if (bits != 1024 && bits != 2048 && bits != 3072 &&
bits != 2048 && bits != 8192) {
printf("Invalid key length %d - valid options are: 1024, 2048, 3072, 4096, 8192\n");
return SSH_ERR_UNSPECIFIED;
}
break;
case SSHKT_ECDSA:
default_filename = "id_ecdsa";
ktype = SSH_KEYTYPE_ECDSA;
if (bits == 0) bits = 256;
if (bits != 256 && bits != 384 && bits != 521) {
printf("Invalid key length %d - valid options are: 256, 384, 521\n");
return SSH_ERR_UNSPECIFIED;
}
break;
case SSHKT_ED25519:
default_filename = "id_ed25519";
ktype = SSH_KEYTYPE_ED25519;
bits = 0; /* No bits */
break;
case SSHKT_DSS_CERT01:
default_filename = NULL;
ktype = SSH_KEYTYPE_DSS_CERT01;
break;
case SSHKT_RSA_CERT01:
default_filename = NULL;
ktype = SSH_KEYTYPE_RSA_CERT01;
break;
case SSHKT_ECDSA_P256:
default_filename = NULL;
ktype = SSH_KEYTYPE_ECDSA_P256;
break;
case SSHKT_ECDSA_P384:
default_filename = NULL;
ktype = SSH_KEYTYPE_ECDSA_P384;
break;
case SSHKT_ECDSA_P521:
default_filename = NULL;
ktype = SSH_KEYTYPE_ECDSA_P521;
break;
case SSHKT_ECDSA_P256_CERT01:
default_filename = NULL;
ktype = SSH_KEYTYPE_ECDSA_P256_CERT01;
break;
case SSHKT_ECDSA_P384_CERT01:
default_filename = NULL;
ktype = SSH_KEYTYPE_ECDSA_P384_CERT01;
break;
case SSHKT_ECDSA_P521_CERT01:
default_filename = NULL;
ktype = SSH_KEYTYPE_ECDSA_P521_CERT01;
break;
case SSHKT_ED25519_CERT01:
default_filename = NULL;
ktype = SSH_KEYTYPE_ED25519_CERT01;
break;
default:
printf("Unrecognised or unsupported key type\n");
return SSH_ERR_UNSPECIFIED;
}

printf("Bits: %d\n", bits);

if (filename) {
output_filename = _strdup(filename);
} else {
char* default_pathname;
output_filename = malloc(MAX_PATH * sizeof(char));
default_pathname = malloc(MAX_PATH * sizeof(char));

/* We'll suggest the user save in %USERPROFILE%\.ssh by default as thats
* where both C-Kermit and the windows builds of OpenSSH look */
snprintf(default_pathname, MAX_PATH, "%s%s.ssh/%s",
GetHomeDrive(), GetHomePath(), default_filename);
#ifdef CK_MKDIR
/* Make the .ssh directory if it doesn't already exist */
zmkdir(default_pathname);
#endif

/* GetHomePath gives unix-style directory separators which the windows
* file dialog doesn't seem to like. So convert to DOS separators */
for (int i = 0; i < MAX_PATH; i++) {
if (default_pathname[i] == '\0') break;
if (default_pathname[i] == '/') default_pathname[i] = '\\';
}

int rc = uq_file(
"Enter a filename to save the generated keys to:", /* Text mode only, text above the prompt */
"Save As", /* file dialog title or text-mode prompt*/
5, /* New file, don't append */
NULL, /* Help text - not used */
default_pathname,
output_filename,
MAX_PATH
);
free(default_pathname);

if (rc == 0) {
free(output_filename);
return SSH_ERR_USER_CANCELED;
} else if (rc < 0 ) {
free(output_filename);
return SSH_ERR_UNSPECIFIED;
}
}

if (pp) {
passphrase = _strdup(pp);
}
else {
/* Prompt for passphrase. Two fields to get confirmation. */
char pp1[250], pp2[250];
struct txtbox fields[2];

fields[0].t_buf = pp1;
fields[0].t_len = sizeof(pp1);
fields[0].t_lbl = "New passphrase: ";
fields[0].t_dflt = NULL;
fields[0].t_echo = 2;

fields[1].t_buf = pp2;
fields[1].t_len = sizeof(pp2);
fields[1].t_lbl = "New passphrase (again): ";
fields[1].t_dflt = NULL;
fields[1].t_echo = 2;

rc = uq_mtxt("Enter SSH Key passphrase. Leave both fields empty empty "
"for no passphrase.",
NULL, 2, fields);

if ( !rc ) {
printf("User cancelled\n");
free(output_filename);
return(SSH_ERR_USER_CANCELED);
}

if (strcmp(pp1, pp2) != 0) {
printf("Passphrase mismatch, no action taken\n");
free(output_filename);
return(SSH_ERR_UNSPECIFIED);
}

if (strlen(pp1) > 0) {
passphrase = _strdup(pp1);
}
}

printf("Generating private key...\n");
rc = ssh_pki_generate(ktype, bits, &key);
if (rc != SSH_OK) {
printf("Failed to generate private key\n");
return SSH_ERR_UNSPECIFIED;
}

rc = ssh_pki_export_privkey_file(key, passphrase, NULL, NULL, output_filename);
if (rc != SSH_OK) {
printf("Failed to write private key to %s - error %d\n", output_filename, rc);
} else {
pubkey_output_filename = malloc(MAX_PATH);

snprintf(pubkey_output_filename, MAX_PATH, "%s.pub", output_filename);
rc = ssh_pki_export_pubkey_file(key, pubkey_output_filename);
if (rc != SSH_OK) {
printf("Failed to write public key to %s\n", pubkey_output_filename);
}

free(pubkey_output_filename);
}

free(output_filename);
free(passphrase);
return SSH_ERR_NO_ERROR;
}

int sshkey_display_fingerprint(char * filename, int babble) {
Expand Down
31 changes: 20 additions & 11 deletions kermit/k95/ckuus2.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,13 +724,14 @@ static char * hmxxssh[] = {
" ",
"SSH KEY commands:",
" The SSH KEY commands create and manage public and private key pairs",
" (identities). There are three forms of SSH keys. Each key pair is",
" (identities). There are four forms of SSH keys. Each key pair is",
" stored in its own set of files:",
" ",
" Key Type Private Key File Public Key File",
" v1 RSA keys \\v(appdata)ssh/identity \\v(appdata)ssh/identity.pub",
" v2 RSA keys \\v(appdata)ssh/id_rsa \\v(appdata)ssh/id_rsa.pub",
" v2 DSA keys \\v(appdata)ssh/id_dsa \\v(appdata)ssh/id_dsa.pub",
" RSA keys \\v(home).ssh/id_rsa \\v(home).ssh/id_rsa.pub",
" DSA keys \\v(home).ssh/id_dsa \\v(home).ssh/id_dsa.pub",
" ECDSA keys \\v(home).ssh/id_ecdsa \\v(home).ssh/id_ecdsa.pub",
" ED25519 keys \\v(home).ssh/id_ed25519 \\v(home).ssh/id_ed25519.pub",
" ",
" Keys are stored using the OpenSSH keyfile format. The private key",
" files can be (optionally) protected by specifying a passphrase. A",
Expand All @@ -751,21 +752,29 @@ static char * hmxxssh[] = {
" not provided Kermit prompts your for them.",
" ",
"SSH KEY CREATE [ /BITS:bits /PASSPHRASE:passphrase",
" /TYPE:{ V1-RSA, V2-DSA, V2-RSA } /V1-RSA-COMMENT:comment ] filename",
" This command creates a new private/public key pair. The defaults are:",
" BITS:1024 and TYPE:V2-RSA. The filename is the name of the private",
" key file. The public key is created with the same name with .pub",
" appended to it. If a filename is not specified Kermit prompts you for",
" it. V1 RSA key files may have an optional comment, which is ignored",
" for other key types.",
" /TYPE:{ DSS, ECDSA, ED25519, RSA } ] filename",
" This command creates a new private/public key pair. The defaults is",
" TYPE:ED25519. The filename is the name of the private key file. The",
" The public key is created with the same name with .pub appended to it.",
" If a filename is not specified Kermit prompts you for it. Key length ",
" options (/BITS:) depends on the key type:",
" ",
" ECDSA: 256 (default), 384, 521",
" RSA: 1024, 2048, 3072 (default), 4096, 8192",
" DSS: 1024 (default), 2048",
" ",
" ED25519 does not support being given a key length and any value supplied",
" via /BITS: will be ignored.",
" ",
"SSH KEY DISPLAY [ /FORMAT:{FINGERPRINT,IETF,OPENSSH,SSH.COM} ] filename",
" This command displays the contents of a public or private key file.",
" The default format is OPENSSH.",
" ",
#ifdef COMMENT
"SSH KEY V1 SET-COMMENT filename comment",
" This command replaces the comment associated with a V1 RSA key file.",
" ",
#endif
"SSH [ OPEN ] host [ port ] [ /COMMAND:command /USER:username",
" /PASSWORD:pwd /VERSION:{ 1, 2 } /X11-FORWARDING:{ ON, OFF } ]",
" This command establishes a new connection using SSH version 1 or",
Expand Down
Loading

0 comments on commit 41c6ee5

Please sign in to comment.