aboutsummaryrefslogtreecommitdiff
path: root/libssh/keyfiles.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/keyfiles.c')
-rw-r--r--libssh/keyfiles.c118
1 files changed, 106 insertions, 12 deletions
diff --git a/libssh/keyfiles.c b/libssh/keyfiles.c
index e2992952..ee0b3ec4 100644
--- a/libssh/keyfiles.c
+++ b/libssh/keyfiles.c
@@ -29,7 +29,9 @@ MA 02111-1307, USA. */
#include <stdlib.h>
#include <fcntl.h>
#include "libssh/priv.h"
-#ifdef HAVE_LIBCRYPTO
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#elif defined HAVE_LIBCRYPTO
#include <openssl/pem.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
@@ -732,6 +734,15 @@ STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char
return pubkey;
}
+static int alldigits(char *s)
+{
+ while (*s) {
+ if (((*s) < '0') || ((*s) > '9')) return 0;
+ s++;
+ }
+ return 1;
+}
+
#define FOUND_OTHER ( (void *)-1)
#define FILE_NOT_FOUND ((void *)-2)
/* will return a token array containing [host,]ip keytype key */
@@ -741,6 +752,7 @@ static char **ssh_parse_knownhost(char *filename, char *hostname, char *type){
FILE *file=fopen(filename,"r");
char buffer[4096];
char *ptr;
+ char *found_type;
char **tokens;
char **ret=NULL;
if(!file)
@@ -753,16 +765,29 @@ static char **ssh_parse_knownhost(char *filename, char *hostname, char *type){
continue; /* skip empty lines */
tokens=space_tokenize(buffer);
if(!tokens[0] || !tokens[1] || !tokens[2]){
- /* it should have exactly 3 tokens */
+ /* it should have at least 3 tokens */
free(tokens[0]);
free(tokens);
continue;
}
+ found_type = tokens[1];
if(tokens[3]){
- /* 3 tokens only, not four */
- free(tokens[0]);
- free(tokens);
- continue;
+ /* openssh rsa1 format has 4 tokens on the line. Recognize it
+ by the fact that everything is all digits */
+ if (tokens[4]) {
+ /* that's never valid */
+ free(tokens[0]);
+ free(tokens);
+ continue;
+ }
+ if (alldigits(tokens[1]) && alldigits(tokens[2]) && alldigits(tokens[3])) {
+ found_type = "ssh-rsa1";
+ } else {
+ /* 3 tokens only, not four */
+ free(tokens[0]);
+ free(tokens);
+ continue;
+ }
}
ptr=tokens[0];
while(*ptr==' ')
@@ -772,7 +797,7 @@ static char **ssh_parse_knownhost(char *filename, char *hostname, char *type){
if(strncasecmp(ptr,hostname,strlen(hostname))==0){
if(ptr[strlen(hostname)]==' ' || ptr[strlen(hostname)]=='\0'
|| ptr[strlen(hostname)]==','){
- if(strcasecmp(tokens[1],type)==0){
+ if(strcasecmp(found_type, type)==0){
fclose(file);
return tokens;
} else {
@@ -814,8 +839,39 @@ int ssh_is_server_known(SSH_SESSION *session){
/* Some time, we may verify the IP address did not change. I honestly think */
/* it's not an important matter as IP address are known not to be secure */
/* and the crypto stuff is enough to prove the server's identity */
- pubkey_64=tokens[2];
- pubkey_buffer=base64_to_bin(pubkey_64);
+ if (alldigits(tokens[1])) { /* openssh rsa1 format */
+ bignum tmpbn;
+ int i;
+ unsigned int len;
+ STRING *tmpstring;
+
+ pubkey_buffer = buffer_new();
+ tmpstring = string_from_char("ssh-rsa1");
+ buffer_add_ssh_string(pubkey_buffer, tmpstring);
+
+ for (i = 2; i < 4; i++) { /* e, then n */
+ tmpbn = NULL;
+ bignum_dec2bn(tokens[i], &tmpbn);
+ /* for some reason, make_bignum_string does not work
+ because of the padding which it does --kv */
+ /* tmpstring = make_bignum_string(tmpbn); */
+ /* do it manually instead */
+ len = bignum_num_bytes(tmpbn);
+ tmpstring = malloc(4 + len);
+ tmpstring->size = htonl(len);
+#ifdef HAVE_LIBGCRYPT
+ bignum_bn2bin(tmpbn, len, tmpstring->string);
+#elif defined HAVE_LIBCRYPTO
+ bignum_bn2bin(tmpbn, tmpstring->string);
+#endif
+ bignum_free(tmpbn);
+ buffer_add_ssh_string(pubkey_buffer, tmpstring);
+ free(tmpstring);
+ }
+ } else {
+ pubkey_64=tokens[2];
+ pubkey_buffer=base64_to_bin(pubkey_64);
+ }
/* at this point, we may free the tokens */
free(tokens[0]);
free(tokens);
@@ -853,9 +909,47 @@ int ssh_write_knownhost(SSH_SESSION *session){
session->options->known_hosts_file,strerror(errno));
return -1;
}
- pubkey_64=bin_to_base64(pubkey->string,string_len(pubkey));
- snprintf(buffer,sizeof(buffer),"%s %s %s\n",session->options->host,session->current_crypto->server_pubkey_type,pubkey_64);
- free(pubkey_64);
+ if (!strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1")) {
+ /* openssh uses a different format for ssh-rsa1 keys.
+ Be compatible --kv */
+ char *e_string, *n_string;
+ bignum e, n;
+ PUBLIC_KEY *key = publickey_from_string(pubkey);
+ int rsa_size;
+#ifdef HAVE_LIBGCRYPT
+ gcry_sexp_t sexp;
+ sexp=gcry_sexp_find_token(key->rsa_pub,"e",0);
+ e=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
+ gcry_sexp_release(sexp);
+ sexp=gcry_sexp_find_token(key->rsa_pub,"n",0);
+ n=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
+ gcry_sexp_release(sexp);
+ rsa_size=(gcry_pk_get_nbits(key->rsa_pub)+7)/8;
+#elif defined HAVE_LIBCRYPTO
+ e = key->rsa_pub->e;
+ n = key->rsa_pub->n;
+ rsa_size = RSA_size(key->rsa_pub);
+#endif
+ e_string = bignum_bn2dec(e);
+ n_string = bignum_bn2dec(n);
+ snprintf(buffer, sizeof(buffer), "%s %d %s %s\n",
+ session->options->host, rsa_size << 3,
+ e_string, n_string);
+#ifdef HAVE_LIBGCRYPT
+ free(e_string);
+ gcry_mpi_release(e);
+ free(n_string);
+ gcry_mpi_release(n);
+#elif defined HAVE_LIBCRYPTO
+ OPENSSL_free(e_string);
+ OPENSSL_free(n_string);
+#endif
+ free(key);
+ } else {
+ pubkey_64=bin_to_base64(pubkey->string,string_len(pubkey));
+ snprintf(buffer,sizeof(buffer),"%s %s %s\n",session->options->host,session->current_crypto->server_pubkey_type,pubkey_64);
+ free(pubkey_64);
+ }
fwrite(buffer,strlen(buffer),1,file);
fclose(file);
return 0;