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/ |