keyfiles.c   keyfiles.c 
skipping to change at line 25 skipping to change at line 25
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to * along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include "config.h"
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#ifndef _WIN32 #ifndef _WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/buffer.h"
#include "libssh/keyfiles.h"
#include "libssh/session.h"
#include "libssh/wrapper.h"
#include "libssh/misc.h"
#include "libssh/keys.h"
/*todo: remove this include */
#include "libssh/string.h"
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
#include <gcrypt.h> #include <gcrypt.h>
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/dsa.h> #include <openssl/dsa.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#endif /* HAVE_LIBCRYPTO */ #endif /* HAVE_LIBCRYPTO */
skipping to change at line 92 skipping to change at line 102
k = header[2*i+1] - 'A' + 10; k = header[2*i+1] - 'A' + 10;
else if ((header[2*i+1] >= 'a') && (header[2*i+1] <= 'f')) else if ((header[2*i+1] >= 'a') && (header[2*i+1] <= 'f'))
k = header[2*i+1] - 'a' + 10; k = header[2*i+1] - 'a' + 10;
else else
return -1; return -1;
iv[i] = (j << 4) + k; iv[i] = (j << 4) + k;
} }
return 0; return 0;
} }
static u32 char_to_u32(unsigned char *data, u32 size) { static uint32_t char_to_u32(unsigned char *data, uint32_t size) {
u32 ret; uint32_t ret;
u32 i; uint32_t i;
for (i = 0, ret = 0; i < size; ret = ret << 8, ret += data[i++]) for (i = 0, ret = 0; i < size; ret = ret << 8, ret += data[i++])
; ;
return ret; return ret;
} }
static u32 asn1_get_len(BUFFER *buffer) { static uint32_t asn1_get_len(ssh_buffer buffer) {
u32 len; uint32_t len;
unsigned char tmp[4]; unsigned char tmp[4];
if (buffer_get_data(buffer,tmp,1) == 0) { if (buffer_get_data(buffer,tmp,1) == 0) {
return 0; return 0;
} }
if (tmp[0] > 127) { if (tmp[0] > 127) {
len = tmp[0] & 127; len = tmp[0] & 127;
if (len > 4) { if (len > 4) {
return 0; /* Length doesn't fit in u32. Can this really happen? */ return 0; /* Length doesn't fit in u32. Can this really happen? */
skipping to change at line 125 skipping to change at line 135
return 0; return 0;
} }
len = char_to_u32(tmp, len); len = char_to_u32(tmp, len);
} else { } else {
len = char_to_u32(tmp, 1); len = char_to_u32(tmp, 1);
} }
return len; return len;
} }
static STRING *asn1_get_int(BUFFER *buffer) { static ssh_string asn1_get_int(ssh_buffer buffer) {
STRING *str; ssh_string str;
unsigned char type; unsigned char type;
u32 size; uint32_t size;
if (buffer_get_data(buffer, &type, 1) == 0 || type != ASN1_INTEGER) { if (buffer_get_data(buffer, &type, 1) == 0 || type != ASN1_INTEGER) {
return NULL; return NULL;
} }
size = asn1_get_len(buffer); size = asn1_get_len(buffer);
if (size == 0) { if (size == 0) {
return NULL; return NULL;
} }
str = string_new(size); str = string_new(size);
skipping to change at line 151 skipping to change at line 161
} }
if (buffer_get_data(buffer, str->string, size) == 0) { if (buffer_get_data(buffer, str->string, size) == 0) {
string_free(str); string_free(str);
return NULL; return NULL;
} }
return str; return str;
} }
static int asn1_check_sequence(BUFFER *buffer) { static int asn1_check_sequence(ssh_buffer buffer) {
unsigned char *j = NULL; unsigned char *j = NULL;
unsigned char tmp; unsigned char tmp;
int i; int i;
u32 size; uint32_t size;
u32 padding; uint32_t padding;
if (buffer_get_data(buffer, &tmp, 1) == 0 || tmp != ASN1_SEQUENCE) { if (buffer_get_data(buffer, &tmp, 1) == 0 || tmp != ASN1_SEQUENCE) {
return 0; return 0;
} }
size = asn1_get_len(buffer); size = asn1_get_len(buffer);
if ((padding = buffer_get_len(buffer) - buffer->pos - size) > 0) { if ((padding = buffer_get_len(buffer) - buffer->pos - size) > 0) {
for (i = buffer_get_len(buffer) - buffer->pos - size, for (i = buffer_get_len(buffer) - buffer->pos - size,
j = buffer_get(buffer) + size + buffer->pos; j = (unsigned char*)buffer_get(buffer) + size + buffer->pos;
i; i;
i--, j++) i--, j++)
{ {
if (*j != padding) { /* padding is allowed */ if (*j != padding) { /* padding is allowed */
return 0; /* but nothing else */ return 0; /* but nothing else */
} }
} }
} }
return 1; return 1;
skipping to change at line 233 skipping to change at line 243
key[j] = digest[i]; key[j] = digest[i];
} }
} }
} }
return 0; return 0;
} }
static int privatekey_decrypt(int algo, int mode, unsigned int key_len, static int privatekey_decrypt(int algo, int mode, unsigned int key_len,
unsigned char *iv, unsigned int iv_len, unsigned char *iv, unsigned int iv_len,
BUFFER *data, ssh_auth_callback cb, ssh_buffer data, ssh_auth_callback cb,
void *userdata, void *userdata,
const char *desc) const char *desc)
{ {
char passphrase[MAX_PASSPHRASE_SIZE] = {0}; char passphrase[MAX_PASSPHRASE_SIZE] = {0};
unsigned char key[MAX_KEY_SIZE] = {0}; unsigned char key[MAX_KEY_SIZE] = {0};
unsigned char *tmp = NULL; unsigned char *tmp = NULL;
gcry_cipher_hd_t cipher; gcry_cipher_hd_t cipher;
int rc = -1; int rc = -1;
if (!algo) { if (!algo) {
skipping to change at line 334 skipping to change at line 344
} }
*iv = malloc(*iv_len); *iv = malloc(*iv_len);
if (*iv == NULL) { if (*iv == NULL) {
return -1; return -1;
} }
return load_iv(header + iv_pos, *iv, *iv_len); return load_iv(header + iv_pos, *iv, *iv_len);
} }
static BUFFER *privatekey_file_to_buffer(FILE *fp, int type, static ssh_buffer privatekey_file_to_buffer(FILE *fp, int type,
ssh_auth_callback cb, void *userdata, const char *desc) { ssh_auth_callback cb, void *userdata, const char *desc) {
BUFFER *buffer = NULL; ssh_buffer buffer = NULL;
BUFFER *out = NULL; ssh_buffer out = NULL;
char buf[MAXLINESIZE] = {0}; char buf[MAXLINESIZE] = {0};
unsigned char *iv = NULL; unsigned char *iv = NULL;
const char *header_begin; const char *header_begin;
const char *header_end; const char *header_end;
unsigned int header_begin_size; unsigned int header_begin_size;
unsigned int header_end_size; unsigned int header_end_size;
unsigned int key_len = 0; unsigned int key_len = 0;
unsigned int iv_len = 0; unsigned int iv_len = 0;
int algo = 0; int algo = 0;
int mode = 0; int mode = 0;
skipping to change at line 448 skipping to change at line 458
return NULL; return NULL;
} }
} }
SAFE_FREE(iv); SAFE_FREE(iv);
return out; return out;
} }
static int read_rsa_privatekey(FILE *fp, gcry_sexp_t *r, static int read_rsa_privatekey(FILE *fp, gcry_sexp_t *r,
ssh_auth_callback cb, void *userdata, const char *desc) { ssh_auth_callback cb, void *userdata, const char *desc) {
STRING *n = NULL; ssh_string n = NULL;
STRING *e = NULL; ssh_string e = NULL;
STRING *d = NULL; ssh_string d = NULL;
STRING *p = NULL; ssh_string p = NULL;
STRING *q = NULL; ssh_string q = NULL;
STRING *unused1 = NULL; ssh_string unused1 = NULL;
STRING *unused2 = NULL; ssh_string unused2 = NULL;
STRING *u = NULL; ssh_string u = NULL;
STRING *v = NULL; ssh_string v = NULL;
BUFFER *buffer = NULL; ssh_buffer buffer = NULL;
int rc = 1; int rc = 1;
buffer = privatekey_file_to_buffer(fp, TYPE_RSA, cb, userdata, desc); buffer = privatekey_file_to_buffer(fp, TYPE_RSA, cb, userdata, desc);
if (buffer == NULL) { if (buffer == NULL) {
return 0; return 0;
} }
if (!asn1_check_sequence(buffer)) { if (!asn1_check_sequence(buffer)) {
buffer_free(buffer); buffer_free(buffer);
return 0; return 0;
skipping to change at line 520 skipping to change at line 530
string_free(unused1); string_free(unused1);
string_free(unused2); string_free(unused2);
string_free(u); string_free(u);
string_free(v); string_free(v);
return rc; return rc;
} }
static int read_dsa_privatekey(FILE *fp, gcry_sexp_t *r, ssh_auth_callback cb, static int read_dsa_privatekey(FILE *fp, gcry_sexp_t *r, ssh_auth_callback cb,
void *userdata, const char *desc) { void *userdata, const char *desc) {
BUFFER *buffer = NULL; ssh_buffer buffer = NULL;
STRING *p = NULL; ssh_string p = NULL;
STRING *q = NULL; ssh_string q = NULL;
STRING *g = NULL; ssh_string g = NULL;
STRING *y = NULL; ssh_string y = NULL;
STRING *x = NULL; ssh_string x = NULL;
STRING *v = NULL; ssh_string v = NULL;
int rc = 1; int rc = 1;
buffer = privatekey_file_to_buffer(fp, TYPE_DSS, cb, userdata, desc); buffer = privatekey_file_to_buffer(fp, TYPE_DSS, cb, userdata, desc);
if (buffer == NULL) { if (buffer == NULL) {
return 0; return 0;
} }
if (!asn1_check_sequence(buffer)) { if (!asn1_check_sequence(buffer)) {
buffer_free(buffer); buffer_free(buffer);
return 0; return 0;
skipping to change at line 581 skipping to change at line 591
string_free(y); string_free(y);
string_free(x); string_free(x);
string_free(v); string_free(v);
return rc; return rc;
} }
#endif /* HAVE_LIBGCRYPT */ #endif /* HAVE_LIBGCRYPT */
#ifdef HAVE_LIBCRYPTO #ifdef HAVE_LIBCRYPTO
static int pem_get_password(char *buf, int size, int rwflag, void *userdata ) { static int pem_get_password(char *buf, int size, int rwflag, void *userdata ) {
SSH_SESSION *session = userdata; ssh_session session = userdata;
/* unused flag */ /* unused flag */
(void) rwflag; (void) rwflag;
ZERO_STRUCTP(buf); ZERO_STRUCTP(buf);
ssh_log(session, SSH_LOG_RARE,
"Trying to call external authentication function");
if (session && session->options->auth_function) { if (session && session->callbacks->auth_function) {
if ((*session->options->auth_function)("Passphrase for private key:", b if (session->callbacks->auth_function("Passphrase for private key:", bu
uf, size, 0, 0, f, size, 0, 0,
session->options->auth_userdata ? session->options->auth_userdata : session->callbacks->userdata) < 0) {
NULL) < 0) {
return 0; return 0;
} }
return strlen(buf); return strlen(buf);
} }
return 0; return 0;
} }
#endif /* HAVE_LIBCRYPTO */ #endif /* HAVE_LIBCRYPTO */
skipping to change at line 614 skipping to change at line 626
/* TODO : implement it to read both DSA and RSA at once */ /* TODO : implement it to read both DSA and RSA at once */
/** \brief Reads a SSH private key from a file /** \brief Reads a SSH private key from a file
* \param session SSH Session * \param session SSH Session
* \param filename Filename containing the private key * \param filename Filename containing the private key
* \param type Type of the private key. One of TYPE_DSS or TYPE_RSA. * \param type Type of the private key. One of TYPE_DSS or TYPE_RSA.
* \param passphrase Passphrase to decrypt the private key. Set to null if none is needed or it is unknown. * \param passphrase Passphrase to decrypt the private key. Set to null if none is needed or it is unknown.
* \returns a PRIVATE_KEY object containing the private key, or NULL if it failed. * \returns a PRIVATE_KEY object containing the private key, or NULL if it failed.
* \see privatekey_free() * \see privatekey_free()
* \see publickey_from_privatekey() * \see publickey_from_privatekey()
*/ */
PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session, const char *filenam e, ssh_private_key privatekey_from_file(ssh_session session, const char *filen ame,
int type, const char *passphrase) { int type, const char *passphrase) {
ssh_auth_callback auth_cb = NULL; ssh_auth_callback auth_cb = NULL;
PRIVATE_KEY *privkey = NULL; ssh_private_key privkey = NULL;
void *auth_ud = NULL; void *auth_ud = NULL;
FILE *file = NULL; FILE *file = NULL;
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa = NULL; gcry_sexp_t dsa = NULL;
gcry_sexp_t rsa = NULL; gcry_sexp_t rsa = NULL;
int valid; int valid;
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA *dsa = NULL; DSA *dsa = NULL;
RSA *rsa = NULL; RSA *rsa = NULL;
#endif #endif
ssh_log(session, SSH_LOG_RARE, "Trying to open %s", filename);
file = fopen(filename,"r"); file = fopen(filename,"r");
if (file == NULL) { if (file == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
"Error opening %s: %s", filename, strerror(errno)); "Error opening %s: %s", filename, strerror(errno));
return NULL; return NULL;
} }
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%
s",
filename, passphrase ? "true" : "false",
session->callbacks && session->callbacks->auth_function ? "true" : "f
alse");
switch (type) { switch (type) {
case TYPE_DSS: case TYPE_DSS:
if (passphrase == NULL) { if (passphrase == NULL) {
if (session->options->auth_function) { if (session->callbacks->auth_function) {
auth_cb = session->options->auth_function; auth_cb = session->callbacks->auth_function;
if (session->options->auth_userdata) { auth_ud = session->callbacks->userdata;
auth_ud = session->options->auth_userdata;
}
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
valid = read_dsa_privatekey(file, &dsa, auth_cb, auth_ud, valid = read_dsa_privatekey(file, &dsa, auth_cb, auth_ud,
"Passphrase for private key:"); "Passphrase for private key:");
} else { /* authcb */ } else { /* authcb */
valid = read_dsa_privatekey(file, &dsa, NULL, NULL, NULL); valid = read_dsa_privatekey(file, &dsa, NULL, NULL, NULL);
} /* authcb */ } /* authcb */
} else { /* passphrase */ } else { /* passphrase */
valid = read_dsa_privatekey(file, &dsa, NULL, valid = read_dsa_privatekey(file, &dsa, NULL,
(void *) passphrase, NULL); (void *) passphrase, NULL);
} }
skipping to change at line 679 skipping to change at line 694
if (dsa == NULL) { if (dsa == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Parsing private key %s: %s", "Parsing private key %s: %s",
filename, ERR_error_string(ERR_get_error(), NULL)); filename, ERR_error_string(ERR_get_error(), NULL));
#endif #endif
return NULL; return NULL;
} }
break; break;
case TYPE_RSA: case TYPE_RSA:
if (passphrase == NULL) { if (passphrase == NULL) {
if (session->options->auth_function) { if (session->callbacks && session->callbacks->auth_function) {
auth_cb = session->options->auth_function; auth_cb = session->callbacks->auth_function;
if (session->options->auth_userdata) { auth_ud = session->callbacks->userdata;
auth_ud = session->options->auth_userdata;
}
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
valid = read_rsa_privatekey(file, &rsa, auth_cb, auth_ud, valid = read_rsa_privatekey(file, &rsa, auth_cb, auth_ud,
"Passphrase for private key:"); "Passphrase for private key:");
} else { /* authcb */ } else { /* authcb */
valid = read_rsa_privatekey(file, &rsa, NULL, NULL, NULL); valid = read_rsa_privatekey(file, &rsa, NULL, NULL, NULL);
} /* authcb */ } /* authcb */
} else { /* passphrase */ } else { /* passphrase */
valid = read_rsa_privatekey(file, &rsa, NULL, valid = read_rsa_privatekey(file, &rsa, NULL,
(void *) passphrase, NULL); (void *) passphrase, NULL);
} }
skipping to change at line 724 skipping to change at line 737
filename, ERR_error_string(ERR_get_error(),NULL)); filename, ERR_error_string(ERR_get_error(),NULL));
#endif #endif
return NULL; return NULL;
} }
break; break;
default: default:
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type ); ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type );
return NULL; return NULL;
} /* switch */ } /* switch */
privkey = malloc(sizeof(PRIVATE_KEY)); privkey = malloc(sizeof(struct ssh_private_key_struct));
if (privkey == NULL) { if (privkey == NULL) {
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_release(dsa); gcry_sexp_release(dsa);
gcry_sexp_release(rsa); gcry_sexp_release(rsa);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA_free(dsa); DSA_free(dsa);
RSA_free(rsa); RSA_free(rsa);
#endif #endif
return NULL; return NULL;
} }
privkey->type = type; privkey->type = type;
privkey->dsa_priv = dsa; privkey->dsa_priv = dsa;
privkey->rsa_priv = rsa; privkey->rsa_priv = rsa;
return privkey; return privkey;
} }
/* same that privatekey_from_file() but without any passphrase things. */ /* same that privatekey_from_file() but without any passphrase things. */
PRIVATE_KEY *_privatekey_from_file(void *session, const char *filename, ssh_private_key _privatekey_from_file(void *session, const char *filename,
int type) { int type) {
PRIVATE_KEY *privkey = NULL; ssh_private_key privkey = NULL;
FILE *file = NULL; FILE *file = NULL;
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa = NULL; gcry_sexp_t dsa = NULL;
gcry_sexp_t rsa = NULL; gcry_sexp_t rsa = NULL;
int valid; int valid;
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA *dsa = NULL; DSA *dsa = NULL;
RSA *rsa = NULL; RSA *rsa = NULL;
#endif #endif
skipping to change at line 812 skipping to change at line 825
filename, ERR_error_string(ERR_get_error(), NULL)); filename, ERR_error_string(ERR_get_error(), NULL));
#endif #endif
return NULL; return NULL;
} }
break; break;
default: default:
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", ty pe); ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", ty pe);
return NULL; return NULL;
} }
privkey = malloc(sizeof(PRIVATE_KEY)); privkey = malloc(sizeof(struct ssh_private_key_struct));
if (privkey == NULL) { if (privkey == NULL) {
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_release(dsa); gcry_sexp_release(dsa);
gcry_sexp_release(rsa); gcry_sexp_release(rsa);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA_free(dsa); DSA_free(dsa);
RSA_free(rsa); RSA_free(rsa);
#endif #endif
return NULL; return NULL;
} }
skipping to change at line 834 skipping to change at line 847
privkey->type = type; privkey->type = type;
privkey->dsa_priv = dsa; privkey->dsa_priv = dsa;
privkey->rsa_priv = rsa; privkey->rsa_priv = rsa;
return privkey; return privkey;
} }
/** \brief deallocate a private key /** \brief deallocate a private key
* \param prv a PRIVATE_KEY object * \param prv a PRIVATE_KEY object
*/ */
void privatekey_free(PRIVATE_KEY *prv) { void privatekey_free(ssh_private_key prv) {
if (prv == NULL) { if (prv == NULL) {
return; return;
} }
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_release(prv->dsa_priv); gcry_sexp_release(prv->dsa_priv);
gcry_sexp_release(prv->rsa_priv); gcry_sexp_release(prv->rsa_priv);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA_free(prv->dsa_priv); DSA_free(prv->dsa_priv);
RSA_free(prv->rsa_priv); RSA_free(prv->rsa_priv);
#endif #endif
memset(prv, 0, sizeof(PRIVATE_KEY)); memset(prv, 0, sizeof(struct ssh_private_key_struct));
SAFE_FREE(prv); SAFE_FREE(prv);
} }
/** \brief Retrieve a public key from a file /** \brief Retrieve a public key from a file
* \param session the SSH session * \param session the SSH session
* \param filename Filename of the key * \param filename Filename of the key
* \param _type Pointer to a integer. If it is not null, it contains the ty pe of the key after execution. * \param type Pointer to a integer. If it is not null, it contains the typ e of the key after execution.
* \return a SSH String containing the public key, or NULL if it failed. * \return a SSH String containing the public key, or NULL if it failed.
* \see string_free() * \see string_free()
* \see publickey_from_privatekey() * \see publickey_from_privatekey()
*/ */
STRING *publickey_from_file(SSH_SESSION *session, const char *filename, ssh_string publickey_from_file(ssh_session session, const char *filename,
int *type) { int *type) {
BUFFER *buffer = NULL; ssh_buffer buffer = NULL;
char buf[4096] = {0}; char buf[4096] = {0};
STRING *str = NULL; ssh_string str = NULL;
char *ptr = NULL; char *ptr = NULL;
int key_type; int key_type;
int fd = -1; int fd = -1;
int r; int r;
fd = open(filename, O_RDONLY); fd = open(filename, O_RDONLY);
if (fd < 0) { if (fd < 0) {
ssh_set_error(session, SSH_REQUEST_DENIED, "Public key file doesn't exi st"); ssh_set_error(session, SSH_REQUEST_DENIED, "Public key file doesn't exi st");
return NULL; return NULL;
} }
skipping to change at line 927 skipping to change at line 940
string_fill(str, buffer_get(buffer), buffer_get_len(buffer)); string_fill(str, buffer_get(buffer), buffer_get_len(buffer));
buffer_free(buffer); buffer_free(buffer);
if (type) { if (type) {
*type = key_type; *type = key_type;
} }
return str; return str;
} }
STRING *try_publickey_from_file(SSH_SESSION *session, struct keys_struct ke ytab, ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_str uct keytab,
char **privkeyfile, int *type) { char **privkeyfile, int *type) {
static char *home = NULL; char *public;
char *private;
char public[256] = {0};
char private[256] = {0};
const char *priv; const char *priv;
const char *pub; const char *pub;
char *new; char *new;
STRING *pubkey; ssh_string pubkey=NULL;
if (home == NULL) {
home = ssh_get_user_home_dir();
if (home == NULL) {
ssh_set_error(session,SSH_FATAL,"User home dir impossible to guess");
return NULL;
}
}
pub = keytab.publickey; pub = keytab.publickey;
if (pub == NULL) { if (pub == NULL) {
return NULL; return NULL;
} }
priv = keytab.privatekey; priv = keytab.privatekey;
if (priv == NULL) { if (priv == NULL) {
return NULL; return NULL;
} }
if (session->sshdir == NULL) {
if (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL) < 0) {
return NULL;
}
}
/* are them readable ? */ /* are them readable ? */
snprintf(public, sizeof(public), pub, home); public=dir_expand_dup(session,pub,1);
ssh_log(session, SSH_LOG_PACKET, "Trying to open public key %s", public); private=dir_expand_dup(session,priv,1);
//snprintf(public, sizeof(public), "%s/%s", session->sshdir, pub);
//snprintf(private, sizeof(private), "%s/%s", session->sshdir, priv);
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", public);
if (!ssh_file_readaccess_ok(public)) { if (!ssh_file_readaccess_ok(public)) {
ssh_log(session, SSH_LOG_PACKET, "Failed"); ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", public)
return NULL; ;
goto error;
} }
snprintf(private, sizeof(private), priv, home); ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", private)
ssh_log(session, SSH_LOG_PACKET, "Trying to open private key %s", private ;
);
if (!ssh_file_readaccess_ok(private)) { if (!ssh_file_readaccess_ok(private)) {
ssh_log(session, SSH_LOG_PACKET, "Failed"); ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", privat
return NULL; e);
goto error;
} }
ssh_log(session, SSH_LOG_PACKET, "Success reading public and private key" ); ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key" );
/* /*
* We are sure both the private and public key file is readable. We retur n * We are sure both the private and public key file is readable. We retur n
* the public as a string, and the private filename as an argument * the public as a string, and the private filename as an argument
*/ */
pubkey = publickey_from_file(session, public, type); pubkey = publickey_from_file(session, public, type);
if (pubkey == NULL) { if (pubkey == NULL) {
ssh_log(session, SSH_LOG_PACKET, ssh_log(session, SSH_LOG_PACKET,
"Wasn't able to open public key file %s: %s", "Wasn't able to open public key file %s: %s",
public, public,
ssh_get_error(session)); ssh_get_error(session));
return NULL; goto error;
} }
new = realloc(*privkeyfile, strlen(private) + 1); new = realloc(*privkeyfile, strlen(private) + 1);
if (new == NULL) { if (new == NULL) {
string_free(pubkey); string_free(pubkey);
return NULL; goto error;
} }
strcpy(new, private); strcpy(new, private);
*privkeyfile = new; *privkeyfile = new;
error:
SAFE_FREE(public);
SAFE_FREE(private);
return pubkey; return pubkey;
} }
static int alldigits(const char *s) { static int alldigits(const char *s) {
while (*s) { while (*s) {
if (isdigit(*s)) { if (isdigit(*s)) {
s++; s++;
} else { } else {
return 0; return 0;
} }
skipping to change at line 1022 skipping to change at line 1036
/** \addtogroup ssh_session /** \addtogroup ssh_session
* @{ */ * @{ */
/** /**
* \brief Lowercase a string. * \brief Lowercase a string.
* \param str String to lowercase. * \param str String to lowercase.
* \return The malloced lowered string or NULL on error. * \return The malloced lowered string or NULL on error.
* \internal * \internal
*/ */
static char *lowercase(const char* str) { static char *lowercase(const char* str) {
char *p = 0; char *new, *p;
char *new = strdup(str);
if (str == NULL) {
return NULL;
}
if((str == NULL) || (new == NULL)) { new = strdup(str);
if (new == NULL) {
return NULL; return NULL;
} }
for (p = new; *p; p++) { for (p = new; *p; p++) {
*p = tolower(*p); *p = tolower(*p);
} }
return new; return new;
} }
skipping to change at line 1060 skipping to change at line 1078
/** \brief returns one line of known host file /** \brief returns one line of known host file
* will return a token array containing (host|ip) keytype key * will return a token array containing (host|ip) keytype key
* \param file pointer to the known host file. Could be pointing to NULL at start * \param file pointer to the known host file. Could be pointing to NULL at start
* \param filename file name of the known host file * \param filename file name of the known host file
* \param found_type pointer to a string to be set with the found key type * \param found_type pointer to a string to be set with the found key type
* \internal * \internal
* \returns NULL if no match was found or the file was not found * \returns NULL if no match was found or the file was not found
* \returns found_type type of key (ie "dsa","ssh-rsa1"). Don't free that v alue. * \returns found_type type of key (ie "dsa","ssh-rsa1"). Don't free that v alue.
*/ */
static char **ssh_get_knownhost_line(SSH_SESSION *session, FILE **file, static char **ssh_get_knownhost_line(ssh_session session, FILE **file,
const char *filename, const char **found_type) { const char *filename, const char **found_type) {
char buffer[4096] = {0}; char buffer[4096] = {0};
char *ptr; char *ptr;
char **tokens; char **tokens;
enter_function(); enter_function();
if(*file == NULL){ if(*file == NULL){
*file = fopen(filename,"r"); *file = fopen(filename,"r");
if (*file == NULL) { if (*file == NULL) {
skipping to change at line 1142 skipping to change at line 1160
} }
/** /**
* \brief Check the public key in the known host line matches the * \brief Check the public key in the known host line matches the
* public key of the currently connected server. * public key of the currently connected server.
* \param tokens list of tokens in the known_hosts line. * \param tokens list of tokens in the known_hosts line.
* \return 1 if the key matches * \return 1 if the key matches
* \return 0 if the key doesn't match * \return 0 if the key doesn't match
* \return -1 on error * \return -1 on error
*/ */
static int check_public_key(SSH_SESSION *session, char **tokens) { static int check_public_key(ssh_session session, char **tokens) {
STRING *pubkey = session->current_crypto->server_pubkey; ssh_string pubkey = session->current_crypto->server_pubkey;
BUFFER *pubkey_buffer; ssh_buffer pubkey_buffer;
char *pubkey_64; char *pubkey_64;
/* ok we found some public key in known hosts file. now un-base64it */ /* ok we found some public key in known hosts file. now un-base64it */
if (alldigits(tokens[1])) { if (alldigits(tokens[1])) {
/* openssh rsa1 format */ /* openssh rsa1 format */
bignum tmpbn; bignum tmpbn;
STRING *tmpstring; ssh_string tmpstring;
unsigned int len; unsigned int len;
int i; int i;
pubkey_buffer = buffer_new(); pubkey_buffer = buffer_new();
if (pubkey_buffer == NULL) { if (pubkey_buffer == NULL) {
return -1; return -1;
} }
tmpstring = string_from_char("ssh-rsa1"); tmpstring = string_from_char("ssh-rsa1");
if (tmpstring == NULL) { if (tmpstring == NULL) {
skipping to change at line 1191 skipping to change at line 1209
because of the padding which it does --kv */ because of the padding which it does --kv */
/* tmpstring = make_bignum_string(tmpbn); */ /* tmpstring = make_bignum_string(tmpbn); */
/* do it manually instead */ /* do it manually instead */
len = bignum_num_bytes(tmpbn); len = bignum_num_bytes(tmpbn);
tmpstring = malloc(4 + len); tmpstring = malloc(4 + len);
if (tmpstring == NULL) { if (tmpstring == NULL) {
buffer_free(pubkey_buffer); buffer_free(pubkey_buffer);
bignum_free(tmpbn); bignum_free(tmpbn);
return -1; return -1;
} }
/* TODO: fix the hardcoding */
tmpstring->size = htonl(len); tmpstring->size = htonl(len);
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
bignum_bn2bin(tmpbn, len, tmpstring->string); bignum_bn2bin(tmpbn, len, tmpstring->string);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
bignum_bn2bin(tmpbn, tmpstring->string); bignum_bn2bin(tmpbn, tmpstring->string);
#endif #endif
bignum_free(tmpbn); bignum_free(tmpbn);
if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) { if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
buffer_free(pubkey_buffer); buffer_free(pubkey_buffer);
string_free(tmpstring); string_free(tmpstring);
skipping to change at line 1241 skipping to change at line 1260
return 1; return 1;
} }
/** /**
* \brief checks if a hostname matches a openssh-style hashed known host * \brief checks if a hostname matches a openssh-style hashed known host
* \param host host to check * \param host host to check
* \param hashed hashed value * \param hashed hashed value
* \returns 1 if it matches * \returns 1 if it matches
* \returns 0 otherwise * \returns 0 otherwise
*/ */
static int match_hashed_host(SSH_SESSION *session, const char *host, static int match_hashed_host(ssh_session session, const char *host,
const char *sourcehash) { const char *sourcehash) {
/* Openssh hash structure : /* Openssh hash structure :
* |1|base64 encoded salt|base64 encoded hash * |1|base64 encoded salt|base64 encoded hash
* hash is produced that way : * hash is produced that way :
* hash := HMAC_SHA1(key=salt,data=host) * hash := HMAC_SHA1(key=salt,data=host)
*/ */
unsigned char buffer[256] = {0}; unsigned char buffer[256] = {0};
BUFFER *salt; ssh_buffer salt;
BUFFER *hash; ssh_buffer hash;
HMACCTX mac; HMACCTX mac;
char *source; char *source;
char *b64hash; char *b64hash;
int match; int match;
unsigned int size; unsigned int size;
enter_function(); enter_function();
if (strncmp(sourcehash, "|1|", 3) != 0) { if (strncmp(sourcehash, "|1|", 3) != 0) {
return 0; return 0;
skipping to change at line 1353 skipping to change at line 1372
* SSH_SERVER_FOUND_OTHER: The server gave use a key of a type wh ile * SSH_SERVER_FOUND_OTHER: The server gave use a key of a type wh ile
* we had an other type recorded. It is a * we had an other type recorded. It is a
* possible attack \n * possible attack \n
* SSH_SERVER_NOT_KNOWN: The server is unknown. User should con firm * SSH_SERVER_NOT_KNOWN: The server is unknown. User should con firm
* the MD5 is correct\n * the MD5 is correct\n
* SSH_SERVER_FILE_NOT_FOUND:The known host file does not exist. Th e * SSH_SERVER_FILE_NOT_FOUND:The known host file does not exist. Th e
* host is thus unknown. File will be cre ated * host is thus unknown. File will be cre ated
* if host key is accepted\n * if host key is accepted\n
* SSH_SERVER_ERROR: Some error happened * SSH_SERVER_ERROR: Some error happened
* *
* \see ssh_options_set_wanted_algo() * \see ssh_options_set()
* \see ssh_get_pubkey_hash() * \see ssh_get_pubkey_hash()
* *
* \bug There is no current way to remove or modify an entry into the known * \bug There is no current way to remove or modify an entry into the known
* host table. * host table.
*/ */
int ssh_is_server_known(SSH_SESSION *session) { int ssh_is_server_known(ssh_session session) {
FILE *file = NULL; FILE *file = NULL;
char **tokens; char **tokens;
char *host; char *host;
const char *type; const char *type;
int match; int match;
int ret = SSH_SERVER_NOT_KNOWN; int ret = SSH_SERVER_NOT_KNOWN;
enter_function(); enter_function();
if (ssh_options_default_known_hosts_file(session->options) < 0) { if (session->knownhosts == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED, if (ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, NULL) < 0) {
"Can't find a known_hosts file"); ssh_set_error(session, SSH_REQUEST_DENIED,
leave_function(); "Can't find a known_hosts file");
return SSH_SERVER_FILE_NOT_FOUND; leave_function();
return SSH_SERVER_FILE_NOT_FOUND;
}
} }
if (session->options->host == NULL) { if (session->host == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Can't verify host in known hosts if the hostname isn't known"); "Can't verify host in known hosts if the hostname isn't known");
leave_function(); leave_function();
return SSH_SERVER_ERROR; return SSH_SERVER_ERROR;
} }
host = lowercase(session->options->host); host = lowercase(session->host);
if (host == NULL) { if (host == NULL) {
ssh_set_error(session, SSH_FATAL, "Not enough space!"); ssh_set_error(session, SSH_FATAL, "Not enough space!");
leave_function(); leave_function();
return SSH_SERVER_ERROR; return SSH_SERVER_ERROR;
} }
do { do {
tokens = ssh_get_knownhost_line(session, &file, tokens = ssh_get_knownhost_line(session, &file,
session->options->known_hosts_file, &type); session->knownhosts, &type);
/* End of file, return the current state */ /* End of file, return the current state */
if (tokens == NULL) { if (tokens == NULL) {
break; break;
} }
match = match_hashed_host(session, host, tokens[0]); match = match_hashed_host(session, host, tokens[0]);
if (match == 0) { if (match == 0) {
match = match_hostname(host, tokens[0], strlen(tokens[0])); match = match_hostname(host, tokens[0], strlen(tokens[0]));
} }
skipping to change at line 1447 skipping to change at line 1468
/* Return the current state at end of file */ /* Return the current state at end of file */
leave_function(); leave_function();
return ret; return ret;
} }
/** You generaly use it when ssh_is_server_known() answered SSH_SERVER_NOT_ KNOWN /** You generaly use it when ssh_is_server_known() answered SSH_SERVER_NOT_ KNOWN
* \brief write the current server as known in the known hosts file. This w ill create the known hosts file if it does not exist. * \brief write the current server as known in the known hosts file. This w ill create the known hosts file if it does not exist.
* \param session ssh session * \param session ssh session
* \return 0 on success, -1 on error * \return 0 on success, -1 on error
*/ */
int ssh_write_knownhost(SSH_SESSION *session) { int ssh_write_knownhost(ssh_session session) {
STRING *pubkey = session->current_crypto->server_pubkey; ssh_string pubkey = session->current_crypto->server_pubkey;
unsigned char *pubkey_64; unsigned char *pubkey_64;
char buffer[4096] = {0}; char buffer[4096] = {0};
FILE *file; FILE *file;
char *dir; char *dir;
size_t len = 0; size_t len = 0;
if (ssh_options_default_known_hosts_file(session->options) < 0) { if (ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, NULL) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot find known_hosts file."); ssh_set_error(session, SSH_FATAL, "Cannot find known_hosts file.");
return -1; return -1;
} }
if (session->options->host == NULL) { if (session->host == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Cannot write host in known hosts if the hostname is unknown"); "Cannot write host in known hosts if the hostname is unknown");
return -1; return -1;
} }
/* Check if ~/.ssh exists and create it if not */ /* Check if ~/.ssh exists and create it if not */
dir = ssh_dirname(session->options->known_hosts_file); dir = ssh_dirname(session->knownhosts);
if (dir == NULL) { if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
return -1; return -1;
} }
if (! ssh_file_readaccess_ok(dir)) { if (! ssh_file_readaccess_ok(dir)) {
if (ssh_mkdir(dir, 0700) < 0) { if (ssh_mkdir(dir, 0700) < 0) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory.", dir); "Cannot create %s directory.", dir);
SAFE_FREE(dir); SAFE_FREE(dir);
return -1; return -1;
} }
} }
SAFE_FREE(dir); SAFE_FREE(dir);
file = fopen(session->options->known_hosts_file, "a"); file = fopen(session->knownhosts, "a");
if (file == NULL) { if (file == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s", "Couldn't open known_hosts file %s for appending: %s",
session->options->known_hosts_file, strerror(errno)); session->knownhosts, strerror(errno));
return -1; return -1;
} }
if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) { if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) {
/* openssh uses a different format for ssh-rsa1 keys. /* openssh uses a different format for ssh-rsa1 keys.
Be compatible --kv */ Be compatible --kv */
PUBLIC_KEY *key; ssh_public_key key;
char *e_string = NULL; char *e_string = NULL;
char *n_string = NULL; char *n_string = NULL;
bignum e = NULL; bignum e = NULL;
bignum n = NULL; bignum n = NULL;
int rsa_size; int rsa_size;
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_t sexp; gcry_sexp_t sexp;
#endif #endif
key = publickey_from_string(session, pubkey); key = publickey_from_string(session, pubkey);
skipping to change at line 1566 skipping to change at line 1587
OPENSSL_free(e_string); OPENSSL_free(e_string);
OPENSSL_free(n_string); OPENSSL_free(n_string);
#endif #endif
publickey_free(key); publickey_free(key);
fclose(file); fclose(file);
return -1; return -1;
} }
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"%s %d %s %s\n", "%s %d %s %s\n",
session->options->host, session->host,
rsa_size << 3, rsa_size << 3,
e_string, e_string,
n_string); n_string);
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
bignum_free(e); bignum_free(e);
bignum_free(n); bignum_free(n);
SAFE_FREE(e_string); SAFE_FREE(e_string);
SAFE_FREE(n_string); SAFE_FREE(n_string);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
skipping to change at line 1591 skipping to change at line 1612
publickey_free(key); publickey_free(key);
} else { } else {
pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey)); pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey));
if (pubkey_64 == NULL) { if (pubkey_64 == NULL) {
fclose(file); fclose(file);
return -1; return -1;
} }
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"%s %s %s\n", "%s %s %s\n",
session->options->host, session->host,
session->current_crypto->server_pubkey_type, session->current_crypto->server_pubkey_type,
pubkey_64); pubkey_64);
SAFE_FREE(pubkey_64); SAFE_FREE(pubkey_64);
} }
len = strlen(buffer); len = strlen(buffer);
if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) { if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) {
fclose(file); fclose(file);
return -1; return -1;
 End of changes. 69 change blocks. 
120 lines changed or deleted 144 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/