*/
#include "includes.h"
-RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $");
+RCSID("$OpenBSD: authfile.c,v 1.28 2001/02/21 09:05:54 deraadt Exp $");
-#include <openssl/bn.h>
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/pem.h>
+#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
*/
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;
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. */
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. */
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);
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;
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;
}
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;
}
* 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;
}
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;
}
*/
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;
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. */
/* 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);
prv->e = NULL;
if (comment_return)
xfree(*comment_return);
+ close(fd);
return 0;
}
/* Read the rest of the private key. */
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 = "<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");
+ 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
if (check_ntsec(filename))
#endif
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;
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;
}
do_load_public_key(const char *filename, Key *k, char **commentp)
{
FILE *f;
- unsigned int bits;
char line[1024];
char *cp;
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);