diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2000-11-12 19:50:40 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2000-11-12 19:50:40 +0000 |
commit | 08a300f8ea3923509e7599236fd8c92d4ff80f5f (patch) | |
tree | 6386a70117e2acdfb8008e63d4f69e20f0df2fea /usr.bin/ssh | |
parent | 4bd022ed91b4335e2a93ecc0f362502599edb9ea (diff) |
add support for RSA to SSH2. please test.
there are now 3 types of keys: RSA1 is used by ssh-1 only,
RSA and DSA are used by SSH2.
you can use 'ssh-keygen -t rsa -f ssh2_rsa_file' to generate RSA
keys for SSH2 and use the RSA keys for hostkeys or for user keys.
SSH2 RSA or DSA keys are added to .ssh/authorised_keys2 as before.
IdentityFile2, HostDsaKey and DSAAuthentication are obsolete.
you can use multiple IdentityFile and HostKey for all types of keys.
the option DSAAuthentication is replaced by PubkeyAuthetication.
Diffstat (limited to 'usr.bin/ssh')
34 files changed, 1308 insertions, 812 deletions
diff --git a/usr.bin/ssh/auth-rh-rsa.c b/usr.bin/ssh/auth-rh-rsa.c index 3070c9d4138..a9f17ef8383 100644 --- a/usr.bin/ssh/auth-rh-rsa.c +++ b/usr.bin/ssh/auth-rh-rsa.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rh-rsa.c,v 1.17 2000/10/03 18:03:03 markus Exp $"); +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.18 2000/11/12 19:50:37 markus Exp $"); #include "packet.h" #include "ssh.h" @@ -53,10 +53,10 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); /* wrap the RSA key into a 'generic' key */ - client_key = key_new(KEY_RSA); + client_key = key_new(KEY_RSA1); BN_copy(client_key->rsa->e, client_host_key->e); BN_copy(client_key->rsa->n, client_host_key->n); - found = key_new(KEY_RSA); + found = key_new(KEY_RSA1); /* Check if we know the host and its host key. */ host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, diff --git a/usr.bin/ssh/auth2.c b/usr.bin/ssh/auth2.c index b20f712ae90..d50fd0693ea 100644 --- a/usr.bin/ssh/auth2.c +++ b/usr.bin/ssh/auth2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.21 2000/11/12 19:50:37 markus Exp $"); #include <openssl/dsa.h> #include <openssl/rsa.h> @@ -47,7 +47,6 @@ RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); #include "key.h" #include "kex.h" -#include "dsa.h" #include "uidswap.h" #include "auth-options.h" @@ -76,7 +75,7 @@ void protocol_error(int type, int plen, void *ctxt); /* helper */ Authmethod *authmethod_lookup(const char *name); struct passwd *pwcopy(struct passwd *pw); -int user_dsa_key_allowed(struct passwd *pw, Key *key); +int user_key_allowed(struct passwd *pw, Key *key); char *authmethods_get(void); /* auth */ @@ -91,7 +90,7 @@ Authmethod authmethods[] = { &one}, {"publickey", userauth_pubkey, - &options.dsa_authentication}, + &options.pubkey_authentication}, {"keyboard-interactive", userauth_kbdint, &options.kbd_interactive_authentication}, @@ -359,7 +358,7 @@ userauth_pubkey(Authctxt *authctxt) Key *key; char *pkalg, *pkblob, *sig; unsigned int alen, blen, slen; - int have_sig; + int have_sig, pktype; int authenticated = 0; if (!authctxt->valid) { @@ -368,13 +367,14 @@ userauth_pubkey(Authctxt *authctxt) } have_sig = packet_get_char(); pkalg = packet_get_string(&alen); - if (strcmp(pkalg, KEX_DSS) != 0) { - log("bad pkalg %s", pkalg); /*XXX*/ + pktype = key_type_from_name(pkalg); + if (pktype == KEY_UNSPEC) { + log("bad pkalg %s", pkalg); xfree(pkalg); return 0; } pkblob = packet_get_string(&blen); - key = dsa_key_from_blob(pkblob, blen); + key = key_from_blob(pkblob, blen); if (key != NULL) { if (have_sig) { sig = packet_get_string(&slen); @@ -394,14 +394,14 @@ userauth_pubkey(Authctxt *authctxt) authctxt->service); buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_string(&b, pkblob, blen); -#ifdef DEBUG_DSS +#ifdef DEBUG_PK buffer_dump(&b); #endif /* test for correct signature */ - if (user_dsa_key_allowed(authctxt->pw, key) && - dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) + if (user_key_allowed(authctxt->pw, key) && + key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) authenticated = 1; buffer_clear(&b); xfree(sig); @@ -417,7 +417,7 @@ userauth_pubkey(Authctxt *authctxt) * if a user is not allowed to login. is this an * issue? -markus */ - if (user_dsa_key_allowed(authctxt->pw, key)) { + if (user_key_allowed(authctxt->pw, key)) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); @@ -430,6 +430,7 @@ userauth_pubkey(Authctxt *authctxt) auth_clear_options(); key_free(key); } + debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); xfree(pkalg); xfree(pkblob); return authenticated; @@ -493,11 +494,10 @@ authmethod_lookup(const char *name) /* return 1 if user allows given key */ int -user_dsa_key_allowed(struct passwd *pw, Key *key) +user_key_allowed(struct passwd *pw, Key *key) { char line[8192], file[1024]; int found_key = 0; - unsigned int bits = -1; FILE *f; unsigned long linenum = 0; struct stat st; @@ -578,10 +578,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) if (!*cp || *cp == '\n' || *cp == '#') continue; - bits = key_read(found, &cp); - if (bits == 0) { + if (key_read(found, &cp) == -1) { /* no key? check if there are options for this key */ int quoted = 0; + debug2("user_key_allowed: check options: '%s'", cp); options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') @@ -592,8 +592,8 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; - bits = key_read(found, &cp); - if (bits == 0) { + if (key_read(found, &cp) == -1) { + debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } diff --git a/usr.bin/ssh/authfd.c b/usr.bin/ssh/authfd.c index d62b8d65e63..e48d8ff4773 100644 --- a/usr.bin/ssh/authfd.c +++ b/usr.bin/ssh/authfd.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.30 2000/11/12 19:50:37 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -50,7 +50,6 @@ RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $"); #include "key.h" #include "authfd.h" #include "kex.h" -#include "dsa.h" #include "compat.h" /* helper */ @@ -207,8 +206,8 @@ ssh_close_authentication_connection(AuthenticationConnection *auth) * Returns the first authentication identity held by the agent. */ -Key * -ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) +int +ssh_get_num_identities(AuthenticationConnection *auth, int version) { int type, code1 = 0, code2 = 0; Buffer request; @@ -223,7 +222,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi code2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: - return NULL; + return 0; } /* @@ -236,14 +235,14 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi buffer_clear(&auth->identities); if (ssh_request_reply(auth, &request, &auth->identities) == 0) { buffer_free(&request); - return NULL; + return 0; } buffer_free(&request); /* Get message type, and verify that we got a proper answer. */ type = buffer_get_char(&auth->identities); if (agent_failed(type)) { - return NULL; + return 0; } else if (type != code2) { fatal("Bad authentication reply message type: %d", type); } @@ -254,8 +253,16 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi fatal("Too many identities in authentication reply: %d\n", auth->howmany); - /* Return the first entry (if any). */ - return ssh_get_next_identity(auth, comment, version); + return auth->howmany; +} + +Key * +ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) +{ + /* get number of identities and return the first entry (if any). */ + if (ssh_get_num_identities(auth, version) > 0) + return ssh_get_next_identity(auth, comment, version); + return NULL; } Key * @@ -276,7 +283,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio */ switch(version){ case 1: - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); bits = buffer_get_int(&auth->identities); buffer_get_bignum(&auth->identities, key->rsa->e); buffer_get_bignum(&auth->identities, key->rsa->n); @@ -288,7 +295,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio case 2: blob = buffer_get_string(&auth->identities, &blen); *comment = buffer_get_string(&auth->identities, NULL); - key = dsa_key_from_blob(blob, blen); + key = key_from_blob(blob, blen); xfree(blob); break; default: @@ -320,7 +327,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth, int i; int type; - if (key->type != KEY_RSA) + if (key->type != KEY_RSA1) return 0; if (response_type == 0) { log("Compatibility with ssh protocol version 1.0 no longer supported."); @@ -372,7 +379,7 @@ ssh_agent_sign(AuthenticationConnection *auth, int type, flags = 0; int ret = -1; - if (dsa_make_key_blob(key, &blob, &blen) == 0) + if (key_to_blob(key, &blob, &blen) == 0) return -1; if (datafellows & SSH_BUG_SIGBLOB) @@ -405,7 +412,7 @@ ssh_agent_sign(AuthenticationConnection *auth, /* Encode key for a message to the agent. */ void -ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment) +ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) { buffer_clear(b); buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY); @@ -421,17 +428,29 @@ ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment) } void -ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment) +ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) { buffer_clear(b); buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY); - buffer_put_cstring(b, KEX_DSS); - buffer_put_bignum2(b, key->p); - buffer_put_bignum2(b, key->q); - buffer_put_bignum2(b, key->g); - buffer_put_bignum2(b, key->pub_key); - buffer_put_bignum2(b, key->priv_key); - buffer_put_string(b, comment, strlen(comment)); + buffer_put_cstring(b, key_ssh_name(key)); + switch(key->type){ + case KEY_RSA: + buffer_put_bignum2(b, key->rsa->n); + buffer_put_bignum2(b, key->rsa->e); + buffer_put_bignum2(b, key->rsa->d); + buffer_put_bignum2(b, key->rsa->iqmp); + buffer_put_bignum2(b, key->rsa->p); + buffer_put_bignum2(b, key->rsa->q); + break; + case KEY_DSA: + buffer_put_bignum2(b, key->dsa->p); + buffer_put_bignum2(b, key->dsa->q); + buffer_put_bignum2(b, key->dsa->g); + buffer_put_bignum2(b, key->dsa->pub_key); + buffer_put_bignum2(b, key->dsa->priv_key); + break; + } + buffer_put_cstring(b, comment); } /* @@ -448,11 +467,12 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) buffer_init(&msg); switch (key->type) { - case KEY_RSA: - ssh_encode_identity_rsa(&msg, key->rsa, comment); + case KEY_RSA1: + ssh_encode_identity_rsa1(&msg, key->rsa, comment); break; + case KEY_RSA: case KEY_DSA: - ssh_encode_identity_dsa(&msg, key->dsa, comment); + ssh_encode_identity_ssh2(&msg, key, comment); break; default: buffer_free(&msg); @@ -483,13 +503,13 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key) buffer_init(&msg); - if (key->type == KEY_RSA) { + if (key->type == KEY_RSA1) { buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->n); - } else if (key->type == KEY_DSA) { - dsa_make_key_blob(key, &blob, &blen); + } else if (key->type == KEY_DSA || key->type == KEY_RSA) { + key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); xfree(blob); diff --git a/usr.bin/ssh/authfd.h b/usr.bin/ssh/authfd.h index 2d2465206b4..65471ad7c21 100644 --- a/usr.bin/ssh/authfd.h +++ b/usr.bin/ssh/authfd.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: authfd.h,v 1.13 2000/10/09 21:51:00 markus Exp $"); */ +/* RCSID("$OpenBSD: authfd.h,v 1.14 2000/11/12 19:50:37 markus Exp $"); */ #ifndef AUTHFD_H #define AUTHFD_H @@ -75,6 +75,11 @@ AuthenticationConnection *ssh_get_authentication_connection(); void ssh_close_authentication_connection(AuthenticationConnection *auth); /* + * Returns the number authentication identity held by the agent. + */ +int ssh_get_num_identities(AuthenticationConnection *auth, int version); + +/* * Returns the first authentication identity held by the agent or NULL if * no identies are available. Caller must free comment and key. * Note that you cannot mix calls with different versions. diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c index fdeab801729..a74972970de 100644 --- a/usr.bin/ssh/authfile.c +++ b/usr.bin/ssh/authfile.c @@ -36,11 +36,12 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: authfile.c,v 1.21 2000/11/12 19:50:37 markus Exp $"); #include <openssl/bn.h> #include <openssl/dsa.h> #include <openssl/rsa.h> +#include <openssl/err.h> #include <openssl/pem.h> #include <openssl/evp.h> @@ -61,7 +62,7 @@ RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); */ int -save_private_key_rsa(const char *filename, const char *passphrase, +save_private_key_rsa1(const char *filename, const char *passphrase, RSA *key, const char *comment) { Buffer buffer, encrypted; @@ -155,16 +156,17 @@ save_private_key_rsa(const char *filename, const char *passphrase, return 1; } -/* save DSA key in OpenSSL PEM format */ - +/* save SSH2 key in OpenSSL PEM format */ int -save_private_key_dsa(const char *filename, const char *passphrase, - DSA *dsa, const char *comment) +save_private_key_ssh2(const char *filename, const char *_passphrase, + Key *key, const char *comment) { FILE *fp; int fd; - int success = 1; - int len = strlen(passphrase); + int success = 0; + int len = strlen(_passphrase); + char *passphrase = (len > 0) ? (char *)_passphrase : NULL; + EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; if (len > 0 && len <= 4) { error("passphrase too short: %d bytes", len); @@ -182,14 +184,15 @@ save_private_key_dsa(const char *filename, const char *passphrase, close(fd); return 0; } - if (len > 0) { - if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(), - (char *)passphrase, strlen(passphrase), NULL, NULL)) - success = 0; - } else { - if (!PEM_write_DSAPrivateKey(fp, dsa, NULL, - NULL, 0, NULL, NULL)) - success = 0; + switch (key->type) { + case KEY_DSA: + success = PEM_write_DSAPrivateKey(fp, key->dsa, + cipher, passphrase, len, NULL, NULL); + break; + case KEY_RSA: + success = PEM_write_RSAPrivateKey(fp, key->rsa, + cipher, passphrase, len, NULL, NULL); + break; } fclose(fp); return success; @@ -200,11 +203,12 @@ save_private_key(const char *filename, const char *passphrase, Key *key, const char *comment) { switch (key->type) { - case KEY_RSA: - return save_private_key_rsa(filename, passphrase, key->rsa, comment); + case KEY_RSA1: + return save_private_key_rsa1(filename, passphrase, key->rsa, comment); break; case KEY_DSA: - return save_private_key_dsa(filename, passphrase, key->dsa, comment); + case KEY_RSA: + return save_private_key_ssh2(filename, passphrase, key, comment); break; default: break; @@ -246,7 +250,7 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) /* Check that it is at least big enought to contain the ID string. */ if (len < strlen(AUTHFILE_ID_STRING) + 1) { - debug("Bad key file %.200s.", filename); + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -256,7 +260,7 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) */ for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { - debug("Bad key file %.200s.", filename); + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -288,10 +292,11 @@ int load_public_key(const char *filename, Key * key, char **comment_return) { switch (key->type) { - case KEY_RSA: + case KEY_RSA1: return load_public_key_rsa(filename, key->rsa, comment_return); break; case KEY_DSA: + case KEY_RSA: default: break; } @@ -306,7 +311,7 @@ load_public_key(const char *filename, Key * key, char **comment_return) */ int -load_private_key_rsa(int fd, const char *filename, +load_private_key_rsa1(int fd, const char *filename, const char *passphrase, RSA * prv, char **comment_return) { int i, check1, check2, cipher_type; @@ -326,7 +331,7 @@ load_private_key_rsa(int fd, const char *filename, if (read(fd, cp, (size_t) len) != (size_t) len) { debug("Read from key file %.200s failed: %.100s", filename, - strerror(errno)); + strerror(errno)); buffer_free(&buffer); close(fd); return 0; @@ -335,7 +340,7 @@ load_private_key_rsa(int fd, const char *filename, /* Check that it is at least big enought to contain the ID string. */ if (len < strlen(AUTHFILE_ID_STRING) + 1) { - debug("Bad key file %.200s.", filename); + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -344,8 +349,8 @@ load_private_key_rsa(int fd, const char *filename, * from the buffer. */ for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) - if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { - debug("Bad key file %.200s.", filename); + if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -431,40 +436,59 @@ fail: } int -load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return) +load_private_key_ssh2(int fd, const char *passphrase, Key *k, char **comment_return) { - DSA *dsa; - BIO *in; FILE *fp; + int success = 0; + EVP_PKEY *pk = NULL; + char *name = "<no key>"; - in = BIO_new(BIO_s_file()); - if (in == NULL) { - error("BIO_new failed"); - return 0; - } fp = fdopen(fd, "r"); if (fp == NULL) { error("fdopen failed"); return 0; } - BIO_set_fp(in, fp, BIO_NOCLOSE); - dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase); - if (dsa == NULL) { - debug("PEM_read_bio_DSAPrivateKey failed"); - } else { + pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); + if (pk == NULL) { + debug("PEM_read_PrivateKey failed"); + (void)ERR_get_error(); + } else if (pk->type == EVP_PKEY_RSA) { + /* replace k->rsa with loaded key */ + if (k->type == KEY_RSA || k->type == KEY_UNSPEC) { + if (k->rsa != NULL) + RSA_free(k->rsa); + k->rsa = EVP_PKEY_get1_RSA(pk); + k->type = KEY_RSA; + name = "rsa w/o comment"; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, k->rsa, 8); +#endif + } + } else if (pk->type == EVP_PKEY_DSA) { /* replace k->dsa with loaded key */ - DSA_free(k->dsa); - k->dsa = dsa; + if (k->type == KEY_DSA || k->type == KEY_UNSPEC) { + if (k->dsa != NULL) + DSA_free(k->dsa); + k->dsa = EVP_PKEY_get1_DSA(pk); + k->type = KEY_DSA; + name = "dsa w/o comment"; +#ifdef DEBUG_PK + DSA_print_fp(stderr, k->dsa, 8); +#endif + success = 1; + } + } else { + error("PEM_read_PrivateKey: mismatch or " + "unknown EVP_PKEY save_type %d", pk->save_type); } - BIO_free(in); fclose(fp); - if (comment_return) - *comment_return = xstrdup("dsa w/o comment"); - debug("read DSA private key done"); -#ifdef DEBUG_DSS - DSA_print_fp(stderr, dsa, 8); -#endif - return dsa != NULL ? 1 : 0; + if (pk != NULL) + EVP_PKEY_free(pk); + if (success && comment_return) + *comment_return = xstrdup(name); + debug("read SSH2 private key done: name %s success %d", name, success); + return success; } int @@ -493,7 +517,7 @@ load_private_key(const char *filename, const char *passphrase, Key *key, return 0; } switch (key->type) { - case KEY_RSA: + case KEY_RSA1: if (key->rsa->e != NULL) { BN_clear_free(key->rsa->e); key->rsa->e = NULL; @@ -502,11 +526,13 @@ load_private_key(const char *filename, const char *passphrase, Key *key, BN_clear_free(key->rsa->n); key->rsa->n = NULL; } - ret = load_private_key_rsa(fd, filename, passphrase, + ret = load_private_key_rsa1(fd, filename, passphrase, key->rsa, comment_return); break; case KEY_DSA: - ret = load_private_key_dsa(fd, passphrase, key, comment_return); + case KEY_RSA: + case KEY_UNSPEC: + ret = load_private_key_ssh2(fd, passphrase, key, comment_return); default: break; } @@ -518,7 +544,6 @@ int do_load_public_key(const char *filename, Key *k, char **commentp) { FILE *f; - unsigned int bits; char line[1024]; char *cp; @@ -537,8 +562,7 @@ do_load_public_key(const char *filename, Key *k, char **commentp) for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) ; if (*cp) { - bits = key_read(k, &cp); - if (bits != 0) { + if (key_read(k, &cp) == 1) { if (commentp) *commentp=xstrdup(filename); fclose(f); diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index 9c03a468800..3b0f286fd6f 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: hostfile.c,v 1.21 2000/11/12 19:50:37 markus Exp $"); #include "packet.h" #include "match.h" @@ -54,15 +54,13 @@ RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $"); int hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) { - unsigned int bits; char *cp; /* Skip leading whitespace. */ for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) ; - bits = key_read(ret, &cp); - if (bits == 0) + if (key_read(ret, &cp) != 1) return 0; /* Skip trailing whitespace. */ @@ -71,14 +69,14 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) /* Return results. */ *cpp = cp; - *bitsp = bits; + *bitsp = key_size(ret); return 1; } int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) { - Key *k = key_new(KEY_RSA); + Key *k = key_new(KEY_RSA1); int ret = hostfile_read_key(cpp, bitsp, k); BN_copy(e, k->rsa->e); BN_copy(n, k->rsa->n); @@ -89,7 +87,7 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) int hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) { - if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) + if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) return 1; if (bits != BN_num_bits(key->rsa->n)) { log("Warning: %s, line %d: keysize mismatch for host %s: " diff --git a/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c index 68b9e522e73..2dbac9b13bd 100644 --- a/usr.bin/ssh/kex.c +++ b/usr.bin/ssh/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.13 2000/11/12 19:50:37 markus Exp $"); #include "ssh.h" #include "ssh2.h" @@ -43,6 +43,7 @@ RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); #include <openssl/pem.h> #include "kex.h" +#include "key.h" #define KEX_COOKIE_LEN 16 @@ -454,11 +455,12 @@ choose_kex(Kex *k, char *client, char *server) void choose_hostkeyalg(Kex *k, char *client, char *server) { - k->hostkeyalg = get_match(client, server); - if (k->hostkeyalg == NULL) + char *hostkeyalg = get_match(client, server); + if (hostkeyalg == NULL) fatal("no hostkey alg"); - if (strcmp(k->hostkeyalg, KEX_DSS) != 0) - fatal("bad hostkey alg %s", k->hostkeyalg); + k->hostkey_type = key_type_from_name(hostkeyalg); + if (k->hostkey_type == KEY_UNSPEC) + fatal("bad hostkey alg '%s'", hostkeyalg); } Kex * diff --git a/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h index 21295813127..1890fc025e1 100644 --- a/usr.bin/ssh/kex.h +++ b/usr.bin/ssh/kex.h @@ -85,7 +85,7 @@ struct Kex { int we_need; int server; char *name; - char *hostkeyalg; + int hostkey_type; int kex_type; }; diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c index f7df0bb1db4..a6b25b7ae83 100644 --- a/usr.bin/ssh/key.c +++ b/usr.bin/ssh/key.c @@ -39,12 +39,14 @@ #include <openssl/evp.h> #include "xmalloc.h" #include "key.h" -#include "dsa.h" +#include "rsa.h" +#include "ssh-dss.h" +#include "ssh-rsa.h" #include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" -RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); - -#define SSH_DSS "ssh-dss" +RCSID("$OpenBSD: key.c,v 1.12 2000/11/12 19:50:37 markus Exp $"); Key * key_new(int type) @@ -57,6 +59,7 @@ key_new(int type) k->dsa = NULL; k->rsa = NULL; switch (k->type) { + case KEY_RSA1: case KEY_RSA: rsa = RSA_new(); rsa->n = BN_new(); @@ -71,7 +74,7 @@ key_new(int type) dsa->pub_key = BN_new(); k->dsa = dsa; break; - case KEY_EMPTY: + case KEY_UNSPEC: break; default: fatal("key_new: bad key type %d", k->type); @@ -79,10 +82,35 @@ key_new(int type) } return k; } +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + k->rsa->d = BN_new(); + k->rsa->iqmp = BN_new(); + k->rsa->q = BN_new(); + k->rsa->p = BN_new(); + k->rsa->dmq1 = BN_new(); + k->rsa->dmp1 = BN_new(); + break; + case KEY_DSA: + k->dsa->priv_key = BN_new(); + break; + case KEY_UNSPEC: + break; + default: + break; + } + return k; +} void key_free(Key *k) { switch (k->type) { + case KEY_RSA1: case KEY_RSA: if (k->rsa != NULL) RSA_free(k->rsa); @@ -93,6 +121,8 @@ key_free(Key *k) DSA_free(k->dsa); k->dsa = NULL; break; + case KEY_UNSPEC: + break; default: fatal("key_free: bad key type %d", k->type); break; @@ -105,6 +135,7 @@ key_equal(Key *a, Key *b) if (a == NULL || b == NULL || a->type != b->type) return 0; switch (a->type) { + case KEY_RSA1: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && @@ -136,8 +167,9 @@ key_fingerprint(Key *k) int len = 0; int nlen, elen; + retval[0] = '\0'; switch (k->type) { - case KEY_RSA: + case KEY_RSA1: nlen = BN_num_bytes(k->rsa->n); elen = BN_num_bytes(k->rsa->e); len = nlen + elen; @@ -146,14 +178,16 @@ key_fingerprint(Key *k) BN_bn2bin(k->rsa->e, blob + nlen); break; case KEY_DSA: - dsa_make_key_blob(k, &blob, &len); + case KEY_RSA: + key_to_blob(k, &blob, &len); + break; + case KEY_UNSPEC: + return retval; break; default: fatal("key_fingerprint: bad key type %d", k->type); break; } - retval[0] = '\0'; - if (blob != NULL) { int i; unsigned char digest[EVP_MAX_MD_SIZE]; @@ -229,56 +263,106 @@ write_bignum(FILE *f, BIGNUM *num) free(buf); return 1; } -unsigned int + +/* returns 1 ok, -1 error, 0 type mismatch */ +int key_read(Key *ret, char **cpp) { Key *k; - unsigned int bits = 0; - char *cp; - int len, n; + int success = -1; + char *cp, *space; + int len, n, type; + u_int bits; unsigned char *blob; cp = *cpp; switch(ret->type) { - case KEY_RSA: + case KEY_RSA1: /* Get number of bits. */ if (*cp < '0' || *cp > '9') - return 0; /* Bad bit count... */ + return -1; /* Bad bit count... */ for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) bits = 10 * bits + *cp - '0'; if (bits == 0) - return 0; + return -1; *cpp = cp; /* Get public exponent, public modulus. */ if (!read_bignum(cpp, ret->rsa->e)) - return 0; + return -1; if (!read_bignum(cpp, ret->rsa->n)) - return 0; + return -1; + success = 1; break; + case KEY_UNSPEC: + case KEY_RSA: case KEY_DSA: - if (strncmp(cp, SSH_DSS " ", 7) != 0) + space = strchr(cp, ' '); + if (space == NULL) { + debug3("key_read: no space"); + return -1; + } + *space = '\0'; + type = key_type_from_name(cp); + *space = ' '; + if (type == KEY_UNSPEC) { + debug3("key_read: no key found"); + return -1; + } + cp = space+1; + if (*cp == '\0') { + debug3("key_read: short string"); + return -1; + } + if (ret->type == KEY_UNSPEC) { + ret->type = type; + } else if (ret->type != type) { + /* is a key, but different type */ + debug3("key_read: type mismatch"); return 0; - cp += 7; + } len = 2*strlen(cp); blob = xmalloc(len); n = uudecode(cp, blob, len); if (n < 0) { error("key_read: uudecode %s failed", cp); - return 0; + return -1; } - k = dsa_key_from_blob(blob, n); + k = key_from_blob(blob, n); if (k == NULL) { - error("key_read: dsa_key_from_blob %s failed", cp); - return 0; + error("key_read: key_from_blob %s failed", cp); + return -1; } xfree(blob); - if (ret->dsa != NULL) - DSA_free(ret->dsa); - ret->dsa = k->dsa; - k->dsa = NULL; + if (k->type != type) { + error("key_read: type mismatch: encoding error"); + key_free(k); + return -1; + } +/*XXXX*/ + if (ret->type == KEY_RSA) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, ret->rsa, 8); +#endif + } else { + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + success = 1; +#ifdef DEBUG_PK + DSA_print_fp(stderr, ret->dsa, 8); +#endif + } +/*XXXX*/ + if (success != 1) + break; key_free(k); - bits = BN_num_bits(ret->dsa->p); /* advance cp: skip whitespace and data */ while (*cp == ' ' || *cp == '\t') cp++; @@ -290,7 +374,7 @@ key_read(Key *ret, char **cpp) fatal("key_read: bad key type: %d", ret->type); break; } - return bits; + return success; } int key_write(Key *key, FILE *f) @@ -298,7 +382,7 @@ key_write(Key *key, FILE *f) int success = 0; unsigned int bits = 0; - if (key->type == KEY_RSA && key->rsa != NULL) { + if (key->type == KEY_RSA1 && key->rsa != NULL) { /* size of modulus 'n' */ bits = BN_num_bits(key->rsa->n); fprintf(f, "%u", bits); @@ -308,14 +392,15 @@ key_write(Key *key, FILE *f) } else { error("key_write: failed for RSA key"); } - } else if (key->type == KEY_DSA && key->dsa != NULL) { + } else if ((key->type == KEY_DSA && key->dsa != NULL) || + (key->type == KEY_RSA && key->rsa != NULL)) { int len, n; unsigned char *blob, *uu; - dsa_make_key_blob(key, &blob, &len); + key_to_blob(key, &blob, &len); uu = xmalloc(2*len); n = uuencode(blob, len, uu, 2*len); if (n > 0) { - fprintf(f, "%s %s", SSH_DSS, uu); + fprintf(f, "%s %s", key_ssh_name(key), uu); success = 1; } xfree(blob); @@ -327,6 +412,9 @@ char * key_type(Key *k) { switch (k->type) { + case KEY_RSA1: + return "RSA1"; + break; case KEY_RSA: return "RSA"; break; @@ -336,9 +424,23 @@ key_type(Key *k) } return "unknown"; } -unsigned int +char * +key_ssh_name(Key *k) +{ + switch (k->type) { + case KEY_RSA: + return "ssh-rsa"; + break; + case KEY_DSA: + return "ssh-dss"; + break; + } + return "ssh-unknown"; +} +u_int key_size(Key *k){ switch (k->type) { + case KEY_RSA1: case KEY_RSA: return BN_num_bits(k->rsa->n); break; @@ -348,3 +450,219 @@ key_size(Key *k){ } return 0; } + +RSA * +rsa_generate_private_key(unsigned int bits) +{ + RSA *private; + private = RSA_generate_key(bits, 35, NULL, NULL); + if (private == NULL) + fatal("rsa_generate_private_key: key generation failed."); + return private; +} + +DSA* +dsa_generate_private_key(unsigned int bits) +{ + DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); + if (private == NULL) + fatal("dsa_generate_private_key: DSA_generate_parameters failed"); + if (!DSA_generate_key(private)) + fatal("dsa_generate_private_key: DSA_generate_key failed."); + if (private == NULL) + fatal("dsa_generate_private_key: NULL."); + return private; +} + +Key * +key_generate(int type, unsigned int bits) +{ + Key *k = key_new(KEY_UNSPEC); + switch (type) { + case KEY_DSA: + k->dsa = dsa_generate_private_key(bits); + break; + case KEY_RSA: + case KEY_RSA1: + k->rsa = rsa_generate_private_key(bits); + break; + default: + fatal("key_generate: unknown type %d", type); + } + k->type = type; + return k; +} + +Key * +key_from_private(Key *k) +{ + Key *n = NULL; + switch (k->type) { + case KEY_DSA: + n = key_new(k->type); + BN_copy(n->dsa->p, k->dsa->p); + BN_copy(n->dsa->q, k->dsa->q); + BN_copy(n->dsa->g, k->dsa->g); + BN_copy(n->dsa->pub_key, k->dsa->pub_key); + break; + case KEY_RSA: + case KEY_RSA1: + n = key_new(k->type); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + break; + default: + fatal("key_from_private: unknown type %d", k->type); + break; + } + return n; +} + +int +key_type_from_name(char *name) +{ + if (strcmp(name, "rsa1") == 0){ + return KEY_RSA1; + } else if (strcmp(name, "rsa") == 0){ + return KEY_RSA; + } else if (strcmp(name, "dsa") == 0){ + return KEY_DSA; + } else if (strcmp(name, "ssh-rsa") == 0){ + return KEY_RSA; + } else if (strcmp(name, "ssh-dss") == 0){ + return KEY_DSA; + } + debug("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +} + +Key * +key_from_blob(char *blob, int blen) +{ + Buffer b; + char *ktype; + int rlen, type; + Key *key = NULL; + +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + ktype = buffer_get_string(&b, NULL); + type = key_type_from_name(ktype); + + switch(type){ + case KEY_RSA: + key = key_new(type); + buffer_get_bignum2(&b, key->rsa->n); + buffer_get_bignum2(&b, key->rsa->e); +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + case KEY_DSA: + key = key_new(type); + buffer_get_bignum2(&b, key->dsa->p); + buffer_get_bignum2(&b, key->dsa->q); + buffer_get_bignum2(&b, key->dsa->g); + buffer_get_bignum2(&b, key->dsa->pub_key); +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + case KEY_UNSPEC: + key = key_new(type); + break; + default: + error("key_from_blob: cannot handle type %s", ktype); + break; + } + rlen = buffer_len(&b); + if (key != NULL && rlen != 0) + error("key_from_blob: remaining bytes in key blob %d", rlen); + xfree(ktype); + buffer_free(&b); + return key; +} + +int +key_to_blob(Key *key, unsigned char **blobp, unsigned int *lenp) +{ + Buffer b; + int len; + unsigned char *buf; + + if (key == NULL) { + error("key_to_blob: key == NULL"); + return 0; + } + buffer_init(&b); + switch(key->type){ + case KEY_DSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->dsa->p); + buffer_put_bignum2(&b, key->dsa->q); + buffer_put_bignum2(&b, key->dsa->g); + buffer_put_bignum2(&b, key->dsa->pub_key); + break; + case KEY_RSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->rsa->n); + buffer_put_bignum2(&b, key->rsa->e); + break; + default: + error("key_to_blob: illegal key type %d", key->type); + break; + } + len = buffer_len(&b); + buf = xmalloc(len); + memcpy(buf, buffer_ptr(&b), len); + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) + *blobp = buf; + return len; +} + +int +key_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen) +{ + switch(key->type){ + case KEY_DSA: + return ssh_dss_sign(key, sigp, lenp, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_sign(key, sigp, lenp, data, datalen); + break; + default: + error("key_sign: illegal key type %d", key->type); + return -1; + break; + } +} + +int +key_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen) +{ + switch(key->type){ + case KEY_DSA: + return ssh_dss_verify(key, signature, signaturelen, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + break; + default: + error("key_verify: illegal key type %d", key->type); + return -1; + break; + } +} diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h index 8e1e0a98d12..b6c3eb0109e 100644 --- a/usr.bin/ssh/key.h +++ b/usr.bin/ssh/key.h @@ -26,9 +26,10 @@ typedef struct Key Key; enum types { + KEY_RSA1, KEY_RSA, KEY_DSA, - KEY_EMPTY + KEY_UNSPEC }; struct Key { int type; @@ -37,12 +38,33 @@ struct Key { }; Key *key_new(int type); +Key *key_new_private(int type); void key_free(Key *k); int key_equal(Key *a, Key *b); char *key_fingerprint(Key *k); char *key_type(Key *k); int key_write(Key *key, FILE *f); -unsigned int key_read(Key *key, char **cpp); -unsigned int key_size(Key *k); +int key_read(Key *key, char **cpp); +u_int key_size(Key *k); + +Key *key_generate(int type, unsigned int bits); +Key *key_from_private(Key *k); +int key_type_from_name(char *name); + +Key *key_from_blob(char *blob, int blen); +int key_to_blob(Key *key, unsigned char **blobp, unsigned int *lenp); +char *key_ssh_name(Key *k); + +int +key_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen); + +int +key_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen); #endif diff --git a/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile index 396186ba94a..d82ad9b9390 100644 --- a/usr.bin/ssh/lib/Makefile +++ b/usr.bin/ssh/lib/Makefile @@ -5,8 +5,8 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \ cipher.c compat.c compress.c crc32.c deattack.c \ hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \ rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \ - key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c \ - cli.c rijndael.c + key.c dispatch.c kex.c hmac.c uuencode.c util.c \ + cli.c rijndael.c ssh-dss.c ssh-rsa.c NOPROFILE= yes NOPIC= yes diff --git a/usr.bin/ssh/myproposal.h b/usr.bin/ssh/myproposal.h index 98060dc3528..5abb0e5a67e 100644 --- a/usr.bin/ssh/myproposal.h +++ b/usr.bin/ssh/myproposal.h @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1" -#define KEX_DEFAULT_PK_ALG "ssh-dss" +#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ "3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ "aes128-cbc,aes192-cbc,aes256-cbc," \ diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index bcdbc4c292c..51bf5776972 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.50 2000/11/12 19:50:37 markus Exp $"); #include "ssh.h" #include "readconf.h" @@ -68,7 +68,7 @@ RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $"); # Defaults for various options Host * ForwardAgent no - ForwardX11 yes + ForwardX11 no RhostsAuthentication yes PasswordAuthentication yes RSAAuthentication yes @@ -101,8 +101,8 @@ typedef enum { oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, - oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2, - oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication, + oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices } OpCodes; @@ -122,7 +122,8 @@ static struct { { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, { "kbdinteractivedevices", oKbdInteractiveDevices }, { "rsaauthentication", oRSAAuthentication }, - { "dsaauthentication", oDSAAuthentication }, + { "pubkeyauthentication", oPubkeyAuthentication }, + { "dsaauthentication", oPubkeyAuthentication }, /* alias */ { "skeyauthentication", oSkeyAuthentication }, #ifdef KRB4 { "kerberosauthentication", oKerberosAuthentication }, @@ -134,7 +135,7 @@ static struct { { "fallbacktorsh", oFallBackToRsh }, { "usersh", oUseRsh }, { "identityfile", oIdentityFile }, - { "identityfile2", oIdentityFile2 }, + { "identityfile2", oIdentityFile }, /* alias */ { "hostname", oHostName }, { "proxycommand", oProxyCommand }, { "port", oPort }, @@ -298,8 +299,8 @@ parse_flag: charptr = &options->kbd_interactive_devices; goto parse_string; - case oDSAAuthentication: - intptr = &options->dsa_authentication; + case oPubkeyAuthentication: + intptr = &options->pubkey_authentication; goto parse_flag; case oRSAAuthentication: @@ -384,20 +385,15 @@ parse_flag: goto parse_int; case oIdentityFile: - case oIdentityFile2: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep) { - intptr = (opcode == oIdentityFile) ? - &options->num_identity_files : - &options->num_identity_files2; + intptr = &options->num_identity_files; if (*intptr >= SSH_MAX_IDENTITY_FILES) fatal("%.200s line %d: Too many identity files specified (max %d).", filename, linenum, SSH_MAX_IDENTITY_FILES); - charptr = (opcode == oIdentityFile) ? - &options->identity_files[*intptr] : - &options->identity_files2[*intptr]; + charptr = &options->identity_files[*intptr]; *charptr = xstrdup(arg); *intptr = *intptr + 1; } @@ -662,7 +658,7 @@ initialize_options(Options * options) options->use_privileged_port = -1; options->rhosts_authentication = -1; options->rsa_authentication = -1; - options->dsa_authentication = -1; + options->pubkey_authentication = -1; options->skey_authentication = -1; #ifdef KRB4 options->kerberos_authentication = -1; @@ -690,7 +686,6 @@ initialize_options(Options * options) options->ciphers = NULL; options->protocol = SSH_PROTO_UNKNOWN; options->num_identity_files = 0; - options->num_identity_files2 = 0; options->hostname = NULL; options->proxy_command = NULL; options->user = NULL; @@ -728,8 +723,8 @@ fill_default_options(Options * options) options->rhosts_authentication = 1; if (options->rsa_authentication == -1) options->rsa_authentication = 1; - if (options->dsa_authentication == -1) - options->dsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; if (options->skey_authentication == -1) options->skey_authentication = 0; #ifdef KRB4 @@ -777,16 +772,18 @@ fill_default_options(Options * options) if (options->protocol == SSH_PROTO_UNKNOWN) options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED; if (options->num_identity_files == 0) { - options->identity_files[0] = - xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); - sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); - options->num_identity_files = 1; - } - if (options->num_identity_files2 == 0) { - options->identity_files2[0] = - xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1); - sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA); - options->num_identity_files2 = 1; + if (options->protocol & SSH_PROTO_1) { + options->identity_files[options->num_identity_files] = + xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); + sprintf(options->identity_files[options->num_identity_files++], + "~/%.100s", SSH_CLIENT_IDENTITY); + } + if (options->protocol & SSH_PROTO_2) { + options->identity_files[options->num_identity_files] = + xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1); + sprintf(options->identity_files[options->num_identity_files++], + "~/%.100s", SSH_CLIENT_ID_DSA); + } } if (options->escape_char == -1) options->escape_char = '~'; diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h index e94213fa177..85d937d8716 100644 --- a/usr.bin/ssh/readconf.h +++ b/usr.bin/ssh/readconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */ +/* RCSID("$OpenBSD: readconf.h,v 1.23 2000/11/12 19:50:37 markus Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -35,7 +35,7 @@ typedef struct { int rhosts_rsa_authentication; /* Try rhosts with RSA * authentication. */ int rsa_authentication; /* Try RSA authentication. */ - int dsa_authentication; /* Try DSA authentication. */ + int pubkey_authentication; /* Try ssh2 pubkey authentication. */ int skey_authentication; /* Try S/Key or TIS authentication. */ #ifdef KRB4 int kerberos_authentication; /* Try Kerberos @@ -78,10 +78,9 @@ typedef struct { char *system_hostfile2; char *user_hostfile2; - int num_identity_files; /* Number of files for RSA identities. */ - int num_identity_files2; /* DSA identities. */ + int num_identity_files; /* Number of files for RSA/DSA identities. */ char *identity_files[SSH_MAX_IDENTITY_FILES]; - char *identity_files2[SSH_MAX_IDENTITY_FILES]; + int identity_files_type[SSH_MAX_IDENTITY_FILES]; /* Local TCP/IP forward requests. */ int num_local_forwards; diff --git a/usr.bin/ssh/rsa.c b/usr.bin/ssh/rsa.c index e5cddc2548c..8ef7b22ce93 100644 --- a/usr.bin/ssh/rsa.c +++ b/usr.bin/ssh/rsa.c @@ -60,78 +60,12 @@ */ #include "includes.h" -RCSID("$OpenBSD: rsa.c,v 1.16 2000/09/07 20:27:53 deraadt Exp $"); +RCSID("$OpenBSD: rsa.c,v 1.17 2000/11/12 19:50:37 markus Exp $"); #include "rsa.h" #include "ssh.h" #include "xmalloc.h" -int rsa_verbose = 1; - -int -rsa_alive() -{ - RSA *key; - - key = RSA_generate_key(32, 3, NULL, NULL); - if (key == NULL) - return (0); - RSA_free(key); - return (1); -} - -/* - * Generates RSA public and private keys. This initializes the data - * structures; they should be freed with rsa_clear_private_key and - * rsa_clear_public_key. - */ - -void -rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits) -{ - RSA *key; - - if (rsa_verbose) { - printf("Generating RSA keys: "); - fflush(stdout); - } - key = RSA_generate_key(bits, 35, NULL, NULL); - if (key == NULL) - fatal("rsa_generate_key: key generation failed."); - - /* Copy public key parameters */ - pub->n = BN_new(); - BN_copy(pub->n, key->n); - pub->e = BN_new(); - BN_copy(pub->e, key->e); - - /* Copy private key parameters */ - prv->n = BN_new(); - BN_copy(prv->n, key->n); - prv->e = BN_new(); - BN_copy(prv->e, key->e); - prv->d = BN_new(); - BN_copy(prv->d, key->d); - prv->p = BN_new(); - BN_copy(prv->p, key->p); - prv->q = BN_new(); - BN_copy(prv->q, key->q); - - prv->dmp1 = BN_new(); - BN_copy(prv->dmp1, key->dmp1); - - prv->dmq1 = BN_new(); - BN_copy(prv->dmq1, key->dmq1); - - prv->iqmp = BN_new(); - BN_copy(prv->iqmp, key->iqmp); - - RSA_free(key); - - if (rsa_verbose) - printf("Key generation complete.\n"); -} - void rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) { @@ -184,11 +118,3 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) xfree(outbuf); xfree(inbuf); } - -/* Set whether to output verbose messages during key generation. */ - -void -rsa_set_verbose(int verbose) -{ - rsa_verbose = verbose; -} diff --git a/usr.bin/ssh/rsa.h b/usr.bin/ssh/rsa.h index 93a2dac85cc..57d72cc7892 100644 --- a/usr.bin/ssh/rsa.h +++ b/usr.bin/ssh/rsa.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: rsa.h,v 1.8 2000/09/07 20:27:53 deraadt Exp $"); */ +/* RCSID("$OpenBSD: rsa.h,v 1.9 2000/11/12 19:50:38 markus Exp $"); */ #ifndef RSA_H #define RSA_H @@ -19,17 +19,6 @@ #include <openssl/bn.h> #include <openssl/rsa.h> -/* Calls SSL RSA_generate_key, only copies to prv and pub */ -void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits); - -/* - * Indicates whether the rsa module is permitted to show messages on the - * terminal. - */ -void rsa_set_verbose __P((int verbose)); - -int rsa_alive __P((void)); - void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); void rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index 76702a83612..5da55de038d 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.53 2000/10/14 12:12:09 markus Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.54 2000/11/12 19:50:38 markus Exp $"); #include "ssh.h" #include "servconf.h" @@ -29,8 +29,7 @@ initialize_server_options(ServerOptions *options) options->num_ports = 0; options->ports_from_cmdline = 0; options->listen_addrs = NULL; - options->host_key_file = NULL; - options->host_dsa_key_file = NULL; + options->num_host_key_files = 0; options->pid_file = NULL; options->server_key_bits = -1; options->login_grace_time = -1; @@ -50,7 +49,7 @@ initialize_server_options(ServerOptions *options) options->rhosts_authentication = -1; options->rhosts_rsa_authentication = -1; options->rsa_authentication = -1; - options->dsa_authentication = -1; + options->pubkey_authentication = -1; #ifdef KRB4 options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; @@ -84,14 +83,19 @@ initialize_server_options(ServerOptions *options) void fill_default_server_options(ServerOptions *options) { + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_1|SSH_PROTO_2; + if (options->num_host_key_files == 0) { + /* fill default hostkeys for protocols */ + if (options->protocol & SSH_PROTO_1) + options->host_key_files[options->num_host_key_files++] = HOST_KEY_FILE; + if (options->protocol & SSH_PROTO_2) + options->host_key_files[options->num_host_key_files++] = HOST_DSA_KEY_FILE; + } if (options->num_ports == 0) options->ports[options->num_ports++] = SSH_DEFAULT_PORT; if (options->listen_addrs == NULL) add_listen_addr(options, NULL); - if (options->host_key_file == NULL) - options->host_key_file = HOST_KEY_FILE; - if (options->host_dsa_key_file == NULL) - options->host_dsa_key_file = HOST_DSA_KEY_FILE; if (options->pid_file == NULL) options->pid_file = SSH_DAEMON_PID_FILE; if (options->server_key_bits == -1) @@ -132,8 +136,8 @@ fill_default_server_options(ServerOptions *options) options->rhosts_rsa_authentication = 0; if (options->rsa_authentication == -1) options->rsa_authentication = 1; - if (options->dsa_authentication == -1) - options->dsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; #ifdef KRB4 if (options->kerberos_authentication == -1) options->kerberos_authentication = (access(KEYFILE, R_OK) == 0); @@ -162,8 +166,6 @@ fill_default_server_options(ServerOptions *options) options->use_login = 0; if (options->allow_tcp_forwarding == -1) options->allow_tcp_forwarding = 1; - if (options->protocol == SSH_PROTO_UNKNOWN) - options->protocol = SSH_PROTO_1|SSH_PROTO_2; if (options->gateway_ports == -1) options->gateway_ports = 0; if (options->max_startups == -1) @@ -194,8 +196,8 @@ typedef enum { sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sUseLogin, sAllowTcpForwarding, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, - sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, - sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups + sIgnoreUserKnownHosts, sCiphers, sProtocol, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, } ServerOpCodes; /* Textual representation of the tokens. */ @@ -205,7 +207,7 @@ static struct { } keywords[] = { { "port", sPort }, { "hostkey", sHostKeyFile }, - { "hostdsakey", sHostDSAKeyFile }, + { "hostdsakey", sHostKeyFile }, /* alias */ { "pidfile", sPidFile }, { "serverkeybits", sServerKeyBits }, { "logingracetime", sLoginGraceTime }, @@ -216,7 +218,8 @@ static struct { { "rhostsauthentication", sRhostsAuthentication }, { "rhostsrsaauthentication", sRhostsRSAAuthentication }, { "rsaauthentication", sRSAAuthentication }, - { "dsaauthentication", sDSAAuthentication }, + { "pubkeyauthentication", sPubkeyAuthentication }, + { "dsaauthentication", sPubkeyAuthentication }, /* alias */ #ifdef KRB4 { "kerberosauthentication", sKerberosAuthentication }, { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, @@ -336,6 +339,8 @@ read_server_config(ServerOptions *options, const char *filename) arg = strdelim(&cp); if (!*arg || *arg == '#') continue; + intptr = NULL; + charptr = NULL; opcode = parse_token(arg, filename, linenum); switch (opcode) { case sBadOption: @@ -389,9 +394,13 @@ parse_int: break; case sHostKeyFile: - case sHostDSAKeyFile: - charptr = (opcode == sHostKeyFile ) ? - &options->host_key_file : &options->host_dsa_key_file; + intptr = &options->num_host_key_files; + if (*intptr >= MAX_HOSTKEYS) { + fprintf(stderr, "%s line %d: to many host keys specified (max %d).\n", + filename, linenum, MAX_HOSTKEYS); + exit(1); + } + charptr = &options->host_key_files[*intptr]; parse_filename: arg = strdelim(&cp); if (!arg || *arg == '\0') { @@ -399,8 +408,12 @@ parse_filename: filename, linenum); exit(1); } - if (*charptr == NULL) + if (*charptr == NULL) { *charptr = tilde_expand_filename(arg, getuid()); + /* increase optional counter */ + if (intptr != NULL) + *intptr = *intptr + 1; + } break; case sPidFile: @@ -474,8 +487,8 @@ parse_flag: intptr = &options->rsa_authentication; goto parse_flag; - case sDSAAuthentication: - intptr = &options->dsa_authentication; + case sPubkeyAuthentication: + intptr = &options->pubkey_authentication; goto parse_flag; #ifdef KRB4 diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 0188b9b893c..3ecf6a00d52 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: servconf.h,v 1.30 2000/10/14 12:12:09 markus Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.31 2000/11/12 19:50:38 markus Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -23,6 +23,7 @@ #define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ +#define MAX_HOSTKEYS 256 /* Max # hostkeys. */ typedef struct { unsigned int num_ports; @@ -30,8 +31,8 @@ typedef struct { u_short ports[MAX_PORTS]; /* Port number to listen on. */ char *listen_addr; /* Address on which the server listens. */ struct addrinfo *listen_addrs; /* Addresses on which the server listens. */ - char *host_key_file; /* File containing host key. */ - char *host_dsa_key_file; /* File containing dsa host key. */ + char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */ + int num_host_key_files; /* Number of files for host keys. */ char *pid_file; /* Where to put our pid */ int server_key_bits;/* Size of the server key. */ int login_grace_time; /* Disconnect if no auth in this time @@ -59,7 +60,7 @@ typedef struct { int rhosts_rsa_authentication; /* If true, permit rhosts RSA * authentication. */ int rsa_authentication; /* If true, permit RSA authentication. */ - int dsa_authentication; /* If true, permit DSA authentication. */ + int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ #ifdef KRB4 int kerberos_authentication; /* If true, permit Kerberos * authentication. */ diff --git a/usr.bin/ssh/ssh-add.c b/usr.bin/ssh/ssh-add.c index 4b33f965447..3ab47fb2343 100644 --- a/usr.bin/ssh/ssh-add.c +++ b/usr.bin/ssh/ssh-add.c @@ -35,7 +35,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-add.c,v 1.22 2000/09/07 20:27:54 deraadt Exp $"); +RCSID("$OpenBSD: ssh-add.c,v 1.23 2000/11/12 19:50:38 markus Exp $"); #include <openssl/evp.h> #include <openssl/rsa.h> @@ -54,10 +54,10 @@ delete_file(AuthenticationConnection *ac, const char *filename) Key *public; char *comment; - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(filename, public, &comment)) { key_free(public); - public = key_new(KEY_DSA); + public = key_new(KEY_UNSPEC); if (!try_load_public_key(filename, public, &comment)) { printf("Bad key file %s\n", filename); return; @@ -136,7 +136,7 @@ add_file(AuthenticationConnection *ac, const char *filename) char buf[1024], msg[1024]; int success; int interactive = isatty(STDIN_FILENO); - int type = KEY_RSA; + int type = KEY_RSA1; if (stat(filename, &st) < 0) { perror(filename); @@ -146,10 +146,10 @@ add_file(AuthenticationConnection *ac, const char *filename) * try to load the public key. right now this only works for RSA, * since DSA keys are fully encrypted */ - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(filename, public, &saved_comment)) { - /* ok, so we will asume this is a DSA key */ - type = KEY_DSA; + /* ok, so we will assume this is 'some' key */ + type = KEY_UNSPEC; saved_comment = xstrdup(filename); } key_free(public); @@ -215,8 +215,9 @@ list_identities(AuthenticationConnection *ac, int fp) key = ssh_get_next_identity(ac, &comment, version)) { had_identities = 1; if (fp) { - printf("%d %s %s\n", - key_size(key), key_fingerprint(key), comment); + printf("%d %s %s (%s)\n", + key_size(key), key_fingerprint(key), + comment, key_type(key)); } else { if (!key_write(key, stdout)) fprintf(stderr, "key_write failed"); @@ -240,15 +241,6 @@ main(int argc, char **argv) int i; int deleting = 0; - /* check if RSA support exists */ - if (rsa_alive() == 0) { - extern char *__progname; - - fprintf(stderr, - "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", - __progname); - exit(1); - } SSLeay_add_all_algorithms(); /* At first, get a connection to the authentication agent. */ diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c index 96a822e6a37..91571c54254 100644 --- a/usr.bin/ssh/ssh-agent.c +++ b/usr.bin/ssh/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.38 2000/11/12 19:03:28 markus Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.39 2000/11/12 19:50:38 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.38 2000/11/12 19:03:28 markus Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.39 2000/11/12 19:50:38 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -54,7 +54,6 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.38 2000/11/12 19:03:28 markus Exp $"); #include <openssl/rsa.h> #include "key.h" #include "authfd.h" -#include "dsa.h" #include "kex.h" #include "compat.h" @@ -143,14 +142,14 @@ process_request_identities(SocketEntry *e, int version) buffer_put_int(&msg, tab->nentries); for (i = 0; i < tab->nentries; i++) { Identity *id = &tab->identities[i]; - if (id->key->type == KEY_RSA) { + if (id->key->type == KEY_RSA1) { buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); buffer_put_bignum(&msg, id->key->rsa->e); buffer_put_bignum(&msg, id->key->rsa->n); } else { unsigned char *blob; unsigned int blen; - dsa_make_key_blob(id->key, &blob, &blen); + key_to_blob(id->key, &blob, &blen); buffer_put_string(&msg, blob, blen); xfree(blob); } @@ -174,7 +173,7 @@ process_authentication_challenge1(SocketEntry *e) unsigned int response_type; buffer_init(&msg); - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); challenge = BN_new(); buffer_get_int(&e->input); /* ignored */ @@ -247,11 +246,11 @@ process_sign_request2(SocketEntry *e) if (flags & SSH_AGENT_OLD_SIGNATURE) datafellows = SSH_BUG_SIGBLOB; - key = dsa_key_from_blob(blob, blen); + key = key_from_blob(blob, blen); if (key != NULL) { private = lookup_private_key(key, NULL, 2); if (private != NULL) - ok = dsa_sign(private, &signature, &slen, data, dlen); + ok = key_sign(private, &signature, &slen, data, dlen); } key_free(key); buffer_init(&msg); @@ -283,7 +282,7 @@ process_remove_identity(SocketEntry *e, int version) switch(version){ case 1: - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); bits = buffer_get_int(&e->input); buffer_get_bignum(&e->input, key->rsa->e); buffer_get_bignum(&e->input, key->rsa->n); @@ -294,7 +293,7 @@ process_remove_identity(SocketEntry *e, int version) break; case 2: blob = buffer_get_string(&e->input, &blen); - key = dsa_key_from_blob(blob, blen); + key = key_from_blob(blob, blen); xfree(blob); break; } @@ -349,79 +348,80 @@ process_remove_all_identities(SocketEntry *e, int version) } void -process_add_identity(SocketEntry *e, int version) +generate_additional_parameters(RSA *rsa) { - Key *k = NULL; - RSA *rsa; BIGNUM *aux; BN_CTX *ctx; - char *type; + /* Generate additional parameters */ + aux = BN_new(); + ctx = BN_CTX_new(); + + BN_sub(aux, rsa->q, BN_value_one()); + BN_mod(rsa->dmq1, rsa->d, aux, ctx); + + BN_sub(aux, rsa->p, BN_value_one()); + BN_mod(rsa->dmp1, rsa->d, aux, ctx); + + BN_clear_free(aux); + BN_CTX_free(ctx); +} + +void +process_add_identity(SocketEntry *e, int version) +{ + Key *k = NULL; + char *type_name; char *comment; - int success = 0; + int type, success = 0; Idtab *tab = idtab_lookup(version); switch (version) { case 1: - k = key_new(KEY_RSA); - rsa = k->rsa; - - /* allocate mem for private key */ - /* XXX rsa->n and rsa->e are already allocated */ - rsa->d = BN_new(); - rsa->iqmp = BN_new(); - rsa->q = BN_new(); - rsa->p = BN_new(); - rsa->dmq1 = BN_new(); - rsa->dmp1 = BN_new(); - - buffer_get_int(&e->input); /* ignored */ - - buffer_get_bignum(&e->input, rsa->n); - buffer_get_bignum(&e->input, rsa->e); - buffer_get_bignum(&e->input, rsa->d); - buffer_get_bignum(&e->input, rsa->iqmp); + k = key_new_private(KEY_RSA1); + buffer_get_int(&e->input); /* ignored */ + buffer_get_bignum(&e->input, k->rsa->n); + buffer_get_bignum(&e->input, k->rsa->e); + buffer_get_bignum(&e->input, k->rsa->d); + buffer_get_bignum(&e->input, k->rsa->iqmp); /* SSH and SSL have p and q swapped */ - buffer_get_bignum(&e->input, rsa->q); /* p */ - buffer_get_bignum(&e->input, rsa->p); /* q */ + buffer_get_bignum(&e->input, k->rsa->q); /* p */ + buffer_get_bignum(&e->input, k->rsa->p); /* q */ /* Generate additional parameters */ - aux = BN_new(); - ctx = BN_CTX_new(); - - BN_sub(aux, rsa->q, BN_value_one()); - BN_mod(rsa->dmq1, rsa->d, aux, ctx); - - BN_sub(aux, rsa->p, BN_value_one()); - BN_mod(rsa->dmp1, rsa->d, aux, ctx); - - BN_clear_free(aux); - BN_CTX_free(ctx); - + generate_additional_parameters(k->rsa); break; case 2: - type = buffer_get_string(&e->input, NULL); - if (strcmp(type, KEX_DSS)) { + type_name = buffer_get_string(&e->input, NULL); + type = key_type_from_name(type_name); + xfree(type_name); + switch(type) { + case KEY_DSA: + k = key_new_private(type); + buffer_get_bignum2(&e->input, k->dsa->p); + buffer_get_bignum2(&e->input, k->dsa->q); + buffer_get_bignum2(&e->input, k->dsa->g); + buffer_get_bignum2(&e->input, k->dsa->pub_key); + buffer_get_bignum2(&e->input, k->dsa->priv_key); + break; + case KEY_RSA: + k = key_new_private(type); + buffer_get_bignum2(&e->input, k->rsa->n); + buffer_get_bignum2(&e->input, k->rsa->e); + buffer_get_bignum2(&e->input, k->rsa->d); + buffer_get_bignum2(&e->input, k->rsa->iqmp); + buffer_get_bignum2(&e->input, k->rsa->p); + buffer_get_bignum2(&e->input, k->rsa->q); + + /* Generate additional parameters */ + generate_additional_parameters(k->rsa); + break; + default: buffer_clear(&e->input); - xfree(type); goto send; } - xfree(type); - - k = key_new(KEY_DSA); - - /* allocate mem for private key */ - k->dsa->priv_key = BN_new(); - - buffer_get_bignum2(&e->input, k->dsa->p); - buffer_get_bignum2(&e->input, k->dsa->q); - buffer_get_bignum2(&e->input, k->dsa->g); - buffer_get_bignum2(&e->input, k->dsa->pub_key); - buffer_get_bignum2(&e->input, k->dsa->priv_key); - break; } - comment = buffer_get_string(&e->input, NULL); if (k == NULL) { xfree(comment); @@ -667,13 +667,6 @@ main(int ac, char **av) pid_t pid; char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; - /* check if RSA support exists */ - if (rsa_alive() == 0) { - fprintf(stderr, - "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", - __progname); - exit(1); - } while ((ch = getopt(ac, av, "cks")) != -1) { switch (ch) { case 'c': diff --git a/usr.bin/ssh/dsa.c b/usr.bin/ssh/ssh-dss.c index 4ff4b58f2b4..fea1fe2d5d0 100644 --- a/usr.bin/ssh/dsa.c +++ b/usr.bin/ssh/ssh-dss.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: dsa.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); +RCSID("$OpenBSD: ssh-dss.c,v 1.1 2000/11/12 19:50:38 markus Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -32,88 +32,17 @@ RCSID("$OpenBSD: dsa.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); #include "compat.h" #include <openssl/bn.h> -#include <openssl/dh.h> #include <openssl/rsa.h> #include <openssl/dsa.h> #include <openssl/evp.h> -#include <openssl/bio.h> -#include <openssl/pem.h> -#include <openssl/hmac.h> -#include "kex.h" #include "key.h" -#include "uuencode.h" #define INTBLOB_LEN 20 #define SIGBLOB_LEN (2*INTBLOB_LEN) -Key * -dsa_key_from_blob(char *blob, int blen) -{ - Buffer b; - char *ktype; - int rlen; - DSA *dsa; - Key *key; - -#ifdef DEBUG_DSS - dump_base64(stderr, blob, blen); -#endif - /* fetch & parse DSA/DSS pubkey */ - buffer_init(&b); - buffer_append(&b, blob, blen); - ktype = buffer_get_string(&b, NULL); - if (strcmp(KEX_DSS, ktype) != 0) { - error("dsa_key_from_blob: cannot handle type %s", ktype); - buffer_free(&b); - xfree(ktype); - return NULL; - } - key = key_new(KEY_DSA); - dsa = key->dsa; - buffer_get_bignum2(&b, dsa->p); - buffer_get_bignum2(&b, dsa->q); - buffer_get_bignum2(&b, dsa->g); - buffer_get_bignum2(&b, dsa->pub_key); - rlen = buffer_len(&b); - if(rlen != 0) - error("dsa_key_from_blob: remaining bytes in key blob %d", rlen); - buffer_free(&b); - xfree(ktype); - -#ifdef DEBUG_DSS - DSA_print_fp(stderr, dsa, 8); -#endif - return key; -} -int -dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp) -{ - Buffer b; - int len; - unsigned char *buf; - - if (key == NULL || key->type != KEY_DSA) - return 0; - buffer_init(&b); - buffer_put_cstring(&b, KEX_DSS); - buffer_put_bignum2(&b, key->dsa->p); - buffer_put_bignum2(&b, key->dsa->q); - buffer_put_bignum2(&b, key->dsa->g); - buffer_put_bignum2(&b, key->dsa->pub_key); - len = buffer_len(&b); - buf = xmalloc(len); - memcpy(buf, buffer_ptr(&b), len); - memset(buffer_ptr(&b), 0, len); - buffer_free(&b); - if (lenp != NULL) - *lenp = len; - if (blobp != NULL) - *blobp = buf; - return len; -} int -dsa_sign( +ssh_dss_sign( Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen) @@ -130,7 +59,7 @@ dsa_sign( Buffer b; if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { - error("dsa_sign: no DSA key"); + error("ssh_dss_sign: no DSA key"); return -1; } digest = xmalloc(evp_md->md_size); @@ -140,7 +69,7 @@ dsa_sign( sig = DSA_do_sign(digest, evp_md->md_size, key->dsa); if (sig == NULL) { - fatal("dsa_sign: cannot sign"); + fatal("ssh_dss_sign: cannot sign"); } rlen = BN_num_bytes(sig->r); @@ -168,7 +97,7 @@ dsa_sign( } else { /* ietf-drafts */ buffer_init(&b); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, "ssh-dss"); buffer_put_string(&b, sigblob, SIGBLOB_LEN); len = buffer_len(&b); ret = xmalloc(len); @@ -182,7 +111,7 @@ dsa_sign( return 0; } int -dsa_verify( +ssh_dss_verify( Key *key, unsigned char *signature, int signaturelen, unsigned char *data, int datalen) @@ -194,12 +123,12 @@ dsa_verify( EVP_MD_CTX md; unsigned char *sigblob; char *txt; - unsigned int len; + unsigned int len, dlen; int rlen; int ret; if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { - error("dsa_verify: no DSA key"); + error("ssh_dss_verify: no DSA key"); return -1; } @@ -225,8 +154,8 @@ dsa_verify( buffer_init(&b); buffer_append(&b, (char *) signature, signaturelen); ktype = buffer_get_string(&b, NULL); - if (strcmp(KEX_DSS, ktype) != 0) { - error("dsa_verify: cannot handle type %s", ktype); + if (strcmp("ssh-dss", ktype) != 0) { + error("ssh_dss_verify: cannot handle type %s", ktype); buffer_free(&b); return -1; } @@ -258,14 +187,15 @@ dsa_verify( } /* sha1 the data */ - digest = xmalloc(evp_md->md_size); + dlen = evp_md->md_size; + digest = xmalloc(dlen); EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, NULL); - ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa); + ret = DSA_do_verify(digest, dlen, sig, key->dsa); - memset(digest, 0, evp_md->md_size); + memset(digest, 0, dlen); xfree(digest); DSA_SIG_free(sig); @@ -281,24 +211,6 @@ dsa_verify( txt = "error"; break; } - debug("dsa_verify: signature %s", txt); + debug("ssh_dss_verify: signature %s", txt); return ret; } - -Key * -dsa_generate_key(unsigned int bits) -{ - DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); - Key *k; - if (dsa == NULL) { - fatal("DSA_generate_parameters failed"); - } - if (!DSA_generate_key(dsa)) { - fatal("DSA_generate_keys failed"); - } - - k = key_new(KEY_EMPTY); - k->type = KEY_DSA; - k->dsa = dsa; - return k; -} diff --git a/usr.bin/ssh/dsa.h b/usr.bin/ssh/ssh-dss.h index 252e7880beb..7b376e82f1f 100644 --- a/usr.bin/ssh/dsa.h +++ b/usr.bin/ssh/ssh-dss.h @@ -24,22 +24,16 @@ #ifndef DSA_H #define DSA_H -Key *dsa_key_from_blob(char *blob, int blen); -int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp); - int -dsa_sign( +ssh_dss_sign( Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen); int -dsa_verify( +ssh_dss_verify( Key *key, unsigned char *signature, int signaturelen, unsigned char *data, int datalen); -Key * -dsa_generate_key(unsigned int bits); - #endif diff --git a/usr.bin/ssh/ssh-keygen.1 b/usr.bin/ssh/ssh-keygen.1 index 688d2acd96b..3a7ffe23f24 100644 --- a/usr.bin/ssh/ssh-keygen.1 +++ b/usr.bin/ssh/ssh-keygen.1 @@ -43,8 +43,9 @@ .Nd authentication key generation .Sh SYNOPSIS .Nm ssh-keygen -.Op Fl dq +.Op Fl q .Op Fl b Ar bits +.Op Fl t Ar type .Op Fl N Ar new_passphrase .Op Fl C Ar comment .Op Fl f Ar output_keyfile @@ -79,8 +80,8 @@ generates and manages authentication keys for .Nm defaults to generating an RSA key for use by protocols 1.3 and 1.5; specifying the -.Fl d -flag will create a DSA key instead for use by protocol 2.0. +.Fl t +allows you to create a key for use by protocol 2.0. .Pp Normally each user wishing to use SSH with RSA or DSA authentication runs this once to create the authentication @@ -154,6 +155,17 @@ Silence Used by .Pa /etc/rc when creating a new key. +.It Fl t Ar type +Specifies the type of the key to create. +The possible values are +.Dq rsa1 +for protocol version 1 and +.Dq rsa +or +.Dq dsa +for protocol version 2. +The default is +.Dq rsa . .It Fl C Ar comment Provides the new comment. .It Fl N Ar new_passphrase @@ -173,7 +185,7 @@ SSH2-compatible private (or public) key file and print an OpenSSH compatible private (or public) key to stdout. .It Fl y This option will read a private -OpenSSH DSA format file and print an OpenSSH DSA public key to stdout. +OpenSSH format file and print an OpenSSH public key to stdout. .El .Sh FILES .Bl -tag -width Ds @@ -211,7 +223,7 @@ Contains the public key for authentication. The contents of this file should be added to .Pa $HOME/.ssh/authorized_keys2 on all machines -where you wish to log in using DSA authentication. +where you wish to log in using public key authentication. There is no need to keep the contents of this file secret. .El .Sh AUTHORS diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index e7b057fea0e..26f0f841fd4 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.33 2000/11/12 19:50:38 markus Exp $"); #include <openssl/evp.h> #include <openssl/pem.h> @@ -23,7 +23,6 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.32 2000/10/09 21:30:44 markus Exp $"); #include "xmalloc.h" #include "key.h" #include "rsa.h" -#include "dsa.h" #include "authfile.h" #include "uuencode.h" @@ -67,7 +66,10 @@ char *identity_comment = NULL; int convert_to_ssh2 = 0; int convert_from_ssh2 = 0; int print_public = 0; -int dsa_mode = 0; + +/* key type */ +int dsa_mode = 0; /* compat */ +char *key_type_name = NULL; /* argv0 */ extern char *__progname; @@ -126,12 +128,12 @@ do_convert_to_ssh2(struct passwd *pw) perror(identity_file); exit(1); } - k = key_new(KEY_DSA); + k = key_new(KEY_UNSPEC); if (!try_load_key(identity_file, k)) { fprintf(stderr, "load failed\n"); exit(1); } - dsa_make_key_blob(k, &blob, &len); + key_to_blob(k, &blob, &len); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n", @@ -262,7 +264,7 @@ do_convert_from_ssh2(struct passwd *pw) } k = private ? do_convert_private_ssh2_from_blob(blob, blen) : - dsa_key_from_blob(blob, blen); + key_from_blob(blob, blen); if (k == NULL) { fprintf(stderr, "decode blob failed.\n"); exit(1); @@ -284,8 +286,6 @@ void do_print_public(struct passwd *pw) { Key *k; - int len; - unsigned char *blob; struct stat st; if (!have_identity) @@ -294,16 +294,14 @@ do_print_public(struct passwd *pw) perror(identity_file); exit(1); } - k = key_new(KEY_DSA); + k = key_new(KEY_UNSPEC); if (!try_load_key(identity_file, k)) { fprintf(stderr, "load failed\n"); exit(1); } - dsa_make_key_blob(k, &blob, &len); if (!key_write(k, stdout)) fprintf(stderr, "key_write failed"); key_free(k); - xfree(blob); fprintf(stdout, "\n"); exit(0); } @@ -311,12 +309,11 @@ do_print_public(struct passwd *pw) void do_fingerprint(struct passwd *pw) { - /* XXX RSA1 only */ FILE *f; Key *public; char *comment = NULL, *cp, *ep, line[16*1024]; - int i, skip = 0, num = 1, invalid = 1; + int i, skip = 0, num = 1, invalid = 1, success = 0; unsigned int ignore; struct stat st; @@ -326,14 +323,27 @@ do_fingerprint(struct passwd *pw) perror(identity_file); exit(1); } - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (load_public_key(identity_file, public, &comment)) { - printf("%d %s %s\n", BN_num_bits(public->rsa->n), - key_fingerprint(public), comment); + success = 1; + } else { + key_free(public); + public = key_new(KEY_UNSPEC); + if (try_load_public_key(identity_file, public, &comment)) + success = 1; + else + error("try_load_public_key KEY_UNSPEC failed"); + } + if (success) { + printf("%d %s %s\n", key_size(public), key_fingerprint(public), comment); key_free(public); + xfree(comment); exit(0); } + /* XXX RSA1 only */ + + public = key_new(KEY_RSA1); f = fopen(identity_file, "r"); if (f != NULL) { while (fgets(line, sizeof(line), f)) { @@ -400,7 +410,7 @@ do_change_passphrase(struct passwd *pw) struct stat st; Key *private; Key *public; - int type = dsa_mode ? KEY_DSA : KEY_RSA; + int type = KEY_RSA1; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); @@ -408,18 +418,13 @@ do_change_passphrase(struct passwd *pw) perror(identity_file); exit(1); } - - if (type == KEY_RSA) { - /* XXX this works currently only for RSA */ - public = key_new(type); - if (!load_public_key(identity_file, public, NULL)) { - printf("%s is not a valid key file.\n", identity_file); - exit(1); - } + public = key_new(type); + if (!load_public_key(identity_file, public, NULL)) { + type = KEY_UNSPEC; + } else { /* Clear the public key since we are just about to load the whole file. */ key_free(public); } - /* Try to load the file with empty passphrase. */ private = key_new(type); if (!load_private_key(identity_file, "", private, &comment)) { @@ -504,13 +509,13 @@ do_change_comment(struct passwd *pw) * Try to load the public key from the file the verify that it is * readable and of the proper format. */ - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(identity_file, public, NULL)) { printf("%s is not a valid key file.\n", identity_file); exit(1); } - private = key_new(KEY_RSA); + private = key_new(KEY_RSA1); if (load_private_key(identity_file, "", private, &comment)) passphrase = xstrdup(""); else { @@ -579,7 +584,7 @@ do_change_comment(struct passwd *pw) void usage(void) { - printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); + printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); exit(1); } @@ -594,8 +599,10 @@ main(int ac, char **av) int opt; struct stat st; FILE *f; + int type = KEY_RSA1; Key *private; Key *public; + extern int optind; extern char *optarg; @@ -612,7 +619,7 @@ main(int ac, char **av) exit(1); } - while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) { + while ((opt = getopt(ac, av, "dqpclRxXyb:f:t:P:N:C:")) != EOF) { switch (opt) { case 'b': bits = atoi(optarg); @@ -656,10 +663,8 @@ main(int ac, char **av) break; case 'R': - if (rsa_alive() == 0) - exit(1); - else - exit(0); + /* unused */ + exit(0); break; case 'x': @@ -675,9 +680,15 @@ main(int ac, char **av) break; case 'd': + key_type_name = "dsa"; dsa_mode = 1; break; + case 't': + key_type_name = optarg; + dsa_mode = (strcmp(optarg, "dsa") == 0); + break; + case '?': default: usage(); @@ -691,13 +702,6 @@ main(int ac, char **av) printf("Can only have one of -p and -c.\n"); usage(); } - /* check if RSA support is needed and exists */ - if (dsa_mode == 0 && rsa_alive() == 0) { - fprintf(stderr, - "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", - __progname); - exit(1); - } if (print_fingerprint) do_fingerprint(pw); if (change_passphrase) @@ -713,22 +717,21 @@ main(int ac, char **av) arc4random_stir(); - if (dsa_mode != 0) { - if (!quiet) - printf("Generating DSA parameter and key.\n"); - public = private = dsa_generate_key(bits); - if (private == NULL) { - fprintf(stderr, "dsa_generate_keys failed"); + if (key_type_name != NULL) { + type = key_type_from_name(key_type_name); + if (type == KEY_UNSPEC) { + fprintf(stderr, "unknown key type %s", key_type_name); exit(1); } - } else { - if (quiet) - rsa_set_verbose(0); - /* Generate the rsa key pair. */ - public = key_new(KEY_RSA); - private = key_new(KEY_RSA); - rsa_generate_key(private->rsa, public->rsa, bits); } + if (!quiet) + printf("Generating public/private key pair.\n"); + private = key_generate(type, bits); + if (private == NULL) { + fprintf(stderr, "key_generate failed"); + exit(1); + } + public = key_from_private(private); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); @@ -797,9 +800,7 @@ passphrase_again: xfree(passphrase1); /* Clear the private key and the random number generator. */ - if (private != public) { - key_free(private); - } + key_free(private); arc4random_stir(); if (!quiet) diff --git a/usr.bin/ssh/ssh-rsa.c b/usr.bin/ssh/ssh-rsa.c new file mode 100644 index 00000000000..cc31154d969 --- /dev/null +++ b/usr.bin/ssh/ssh-rsa.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-rsa.c,v 1.1 2000/11/12 19:50:38 markus Exp $"); + +#include "ssh.h" +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" + +#include <openssl/evp.h> +#include <openssl/dsa.h> +#include <openssl/rsa.h> +#include <openssl/err.h> + +#include "key.h" + +#define INTBLOB_LEN 20 +#define SIGBLOB_LEN (2*INTBLOB_LEN) + +/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ +int +ssh_rsa_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen) +{ + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + unsigned char *digest, *sig, *ret; + unsigned int slen, dlen, len; + int ok; + Buffer b; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_sign: no RSA key"); + return -1; + } + slen = RSA_size(key->rsa); + sig = xmalloc(slen); + + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + ok = RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa); + memset(digest, 'd', dlen); + xfree(digest); + + if (ok != 1) { + int ecode = ERR_get_error(); + error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL)); + xfree(sig); + return -1; + } + if (len < slen) { + int diff = slen - len; + debug("slen %d > len %d", slen, len); + memmove(sig + diff, sig, len); + memset(sig, 0, diff); + } else if (len > slen) { + error("ssh_rsa_sign: slen %d slen2 %d", slen, len); + xfree(sig); + return -1; + } + /* encode signature */ + buffer_init(&b); + buffer_put_cstring(&b, "ssh-rsa"); + buffer_put_string(&b, sig, slen); + len = buffer_len(&b); + ret = xmalloc(len); + memcpy(ret, buffer_ptr(&b), len); + buffer_free(&b); + memset(sig, 's', slen); + xfree(sig); + + if (lenp != NULL) + *lenp = len; + if (sigp != NULL) + *sigp = ret; + debug2("ssh_rsa_sign: done"); + return 0; +} + +int +ssh_rsa_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen) +{ + Buffer b; + EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + char *ktype; + unsigned char *sigblob, *digest; + unsigned int len, dlen; + int rlen; + int ret; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_verify: no RSA key"); + return -1; + } + buffer_init(&b); + buffer_append(&b, (char *) signature, signaturelen); + ktype = buffer_get_string(&b, NULL); + if (strcmp("ssh-rsa", ktype) != 0) { + error("ssh_rsa_verify: cannot handle type %s", ktype); + buffer_free(&b); + xfree(ktype); + return -1; + } + xfree(ktype); + sigblob = (unsigned char *)buffer_get_string(&b, &len); + rlen = buffer_len(&b); + buffer_free(&b); + if(rlen != 0) { + error("ssh_rsa_verify: remaining bytes in signature %d", rlen); + return -1; + } + + dlen = evp_md->md_size; + digest = xmalloc(dlen); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, NULL); + + ret = RSA_verify(NID_sha1, digest, dlen, sigblob, len, key->rsa); + memset(digest, 'd', dlen); + xfree(digest); + memset(sigblob, 's', len); + xfree(sigblob); + if (ret == 0) { + int ecode = ERR_get_error(); + error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL)); + } + debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); + return ret; +} diff --git a/usr.bin/ssh/ssh-rsa.h b/usr.bin/ssh/ssh-rsa.h new file mode 100644 index 00000000000..29a0c029c8e --- /dev/null +++ b/usr.bin/ssh/ssh-rsa.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SSH_RSA_H +#define SSH_RSA_H + +int +ssh_rsa_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen); + +int +ssh_rsa_verify( + Key *key, + unsigned char *signature, int signaturelen, + unsigned char *data, int datalen); + +#endif diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1 index c557110f6ef..5a1871c4c53 100644 --- a/usr.bin/ssh/ssh.1 +++ b/usr.bin/ssh/ssh.1 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.67 2000/11/10 05:10:40 aaron Exp $ +.\" $OpenBSD: ssh.1,v 1.68 2000/11/12 19:50:38 markus Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -209,9 +209,9 @@ At first, the client attempts to authenticate using the public key method. If this method fails password authentication is tried. .Pp The public key method is similar to RSA authentication described -in the previous section except that the DSA algorithm is used -instead of the patented RSA algorithm. -The client uses his private DSA key +in the previous section except that the DSA or RSA algorithm is used +instead. +The client uses his private key .Pa $HOME/.ssh/id_dsa to sign the session identifier and sends the result to the server. The server checks whether the matching public key is listed in @@ -331,7 +331,7 @@ identifications for all hosts it has ever been used with. RSA host keys are stored in .Pa $HOME/.ssh/known_hosts and -DSA host keys are stored in +host keys used in the protocol version 2 are stored in .Pa $HOME/.ssh/known_hosts2 in the user's home directory. Additionally, the files @@ -408,7 +408,7 @@ something like Allows remote hosts to connect to local forwarded ports. .It Fl i Ar identity_file Selects the file from which the identity (private key) for -RSA authentication is read. +RSA or DSA authentication is read. Default is .Pa $HOME/.ssh/identity in the user's home directory. @@ -677,14 +677,12 @@ Specifies the number of tries (one per second) to make before falling back to rsh or exiting. The argument must be an integer. This may be useful in scripts if the connection sometimes fails. -.It Cm DSAAuthentication -Specifies whether to try DSA authentication. +.It Cm PubkeyAuthentication +Specifies whether to try public key authentication. The argument to this keyword must be .Dq yes or .Dq no . -DSA authentication will only be -attempted if a DSA identity file exists. Note that this option applies to protocol version 2 only. .It Cm EscapeChar Sets the escape character (default: @@ -762,16 +760,6 @@ syntax to refer to a user's home directory. It is possible to have multiple identity files specified in configuration files; all these identities will be tried in sequence. -.It Cm IdentityFile2 -Specifies the file from which the user's DSA authentication identity -is read (default -.Pa $HOME/.ssh/id_dsa -in the user's home directory). -The file name may use the tilde -syntax to refer to a user's home directory. -It is possible to have -multiple identity files specified in configuration files; all these -identities will be tried in sequence. .It Cm KeepAlive Specifies whether the system should send keepalive messages to the other side. @@ -1113,7 +1101,7 @@ spaces). This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. .It Pa $HOME/.ssh/authorized_keys2 -Lists the DSA keys that can be used for logging in as this user. +Lists the public keys (DSA/RSA) that can be used for logging in as this user. This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. .It Pa /etc/ssh_known_hosts, /etc/ssh_known_hosts2 @@ -1121,7 +1109,7 @@ Systemwide list of known host keys. .Pa /etc/ssh_known_hosts contains RSA and .Pa /etc/ssh_known_hosts2 -contains DSA keys. +contains DSA or RSA keys for protocol version 2. These files should be prepared by the system administrator to contain the public host keys of all machines in the organization. diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index c5c769629a0..6e2acda0ec4 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -39,11 +39,12 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.71 2000/11/06 23:13:26 markus Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.72 2000/11/12 19:50:38 markus Exp $"); #include <openssl/evp.h> #include <openssl/dsa.h> #include <openssl/rsa.h> +#include <openssl/err.h> #include "xmalloc.h" #include "ssh.h" @@ -210,8 +211,9 @@ rsh_connect(char *host, char *user, Buffer * command) exit(1); } -int ssh_session(void); -int ssh_session2(void); +int ssh_session(void); +int ssh_session2(void); +int guess_identity_file_type(const char *filename); /* * Main program for the ssh client. @@ -349,14 +351,13 @@ main(int ac, char **av) case 'i': if (stat(optarg, &st) < 0) { fprintf(stderr, "Warning: Identity file %s does not exist.\n", - optarg); + optarg); break; } if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) fatal("Too many identity files specified (max %d)", - SSH_MAX_IDENTITY_FILES); - options.identity_files[options.num_identity_files++] = - xstrdup(optarg); + SSH_MAX_IDENTITY_FILES); + options.identity_files[options.num_identity_files++] = xstrdup(optarg); break; case 't': tty_flag = 1; @@ -466,6 +467,7 @@ main(int ac, char **av) usage(); SSLeay_add_all_algorithms(); + ERR_load_crypto_strings(); /* Initialize the command to execute on remote host. */ buffer_init(&command); @@ -540,20 +542,6 @@ main(int ac, char **av) /* reinit */ log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0); - /* check if RSA support exists */ - if ((options.protocol & SSH_PROTO_1) && - rsa_alive() == 0) { - log("%s: no RSA support in libssl and libcrypto. See ssl(8).", - __progname); - log("Disabling protocol version 1"); - options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED); - } - if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) { - fprintf(stderr, "%s: No protocol version available.\n", - __progname); - exit(1); - } - if (options.user == NULL) options.user = xstrdup(pw->pw_name); @@ -609,7 +597,7 @@ main(int ac, char **av) if (ok && (options.protocol & SSH_PROTO_1)) { Key k; host_private_key = RSA_new(); - k.type = KEY_RSA; + k.type = KEY_RSA1; k.rsa = host_private_key; if (load_private_key(HOST_KEY_FILE, "", &k, NULL)) host_private_key_loaded = 1; @@ -656,23 +644,23 @@ main(int ac, char **av) } exit(1); } - /* Expand ~ in options.identity_files. */ + /* Expand ~ in options.identity_files, known host file names. */ /* XXX mem-leaks */ - for (i = 0; i < options.num_identity_files; i++) + for (i = 0; i < options.num_identity_files; i++) { options.identity_files[i] = - tilde_expand_filename(options.identity_files[i], original_real_uid); - for (i = 0; i < options.num_identity_files2; i++) - options.identity_files2[i] = - tilde_expand_filename(options.identity_files2[i], original_real_uid); - /* Expand ~ in known host file names. */ - options.system_hostfile = tilde_expand_filename(options.system_hostfile, - original_real_uid); - options.user_hostfile = tilde_expand_filename(options.user_hostfile, - original_real_uid); - options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2, - original_real_uid); - options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2, - original_real_uid); + tilde_expand_filename(options.identity_files[i], original_real_uid); + options.identity_files_type[i] = guess_identity_file_type(options.identity_files[i]); + debug("identity file %s type %d", options.identity_files[i], + options.identity_files_type[i]); + } + options.system_hostfile = + tilde_expand_filename(options.system_hostfile, original_real_uid); + options.user_hostfile = + tilde_expand_filename(options.user_hostfile, original_real_uid); + options.system_hostfile2 = + tilde_expand_filename(options.system_hostfile2, original_real_uid); + options.user_hostfile2 = + tilde_expand_filename(options.user_hostfile2, original_real_uid); /* Log into the remote system. This never returns if the login fails. */ ssh_login(host_private_key_loaded, host_private_key, @@ -1023,3 +1011,23 @@ ssh_session2(void) return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id); } + +int +guess_identity_file_type(const char *filename) +{ + struct stat st; + Key *public; + int type = KEY_RSA1; /* default */ + + if (stat(filename, &st) < 0) { + perror(filename); + return KEY_UNSPEC; + } + public = key_new(type); + if (!load_public_key(filename, public, NULL)) { + /* ok, so we will assume this is 'some' key */ + type = KEY_UNSPEC; + } + key_free(public); + return type; +} diff --git a/usr.bin/ssh/ssh_config b/usr.bin/ssh/ssh_config index cb360d04b59..fdac1313c6a 100644 --- a/usr.bin/ssh/ssh_config +++ b/usr.bin/ssh/ssh_config @@ -13,9 +13,9 @@ # Site-wide defaults for various options # Host * -# ForwardAgent yes -# ForwardX11 yes -# RhostsAuthentication yes +# ForwardAgent no +# ForwardX11 no +# RhostsAuthentication no # RhostsRSAAuthentication yes # RSAAuthentication yes # PasswordAuthentication yes @@ -23,9 +23,12 @@ # UseRsh no # BatchMode no # CheckHostIP yes -# StrictHostKeyChecking no +# StrictHostKeyChecking yes # IdentityFile ~/.ssh/identity +# IdentityFile ~/.ssh/id_dsa +# IdentityFile ~/.ssh/id_rsa1 +# IdentityFile ~/.ssh/id_rsa2 # Port 22 -# Protocol 2,1 +# Protocol 1,2 # Cipher blowfish # EscapeChar ~ diff --git a/usr.bin/ssh/sshconnect1.c b/usr.bin/ssh/sshconnect1.c index ce560791cea..227e10b4b9c 100644 --- a/usr.bin/ssh/sshconnect1.c +++ b/usr.bin/ssh/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.8 2000/10/12 09:59:19 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.9 2000/11/12 19:50:38 markus Exp $"); #include <openssl/bn.h> #include <openssl/dsa.h> @@ -62,7 +62,7 @@ try_agent_authentication() return 0; challenge = BN_new(); - key = key_new(KEY_RSA); + key = key_new(KEY_RSA1); /* Loop through identities served by the agent. */ for (key = ssh_get_first_identity(auth, &comment, 1); @@ -196,7 +196,7 @@ try_rsa_authentication(const char *authfile) int plen, clen; /* Try to load identification for the authentication key. */ - public = key_new(KEY_RSA); + public = key_new(KEY_RSA1); if (!load_public_key(authfile, public, &comment)) { key_free(public); /* Could not load it. Fail. */ @@ -237,7 +237,7 @@ try_rsa_authentication(const char *authfile) debug("Received RSA challenge from server."); - private = key_new(KEY_RSA); + private = key_new(KEY_RSA1); /* * Load the private key. Try first with empty passphrase; if it * fails, ask for a passphrase. @@ -760,7 +760,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr) packet_integrity_check(payload_len, 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, SSH_SMSG_PUBLIC_KEY); - k.type = KEY_RSA; + k.type = KEY_RSA1; k.rsa = host_key; check_host_key(host, hostaddr, &k, options.user_hostfile, options.system_hostfile); @@ -994,7 +994,8 @@ ssh_userauth( /* Try RSA authentication for each identity. */ for (i = 0; i < options.num_identity_files; i++) - if (try_rsa_authentication(options.identity_files[i])) + if (options.identity_files_type[i] == KEY_RSA1 && + try_rsa_authentication(options.identity_files[i])) return; } /* Try skey authentication if the server supports it. */ diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c index 6ba23d445c5..bb4774aa46f 100644 --- a/usr.bin/ssh/sshconnect2.c +++ b/usr.bin/ssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.27 2000/10/19 16:45:16 provos Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.28 2000/11/12 19:50:38 markus Exp $"); #include <openssl/bn.h> #include <openssl/rsa.h> @@ -45,7 +45,6 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.27 2000/10/19 16:45:16 provos Exp $"); #include "kex.h" #include "myproposal.h" #include "key.h" -#include "dsa.h" #include "sshconnect.h" #include "authfile.h" #include "cli.h" @@ -196,7 +195,7 @@ ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); if (server_host_key == NULL) fatal("cannot decode server_host_key_blob"); @@ -258,8 +257,8 @@ ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, fprintf(stderr, "%02x", (hash[i])&0xff); fprintf(stderr, "\n"); #endif - if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) - fatal("dsa_verify failed for server_host_key"); + if (key_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); key_free(server_host_key); kex_derive_keys(kex, hash, shared_secret); @@ -366,7 +365,7 @@ ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); if (server_host_key == NULL) fatal("cannot decode server_host_key_blob"); @@ -429,8 +428,8 @@ ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, fprintf(stderr, "%02x", (hash[i])&0xff); fprintf(stderr, "\n"); #endif - if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) - fatal("dsa_verify failed for server_host_key"); + if (key_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); key_free(server_host_key); kex_derive_keys(kex, hash, shared_secret); @@ -485,7 +484,7 @@ Authmethod *authmethod_lookup(const char *name); Authmethod authmethods[] = { {"publickey", userauth_pubkey, - &options.dsa_authentication, + &options.pubkey_authentication, NULL}, {"password", userauth_passwd, @@ -653,8 +652,10 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) int ret = -1; int have_sig = 1; - dsa_make_key_blob(k, &blob, &bloblen); - + if (key_to_blob(k, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + return 0; + } /* data to be signed */ buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { @@ -672,7 +673,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) authctxt->service); buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, key_ssh_name(k)); buffer_put_string(&b, blob, bloblen); /* generate signature */ @@ -682,7 +683,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) buffer_free(&b); return 0; } -#ifdef DEBUG_DSS +#ifdef DEBUG_PK buffer_dump(&b); #endif if (datafellows & SSH_BUG_PUBKEYAUTH) { @@ -693,7 +694,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) buffer_put_cstring(&b, authctxt->service); buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + buffer_put_cstring(&b, key_ssh_name(k)); buffer_put_string(&b, blob, bloblen); } xfree(blob); @@ -719,10 +720,10 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) } /* sign callback */ -int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, +int key_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, unsigned char *data, int datalen) { - return dsa_sign(key, sigp, lenp, data, datalen); + return key_sign(key, sigp, lenp, data, datalen); } int @@ -738,14 +739,13 @@ userauth_pubkey_identity(Authctxt *authctxt, char *filename) } debug("try pubkey: %s", filename); - k = key_new(KEY_DSA); + k = key_new(KEY_UNSPEC); if (!load_private_key(filename, "", k, NULL)) { int success = 0; char *passphrase; char prompt[300]; snprintf(prompt, sizeof prompt, - "Enter passphrase for %s key '%.100s': ", - key_type(k), filename); + "Enter passphrase for key '%.100s': ", filename); for (i = 0; i < options.number_of_password_prompts; i++) { passphrase = read_passphrase(prompt, 0); if (strcmp(passphrase, "") != 0) { @@ -766,7 +766,7 @@ userauth_pubkey_identity(Authctxt *authctxt, char *filename) return 0; } } - ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb); + ret = sign_and_send_pubkey(authctxt, k, key_sign_cb); key_free(k); return ret; } @@ -782,24 +782,26 @@ int userauth_pubkey_agent(Authctxt *authctxt) { static int called = 0; + int ret = 0; char *comment; Key *k; - int ret; if (called == 0) { - k = ssh_get_first_identity(authctxt->agent, &comment, 2); + if (ssh_get_num_identities(authctxt->agent, 2) == 0) + debug2("userauth_pubkey_agent: no keys at all"); called = 1; - } else { - k = ssh_get_next_identity(authctxt->agent, &comment, 2); } + k = ssh_get_next_identity(authctxt->agent, &comment, 2); if (k == NULL) { - debug2("no more DSA keys from agent"); - return 0; + debug2("userauth_pubkey_agent: no more keys"); + } else { + debug("userauth_pubkey_agent: trying agent key %s", comment); + xfree(comment); + ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); + key_free(k); } - debug("trying DSA agent key %s", comment); - xfree(comment); - ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); - key_free(k); + if (ret == 0) + debug2("userauth_pubkey_agent: no message sent"); return ret; } @@ -809,10 +811,17 @@ userauth_pubkey(Authctxt *authctxt) static int idx = 0; int sent = 0; - if (authctxt->agent != NULL) - sent = userauth_pubkey_agent(authctxt); - while (sent == 0 && idx < options.num_identity_files2) - sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]); + if (authctxt->agent != NULL) { + do { + sent = userauth_pubkey_agent(authctxt); + } while(!sent && authctxt->agent->howmany > 0); + } + while (!sent && idx < options.num_identity_files) { + if (options.identity_files_type[idx] != KEY_RSA1) + sent = userauth_pubkey_identity(authctxt, + options.identity_files[idx]); + idx++; + } return sent; } diff --git a/usr.bin/ssh/sshd.8 b/usr.bin/ssh/sshd.8 index 4c0df4314fd..2c54b6e4aa0 100644 --- a/usr.bin/ssh/sshd.8 +++ b/usr.bin/ssh/sshd.8 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.71 2000/11/10 05:10:40 aaron Exp $ +.\" $OpenBSD: sshd.8,v 1.72 2000/11/12 19:50:38 markus Exp $ .Dd September 25, 1999 .Dt SSHD 8 .Os @@ -144,7 +144,7 @@ through a cryptographic message authentication code (hmac-sha1 or hmac-md5). .Pp Protocol version 2 provides a public key based -user authentication method (DSAAuthentication) +user authentication method (PubkeyAuthentication) and conventional password authentication. .Pp .Ss Command execution and data forwarding @@ -359,8 +359,8 @@ and can be used as wildcards in the patterns. Only user names are valid; a numerical user ID isn't recognized. By default login is allowed regardless of the user name. -.It Cm DSAAuthentication -Specifies whether DSA authentication is allowed. +.It Cm PubkeyAuthentication +Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. @@ -373,20 +373,20 @@ or .Dq no . The default is .Dq no . -.It Cm HostDSAKey -Specifies the file containing the private DSA host key (default -.Pa /etc/ssh_host_dsa_key ) -used by SSH protocol 2.0. -Note that -.Nm -disables protocol 2.0 if this file is group/world-accessible. .It Cm HostKey -Specifies the file containing the private RSA host key (default +Specifies the file containing the private host keys (default .Pa /etc/ssh_host_key ) -used by SSH protocols 1.3 and 1.5. +used by SSH protocol versions 1 and 2. Note that .Nm -disables protocols 1.3 and 1.5 if this file is group/world-accessible. +if this file is group/world-accessible. +It is possible to have multiple host key files. +.Dq rsa1 +keys are used for version 1 and +.Dq dsa +or +.Dq rsa +are used for version 2 of the SSH protocol. .It Cm IgnoreRhosts Specifies that .Pa .rhosts diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index fdee1e4902c..d3c8984dbfb 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.133 2000/11/06 23:13:27 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.134 2000/11/12 19:50:38 markus Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -61,7 +61,6 @@ RCSID("$OpenBSD: sshd.c,v 1.133 2000/11/06 23:13:27 markus Exp $"); #include <openssl/dsa.h> #include <openssl/rsa.h> #include "key.h" -#include "dsa.h" #include "dh.h" #include "auth.h" @@ -135,9 +134,11 @@ char *server_version_string = NULL; * not very useful. Currently, memory locking is not implemented. */ struct { - RSA *private_key; /* Private part of empheral server key. */ - RSA *host_key; /* Private part of host key. */ - Key *dsa_host_key; /* Private DSA host key. */ + Key *server_key; /* empheral server key */ + Key *ssh1_host_key; /* ssh1 host key */ + Key **host_keys; /* all private host keys */ + int have_ssh1_key; + int have_ssh2_key; } sensitive_data; /* @@ -149,10 +150,6 @@ int key_used = 0; /* This is set to true when SIGHUP is received. */ int received_sighup = 0; -/* Public side of the server key. This value is regenerated regularly with - the private key. */ -RSA *public_key; - /* session identifier, used by RSA-auth */ unsigned char session_id[16]; @@ -261,6 +258,17 @@ grace_alarm_handler(int sig) */ /* XXX do we really want this work to be done in a signal handler ? -m */ void +generate_empheral_server_key(void) +{ + log("Generating %s%d bit RSA key.", sensitive_data.server_key ? "new " : "", + options.server_key_bits); + if (sensitive_data.server_key != NULL) + key_free(sensitive_data.server_key); + sensitive_data.server_key = key_generate(KEY_RSA1, options.server_key_bits); + arc4random_stir(); + log("RSA key generation complete."); +} +void key_regeneration_alarm(int sig) { int save_errno = errno; @@ -268,21 +276,8 @@ key_regeneration_alarm(int sig) /* Check if we should generate a new key. */ if (key_used) { /* This should really be done in the background. */ - log("Generating new %d bit RSA key.", options.server_key_bits); - - if (sensitive_data.private_key != NULL) - RSA_free(sensitive_data.private_key); - sensitive_data.private_key = RSA_new(); - - if (public_key != NULL) - RSA_free(public_key); - public_key = RSA_new(); - - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); + generate_empheral_server_key(); key_used = 0; - log("RSA key generation complete."); } /* Reschedule the alarm. */ signal(SIGALRM, key_regeneration_alarm); @@ -417,18 +412,93 @@ sshd_exchange_identification(int sock_in, int sock_out) } +/* Destroy the host and server keys. They will no longer be needed. */ void destroy_sensitive_data(void) { - /* Destroy the private and public keys. They will no longer be needed. */ - if (public_key) - RSA_free(public_key); - if (sensitive_data.private_key) - RSA_free(sensitive_data.private_key); - if (sensitive_data.host_key) - RSA_free(sensitive_data.host_key); - if (sensitive_data.dsa_host_key != NULL) - key_free(sensitive_data.dsa_host_key); + int i; + + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } + for(i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; + } + } + sensitive_data.ssh1_host_key = NULL; +} +Key * +load_private_key_autodetect(const char *filename) +{ + struct stat st; + int type; + Key *public, *private; + + if (stat(filename, &st) < 0) { + perror(filename); + return NULL; + } + /* + * try to load the public key. right now this only works for RSA1, + * since SSH2 keys are fully encrypted + */ + type = KEY_RSA1; + public = key_new(type); + if (!load_public_key(filename, public, NULL)) { + /* ok, so we will assume this is 'some' key */ + type = KEY_UNSPEC; + } + key_free(public); + + /* Ok, try key with empty passphrase */ + private = key_new(type); + if (load_private_key(filename, "", private, NULL)) { + debug("load_private_key_autodetect: type %d %s", + private->type, key_type(private)); + return private; + } + key_free(private); + return NULL; +} + +char * +list_hostkey_types(void) +{ + static char buf[1024]; + int i; + buf[0] = '\0'; + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key == NULL) + continue; + switch(key->type) { + case KEY_RSA: + case KEY_DSA: + strlcat(buf, key_ssh_name(key), sizeof buf); + strlcat(buf, ",", sizeof buf); + break; + } + } + i = strlen(buf); + if (i > 0 && buf[i-1] == ',') + buf[i-1] = '\0'; + debug("list_hostkey_types: %s", buf); + return buf; +} + +Key * +get_hostkey_by_type(int type) +{ + int i; + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key != NULL && key->type == type) + return key; + } + return NULL; } /* @@ -547,7 +617,11 @@ main(int ac, char **av) options.key_regeneration_time = atoi(optarg); break; case 'h': - options.host_key_file = optarg; + if (options.num_host_key_files >= MAX_HOSTKEYS) { + fprintf(stderr, "too many host keys.\n"); + exit(1); + } + options.host_key_files[options.num_host_key_files++] = optarg; break; case 'V': client_version_string = optarg; @@ -602,39 +676,39 @@ main(int ac, char **av) debug("sshd version %.100s", SSH_VERSION); - sensitive_data.dsa_host_key = NULL; - sensitive_data.host_key = NULL; + /* load private host keys */ + sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*)); + sensitive_data.server_key = NULL; + sensitive_data.ssh1_host_key = NULL; + sensitive_data.have_ssh1_key = 0; + sensitive_data.have_ssh2_key = 0; - /* check if RSA support exists */ - if ((options.protocol & SSH_PROTO_1) && - rsa_alive() == 0) { - log("no RSA support in libssl and libcrypto. See ssl(8)"); - log("Disabling protocol version 1"); - options.protocol &= ~SSH_PROTO_1; - } - /* Load the RSA/DSA host key. It must have empty passphrase. */ - if (options.protocol & SSH_PROTO_1) { - Key k; - sensitive_data.host_key = RSA_new(); - k.type = KEY_RSA; - k.rsa = sensitive_data.host_key; - errno = 0; - if (!load_private_key(options.host_key_file, "", &k, NULL)) { + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = load_private_key_autodetect(options.host_key_files[i]); + if (key == NULL) { error("Could not load host key: %.200s: %.100s", - options.host_key_file, strerror(errno)); - log("Disabling protocol version 1"); - options.protocol &= ~SSH_PROTO_1; + options.host_key_files[i], strerror(errno)); + continue; } - k.rsa = NULL; - } - if (options.protocol & SSH_PROTO_2) { - sensitive_data.dsa_host_key = key_new(KEY_DSA); - if (!load_private_key(options.host_dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) { - - error("Could not load DSA host key: %.200s", options.host_dsa_key_file); - log("Disabling protocol version 2"); - options.protocol &= ~SSH_PROTO_2; + switch(key->type){ + case KEY_RSA1: + sensitive_data.ssh1_host_key = key; + sensitive_data.have_ssh1_key = 1; + break; + case KEY_RSA: + case KEY_DSA: + sensitive_data.have_ssh2_key = 1; + break; } + sensitive_data.host_keys[i] = key; + } + if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { + log("Disabling protocol version 1. Could not load host key"); + options.protocol &= ~SSH_PROTO_1; + } + if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { + log("Disabling protocol version 2. Could not load host key"); + options.protocol &= ~SSH_PROTO_2; } if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) { if (silent == 0) @@ -656,11 +730,11 @@ main(int ac, char **av) * hate software patents. I dont know if this can go? Niels */ if (options.server_key_bits > - BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED && + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - SSH_KEY_BITS_RESERVED && options.server_key_bits < - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED; + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } @@ -695,9 +769,6 @@ main(int ac, char **av) /* Reinitialize the log (because of the fork above). */ log_init(av0, options.log_level, options.log_facility, log_stderr); - /* Do not display messages to stdout in RSA code. */ - rsa_set_verbose(0); - /* Initialize the random number generator. */ arc4random_stir(); @@ -719,16 +790,8 @@ main(int ac, char **av) * ttyfd happens to be one of those. */ debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); - - if (options.protocol & SSH_PROTO_1) { - public_key = RSA_new(); - sensitive_data.private_key = RSA_new(); - log("Generating %d bit RSA key.", options.server_key_bits); - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); - log("RSA key generation complete."); - } + if (options.protocol & SSH_PROTO_1) + generate_empheral_server_key(); } else { for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) @@ -805,14 +868,7 @@ main(int ac, char **av) } } if (options.protocol & SSH_PROTO_1) { - public_key = RSA_new(); - sensitive_data.private_key = RSA_new(); - - log("Generating %d bit RSA key.", options.server_key_bits); - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); - log("RSA key generation complete."); + generate_empheral_server_key(); /* Schedule server key regeneration alarm. */ signal(SIGALRM, key_regeneration_alarm); @@ -1128,14 +1184,14 @@ do_ssh1_kex() packet_put_char(cookie[i]); /* Store our public server RSA key. */ - packet_put_int(BN_num_bits(public_key->n)); - packet_put_bignum(public_key->e); - packet_put_bignum(public_key->n); + packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); + packet_put_bignum(sensitive_data.server_key->rsa->e); + packet_put_bignum(sensitive_data.server_key->rsa->n); /* Store our public host RSA key. */ - packet_put_int(BN_num_bits(sensitive_data.host_key->n)); - packet_put_bignum(sensitive_data.host_key->e); - packet_put_bignum(sensitive_data.host_key->n); + packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); /* Put protocol flags. */ packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); @@ -1173,8 +1229,9 @@ do_ssh1_kex() packet_send(); packet_write_wait(); - debug("Sent %d bit public key and %d bit host key.", - BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n)); + debug("Sent %d bit server key and %d bit host key.", + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); /* Read clients reply (cipher type and session key). */ packet_read_expect(&plen, SSH_CMSG_SESSION_KEY); @@ -1206,39 +1263,39 @@ do_ssh1_kex() * Decrypt it using our private server key and private host key (key * with larger modulus first). */ - if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) { + if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { /* Private key has bigger modulus. */ - if (BN_num_bits(sensitive_data.private_key->n) < - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.private_key->n), - BN_num_bits(sensitive_data.host_key->n), - SSH_KEY_BITS_RESERVED); + if (BN_num_bits(sensitive_data.server_key->rsa->n) < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + SSH_KEY_BITS_RESERVED); } rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.private_key); + sensitive_data.server_key->rsa); rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.host_key); + sensitive_data.ssh1_host_key->rsa); } else { /* Host key has bigger modulus (or they are equal). */ - if (BN_num_bits(sensitive_data.host_key->n) < - BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.host_key->n), - BN_num_bits(sensitive_data.private_key->n), - SSH_KEY_BITS_RESERVED); + if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < + BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + BN_num_bits(sensitive_data.server_key->rsa->n), + SSH_KEY_BITS_RESERVED); } rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.host_key); + sensitive_data.ssh1_host_key->rsa); rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.private_key); + sensitive_data.server_key->rsa); } compute_session_id(session_id, cookie, - sensitive_data.host_key->n, - sensitive_data.private_key->n); + sensitive_data.ssh1_host_key->rsa->n, + sensitive_data.server_key->rsa->n); /* Destroy the private and public keys. They will no longer be needed. */ destroy_sensitive_data(); @@ -1252,8 +1309,8 @@ do_ssh1_kex() len = BN_num_bytes(session_key_int); if (len < 0 || len > sizeof(session_key)) fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d", - get_remote_ipaddr(), - len, sizeof(session_key)); + get_remote_ipaddr(), + len, sizeof(session_key)); memset(session_key, 0, sizeof(session_key)); BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); @@ -1297,6 +1354,8 @@ do_ssh2_kex() myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); + server_kexinit = kex_init(myproposal); client_kexinit = xmalloc(sizeof(*client_kexinit)); buffer_init(client_kexinit); @@ -1362,6 +1421,11 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) BIGNUM *shared_secret = 0; DH *dh; BIGNUM *dh_client_pub = 0; + Key *hostkey; + + hostkey = get_hostkey_by_type(kex->hostkey_type); + if (hostkey == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); /* KEXDH */ debug("Wait SSH2_MSG_KEXDH_INIT."); @@ -1414,8 +1478,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) xfree(kbuf); /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, - &server_host_key_blob, &sbloblen); + key_to_blob(hostkey, &server_host_key_blob, &sbloblen); /* calc H */ /* XXX depends on 'kex' */ hash = kex_hash( @@ -1446,7 +1509,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) /* sign H */ /* XXX hashlen depends on KEX */ - dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); + key_sign(hostkey, &signature, &slen, hash, 20); destroy_sensitive_data(); @@ -1486,6 +1549,11 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) BIGNUM *shared_secret = 0; DH *dh; BIGNUM *dh_client_pub = 0; + Key *hostkey; + + hostkey = get_hostkey_by_type(kex->hostkey_type); + if (hostkey == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); /* KEXDHGEX */ debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST."); @@ -1547,8 +1615,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) xfree(kbuf); /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, - &server_host_key_blob, &sbloblen); + key_to_blob(hostkey, &server_host_key_blob, &sbloblen); /* calc H */ /* XXX depends on 'kex' */ hash = kex_hash_gex( @@ -1580,7 +1647,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) /* sign H */ /* XXX hashlen depends on KEX */ - dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); + key_sign(hostkey, &signature, &slen, hash, 20); destroy_sensitive_data(); @@ -1600,4 +1667,3 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) /* have keys, free DH */ DH_free(dh); } - diff --git a/usr.bin/ssh/sshd_config b/usr.bin/ssh/sshd_config index 0ef2fa8915b..6ecc1dc3b45 100644 --- a/usr.bin/ssh/sshd_config +++ b/usr.bin/ssh/sshd_config @@ -5,6 +5,7 @@ Port 22 #ListenAddress 0.0.0.0 #ListenAddress :: HostKey /etc/ssh_host_key +#HostKey /etc/ssh_host_dsa_key ServerKeyBits 768 LoginGraceTime 600 KeyRegenerationInterval 3600 |