aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Garcia Ballester <giga@le-pec.org>2005-11-25 09:31:33 +0000
committerJean-Philippe Garcia Ballester <giga@le-pec.org>2005-11-25 09:31:33 +0000
commitac4fd091775805b6849774f3c4b7e59dc1ab6bde (patch)
tree0e2b654829aa923b68fecbe67e056a71a71e3f07
parentd923851664f20f7143981dde3562ae9d6ce0b72e (diff)
downloadlibssh-ac4fd091775805b6849774f3c4b7e59dc1ab6bde.tar.gz
libssh-ac4fd091775805b6849774f3c4b7e59dc1ab6bde.tar.xz
libssh-ac4fd091775805b6849774f3c4b7e59dc1ab6bde.zip
Added support for known_hosts format version 1
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@51 7dcaeef0-15fb-0310-b436-a5af3365683c
-rw-r--r--include/libssh/priv.h10
-rw-r--r--libssh/Makefile.in3
-rw-r--r--libssh/gcrypt_missing.c78
-rw-r--r--libssh/kex.c15
-rw-r--r--libssh/keyfiles.c118
5 files changed, 207 insertions, 17 deletions
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index e587e1e..c6cc663 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -73,6 +73,8 @@ typedef gcry_mpi_t bignum;
#define bignum_free(num) gcry_mpi_release(num)
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
+#define bignum_bn2dec(num) my_gcry_bn2dec(num)
+#define bignum_dec2bn(num, data) my_gcry_dec2bn(data, num)
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
@@ -108,6 +110,8 @@ typedef BN_CTX* bignum_CTX;
#define bignum_free(num) BN_clear_free(num)
#define bignum_set_word(bn,n) BN_set_word(bn,n)
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
+#define bignum_bn2dec(num) BN_bn2dec(num)
+#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
#define bignum_bn2hex(num) BN_bn2hex(num)
#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
#define bignum_ctx_new() BN_CTX_new()
@@ -532,6 +536,12 @@ int channel_write1(CHANNEL *channel, void *data, int len);
int ssh_handle_packets(SSH_SESSION *session);
+#ifdef HAVE_LIBGCRYPT
+/* gcrypt_missing.c */
+int my_gcry_dec2bn(bignum *bn, const char *data);
+char *my_gcry_bn2dec(bignum bn);
+#endif /* !HAVE_LIBGCRYPT */
+
#ifdef __cplusplus
} ;
#endif
diff --git a/libssh/Makefile.in b/libssh/Makefile.in
index 963fa21..5b28caa 100644
--- a/libssh/Makefile.in
+++ b/libssh/Makefile.in
@@ -2,7 +2,8 @@
OBJECTS= client.o packet.o dh.o crypt.o connect.o error.o buffer.o \
string.o kex.o channels.o options.o keys.o auth.o base64.o \
keyfiles.o misc.o gzip.o wrapper.o sftp.o server.o crc32.o \
- session.o messages.o channels1.o auth1.o sftpserver.o
+ session.o messages.o channels1.o auth1.o sftpserver.o \
+ gcrypt_missing.o
SHELL = /bin/sh
VPATH = @srcdir@
diff --git a/libssh/gcrypt_missing.c b/libssh/gcrypt_missing.c
new file mode 100644
index 0000000..10f9da8
--- /dev/null
+++ b/libssh/gcrypt_missing.c
@@ -0,0 +1,78 @@
+/* gcrypt_missing.c */
+/* This part of the library handles private and public key files needed for publickey authentication,*/
+/* as well as servers public hashes verifications and certifications. Lot of code here handles openssh */
+/* implementations (key files aren't standardized yet). */
+
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+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
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+#include <stdlib.h>
+#include "libssh/priv.h"
+
+#ifdef HAVE_LIBGCRYPT
+int my_gcry_dec2bn(bignum *bn, const char *data)
+{
+ int count;
+
+ *bn = bignum_new();
+ gcry_mpi_set_ui(*bn, 0);
+ for (count = 0; data[count]; ++count)
+ {
+ gcry_mpi_mul_ui(*bn, *bn, 10);
+ gcry_mpi_add_ui(*bn, *bn, data[count] - '0');
+ }
+ return count;
+}
+
+char *my_gcry_bn2dec(bignum bn)
+{
+ int count, count2;
+ int size, rsize;
+ char *ret;
+ bignum bndup, num, ten;
+ char decnum;
+
+ size = gcry_mpi_get_nbits(bn) * 3;
+ rsize = size / 10 + size / 1000 + 2;
+ ret = malloc(rsize + 1);
+ if (!gcry_mpi_cmp_ui(bn, 0))
+ strcpy(ret, "0");
+ else
+ {
+ for (bndup = gcry_mpi_copy(bn), ten = bignum_new(), num = bignum_new(),
+ bignum_set_word(ten, 10), count = rsize; count; --count)
+ {
+ gcry_mpi_div(bndup, num, bndup, ten, 0);
+ for (decnum = 0, count2 = gcry_mpi_get_nbits(num); count2; decnum *= 2,
+ decnum += (gcry_mpi_test_bit(num, count2 - 1) ? 1 : 0), --count2)
+ ;
+ ret[count - 1] = decnum + '0';
+ }
+ for (count = 0; count < rsize && ret[count] == '0'; ++count)
+ ;
+ for (count2 = 0; count2 < rsize - count; ++count2)
+ ret[count2] = ret[count2 + count];
+ ret[count2] = 0;
+ bignum_free(num);
+ bignum_free(bndup);
+ bignum_free(ten);
+ }
+ return ret;
+}
+#endif
diff --git a/libssh/kex.c b/libssh/kex.c
index 5097b06..1d66f28 100644
--- a/libssh/kex.c
+++ b/libssh/kex.c
@@ -312,22 +312,29 @@ static void build_session_id1(SSH_SESSION *session, STRING *servern,
static int modulus_smaller(PUBLIC_KEY *k1, PUBLIC_KEY *k2){
bignum n1;
bignum n2;
+ int res;
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t sexp;
sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0);
- n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_STD);
+ n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
gcry_sexp_release(sexp);
sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0);
- n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_STD);
+ n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
gcry_sexp_release(sexp);
#elif defined HAVE_LIBCRYPTO
n1=k1->rsa_pub->n;
n2=k2->rsa_pub->n;
#endif
if(bignum_cmp(n1,n2)<0)
- return 1;
+ res=1;
else
- return 0;
+ res=0;
+#ifdef HAVE_LIBGCRYPT
+ bignum_free(n1);
+ bignum_free(n2);
+#endif
+ return res;
+
}
#define ABS(A) ( (A)<0 ? -(A):(A) )
diff --git a/libssh/keyfiles.c b/libssh/keyfiles.c
index e299295..ee0b3ec 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;