=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/authfile.c,v retrieving revision 1.20 retrieving revision 1.20.2.3 diff -u -r1.20 -r1.20.2.3 --- src/usr.bin/ssh/authfile.c 2000/10/11 20:27:23 1.20 +++ src/usr.bin/ssh/authfile.c 2001/03/21 19:46:23 1.20.2.3 @@ -36,22 +36,24 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); +RCSID("$OpenBSD: authfile.c,v 1.20.2.3 2001/03/21 19:46:23 jason Exp $"); -#include -#include -#include -#include +#include #include +#include +#include "cipher.h" #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" -#include "ssh.h" #include "key.h" +#include "ssh.h" +#include "log.h" +#include "authfile.h" /* Version identification string for identity files. */ -#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n" +static const char authfile_id_string[] = + "SSH PRIVATE KEY FILE FORMAT 1.1\n"; /* * Saves the authentication (private) key in a file, encrypting it with @@ -61,7 +63,7 @@ */ 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; @@ -111,9 +113,8 @@ buffer_init(&encrypted); /* First store keyfile id string. */ - cp = AUTHFILE_ID_STRING; - for (i = 0; cp[i]; i++) - buffer_put_char(&encrypted, cp[i]); + for (i = 0; authfile_id_string[i]; i++) + buffer_put_char(&encrypted, authfile_id_string[i]); buffer_put_char(&encrypted, 0); /* Store cipher type. */ @@ -130,8 +131,8 @@ buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); cipher_set_key_string(&ciphercontext, cipher, passphrase); - cipher_encrypt(&ciphercontext, (unsigned char *) cp, - (unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer)); + cipher_encrypt(&ciphercontext, (u_char *) cp, + (u_char *) buffer_ptr(&buffer), buffer_len(&buffer)); memset(&ciphercontext, 0, sizeof(ciphercontext)); /* Destroy temporary data. */ @@ -147,7 +148,7 @@ strerror(errno)); buffer_free(&encrypted); close(fd); - remove(filename); + unlink(filename); return 0; } close(fd); @@ -155,16 +156,17 @@ 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 @@ 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 @@ 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; @@ -244,9 +248,9 @@ } close(fd); - /* 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); + /* Check that it is at least big enough to contain the ID string. */ + if (len < sizeof(authfile_id_string)) { + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -254,9 +258,9 @@ * Make sure it begins with the id string. Consume the id string * from the buffer. */ - 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); + for (i = 0; i < sizeof(authfile_id_string); i++) + if (buffer_get_char(&buffer) != authfile_id_string[i]) { + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); return 0; } @@ -288,10 +292,11 @@ 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 @@ */ 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,29 +331,31 @@ 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; } - close(fd); - /* 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); + /* Check that it is at least big enough to contain the ID string. */ + if (len < sizeof(authfile_id_string)) { + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); + close(fd); return 0; } /* * Make sure it begins with the id string. Consume the id string * 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); + for (i = 0; i < sizeof(authfile_id_string); i++) + if (buffer_get_char(&buffer) != authfile_id_string[i]) { + debug3("Bad RSA1 key file %.200s.", filename); buffer_free(&buffer); + close(fd); return 0; } + /* Read cipher type. */ cipher_type = buffer_get_char(&buffer); (void) buffer_get_int(&buffer); /* Reserved data. */ @@ -378,8 +385,8 @@ /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase); - cipher_decrypt(&ciphercontext, (unsigned char *) cp, - (unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer)); + cipher_decrypt(&ciphercontext, (u_char *) cp, + (u_char *) buffer_ptr(&buffer), buffer_len(&buffer)); memset(&ciphercontext, 0, sizeof(ciphercontext)); buffer_free(&buffer); @@ -398,6 +405,7 @@ prv->e = NULL; if (comment_return) xfree(*comment_return); + close(fd); return 0; } /* Read the rest of the private key. */ @@ -426,45 +434,65 @@ BN_CTX_free(ctx); buffer_free(&decrypted); - + close(fd); return 1; } 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 = ""; - 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"); + close(fd); 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 @@ -481,19 +509,19 @@ /* check owner and modes */ if (fstat(fd, &st) < 0 || - (st.st_uid != 0 && st.st_uid != getuid()) || + (st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) || (st.st_mode & 077) != 0) { close(fd); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("Bad ownership or mode(0%3.3o) for '%s'.", - st.st_mode & 0777, filename); + st.st_mode & 0777, filename); error("It is recommended that your private key files are NOT accessible by others."); 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,15 +530,20 @@ BN_clear_free(key->rsa->n); key->rsa->n = NULL; } - ret = load_private_key_rsa(fd, filename, passphrase, - key->rsa, comment_return); + ret = load_private_key_rsa1(fd, filename, passphrase, + key->rsa, comment_return); /* closes fd */ + 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); /* closes fd */ + break; default: + close(fd); break; } - close(fd); return ret; } @@ -518,7 +551,6 @@ do_load_public_key(const char *filename, Key *k, char **commentp) { FILE *f; - unsigned int bits; char line[1024]; char *cp; @@ -537,8 +569,7 @@ 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);